Skip to content

Commit 55c2a7c

Browse files
authored
Merge pull request #60 from jmboehm/augmentdfbug
fix augmentdf bug, error without fe
2 parents 0cd6599 + 488c3b3 commit 55c2a7c

File tree

5 files changed

+35
-13
lines changed

5 files changed

+35
-13
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "GLFixedEffectModels"
22
uuid = "bafb0ae5-e5f5-5100-81b6-6a55d777c812"
33
authors = ["Johannes Boehm <[email protected]>"]
4-
version = "0.5.3"
4+
version = "0.5.4"
55

66
[deps]
77
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

src/GLFixedEffectModel.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct GLFixedEffectModel <: RegressionModel
1616

1717
esample::BitVector # Is the row of the original dataframe part of the estimation sample?
1818
augmentdf::DataFrame
19+
fekeys::Vector{Symbol}
1920
loglikelihood::Float64
2021
nullloglikelihood::Float64
2122

@@ -126,7 +127,7 @@ end
126127

127128
function FixedEffectModels.fe(x::GLFixedEffectModel)
128129
!has_fe(x) && throw("fe() is not defined for fixed effect models without fixed effects")
129-
x.augmentdf[!, 2:size(x.augmentdf, 2)]
130+
x.augmentdf[!, Symbol.( "fe_" .* String.(x.fekeys))]
130131
end
131132

132133

src/fit.jl

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function nlreg(@nospecialize(df),
5151
dof_add::Integer = 0,
5252
save::Vector{Symbol} = Symbol[],
5353
method::Symbol = :cpu,
54+
nthreads::Integer = method == :cpu ? Threads.nthreads() : 256,
5455
drop_singletons = true,
5556
double_precision::Bool = true,
5657
dev_tol::Real = 1.0e-8, # tolerance level for the first stopping condition of the maximization routine.
@@ -83,6 +84,11 @@ function nlreg(@nospecialize(df),
8384
subset = eval(evaluate_subset(df, subsetformula))
8485
end
8586

87+
if method == :cpu && nthreads > Threads.nthreads()
88+
@warn "Keyword argument nthreads = $(nthreads) is ignored (Julia was started with only $(Threads.nthreads()) threads)."
89+
nthreads = Threads.nthreads()
90+
end
91+
8692
##############################################################################
8793
##
8894
## Parse formula
@@ -157,6 +163,8 @@ function nlreg(@nospecialize(df),
157163
@info "$(dropped_n) observations detected as singletons. Dropping them ..."
158164
end
159165
end
166+
else
167+
error("No fixed effect specified. Use GLM.jl for the estimation of generalized linear models without fixed effects.")
160168
end
161169

162170
save_fe = (:fe save) & has_fes
@@ -263,7 +271,7 @@ function nlreg(@nospecialize(df),
263271
Xexo, basecoef = detect_linear_dependency_among_X!(Xexo, basecoef; coefnames=coef_names)
264272

265273
weights = Weights(Ones{Float64}(sum(esample)))
266-
feM = AbstractFixedEffectSolver{double_precision ? Float64 : Float32}(fes, weights, Val{method})
274+
feM = AbstractFixedEffectSolver{double_precision ? Float64 : Float32}(fes, weights, Val{method}, nthreads)
267275

268276
# make one copy after deleting NAs + dropping singletons + detecting separations (fe + relu)
269277
nobs = sum(esample)
@@ -283,24 +291,25 @@ function nlreg(@nospecialize(df),
283291
(length(start) == coeflength) || error("Invalid length of `start` argument.")
284292
beta = start
285293
else
286-
beta = 0.1 .* ones(Float64, coeflength)
294+
# beta = zeros(double_precision ? Float64 : Float32, coeflength)
295+
beta = 0.1 .* ones(double_precision ? Float64 : Float32, coeflength)
287296
end
288297

289298
#Xexo = oldX[esample,:]
290299
Xexo = GLFixedEffectModels.getcols(Xexo, basecoef) # get Xexo from oldX and basecoef and esample
291300

292301
eta = Xexo * beta
293302
mu = GLM.linkinv.(Ref(link),eta)
294-
wt = ones(Float64, nobs, 1)
303+
wt = ones(double_precision ? Float64 : Float32, nobs, 1)
295304
dev = sum(devresid.(Ref(distribution), y, mu))
296305
nulldev = sum(devresid.(Ref(distribution), mean(y), mu))
297306

298307
Xhat = Xexo
299-
crossx = Matrix{Float64}(undef, nobs, 0)
308+
crossx = Matrix{double_precision ? Float64 : Float32}(undef, nobs, 0)
300309
residuals = y[:] # just for initialization
301310

302311
# Stuff that we need in outside scope
303-
emp = Array{Float64,2}(undef,2,2)
312+
emp = Array{double_precision ? Float64 : Float32,2}(undef,2,2)
304313
score = hessian = emp
305314

306315
outer_iterations = 0
@@ -439,6 +448,11 @@ function nlreg(@nospecialize(df),
439448
display(Xdemean .* nudemean)
440449
display(Xhat .* nu)
441450
end
451+
452+
# if dev > nulldev
453+
# @warn "Final deviance exceeds null deviance. Possibly running into a local maximum. Try restarting with a different starting guess."
454+
# end
455+
442456
break
443457
else
444458
verbose && println("Iter $i : not converged. Δdev = $((devold - dev)/dev), ||Δβ|| = $(norm(beta_update))")
@@ -463,7 +477,7 @@ function nlreg(@nospecialize(df),
463477
augmentdf = DataFrame()
464478
if save_residuals
465479
if nobs < length(esample)
466-
augmentdf.residuals = Vector{Union{Float64, Missing}}(missing, length(esample))
480+
augmentdf.residuals = Vector{Union{double_precision ? Float64 : Float32, Missing}}(missing, length(esample))
467481
augmentdf[esample, :residuals] = residuals
468482
else
469483
augmentdf[!, :residuals] = residuals
@@ -473,12 +487,15 @@ function nlreg(@nospecialize(df),
473487
oldX = oldX[esample,:]
474488
oldX = getcols(oldX, basecoef)
475489
# update FixedEffectSolver
476-
weights = Weights(Ones{Float64}(sum(esample)))
490+
weights = Weights(Ones{double_precision ? Float64 : Float32}(sum(esample)))
477491
feM = AbstractFixedEffectSolver{double_precision ? Float64 : Float32}(fes, weights, Val{method})
478492
newfes, b, c = solve_coefficients!(eta - oldX * coef, feM; tol = center_tol, maxiter = maxiter_center)
493+
for fekey in fekeys
494+
augmentdf[!, fekey] = df[:, fekey]
495+
end
479496
for j in 1:length(fes)
480497
if nobs < length(esample)
481-
augmentdf[!, ids[j]] = Vector{Union{Float64, Missing}}(missing, length(esample))
498+
augmentdf[!, ids[j]] = Vector{Union{double_precision ? Float64 : Float32, Missing}}(missing, length(esample))
482499
augmentdf[esample, ids[j]] = newfes[j]
483500
else
484501
augmentdf[!, ids[j]] = newfes[j]
@@ -487,15 +504,15 @@ function nlreg(@nospecialize(df),
487504
end
488505
if :mu save
489506
if nobs < length(esample)
490-
augmentdf.mu = Vector{Union{Float64, Missing}}(missing, length(esample))
507+
augmentdf.mu = Vector{Union{double_precision ? Float64 : Float32, Missing}}(missing, length(esample))
491508
augmentdf[esample, :mu] = mu
492509
else
493510
augmentdf[!, :mu] = mu
494511
end
495512
end
496513
if :eta save
497514
if nobs < length(esample)
498-
augmentdf.eta = Vector{Union{Float64, Missing}}(missing, length(esample))
515+
augmentdf.eta = Vector{Union{double_precision ? Float64 : Float32, Missing}}(missing, length(esample))
499516
augmentdf[esample, :eta] = eta
500517
else
501518
augmentdf[!, :eta] = eta
@@ -589,6 +606,7 @@ function nlreg(@nospecialize(df),
589606
outer_converged,
590607
esample,
591608
augmentdf,
609+
fekeys,
592610
ll,
593611
null_ll,
594612
distribution,

src/utils/biascorr.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ function biascorr_probit(model::GLFixedEffectModel,df::DataFrame,fes::Dict,L::In
166166
model.converged,
167167
model.esample,
168168
model.augmentdf,
169+
model.fekeys,
169170
model.loglikelihood,
170171
model.nullloglikelihood,
171172
model.distribution,
@@ -213,6 +214,7 @@ function biascorr_logit(model::GLFixedEffectModel,df::DataFrame,fes::Dict,L::Int
213214
model.converged,
214215
model.esample,
215216
model.augmentdf,
217+
model.fekeys,
216218
model.loglikelihood,
217219
model.nullloglikelihood,
218220
model.distribution,
@@ -327,6 +329,7 @@ function biascorr_poisson(model::GLFixedEffectModel,df::DataFrame,fes::Dict,L::I
327329
model.converged,
328330
model.esample,
329331
model.augmentdf,
332+
model.fekeys,
330333
model.loglikelihood,
331334
model.nullloglikelihood,
332335
model.distribution,

test/nlreg.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ df.RandomCategorical = df.Random
3636
# PROBIT ------------------------------------------------------------------
3737
# One FE, Probit
3838
m = @formula binary ~ SepalWidth + fe(SpeciesDummy)
39-
x = nlreg(df, m, Binomial(), GLM.ProbitLink(), start = [0.2])
39+
x = nlreg(df, m, Binomial(), GLM.ProbitLink(), start = [0.2], save = [:fe])
4040
@test x.coef [4.7793003788996895] atol = 1e-4
4141

4242
# Two FE, Probit

0 commit comments

Comments
 (0)