@@ -16,6 +16,7 @@ using Printf: Printf
16
16
using ForwardDiff: ForwardDiff
17
17
using StatsAPI: StatsAPI
18
18
using Statistics: Statistics
19
+ using LinearAlgebra: LinearAlgebra
19
20
20
21
export maximum_a_posteriori, maximum_likelihood
21
22
# The MAP and MLE exports are only needed for the Optim.jl interface.
@@ -228,11 +229,61 @@ end
228
229
229
230
# Various StatsBase methods for ModeResult
230
231
231
- function StatsBase. coeftable (m:: ModeResult ; level:: Real = 0.95 )
232
+ """
233
+ StatsBase.coeftable(m::ModeResult; level::Real=0.95, numerrors_warnonly::Bool=true)
234
+
235
+
236
+ Return a table with coefficients and related statistics of the model. level determines the
237
+ level for confidence intervals (by default, 95%).
238
+
239
+ In case the `numerrors_warnonly` argument is true (the default) numerical errors encountered
240
+ during the computation of the standard errors will be caught and reported in an extra
241
+ "Error notes" column.
242
+ """
243
+ function StatsBase. coeftable (m:: ModeResult ; level:: Real = 0.95 , numerrors_warnonly:: Bool = true )
232
244
# Get columns for coeftable.
233
245
terms = string .(StatsBase. coefnames (m))
234
246
estimates = m. values. array[:, 1 ]
235
- stderrors = StatsBase. stderror (m)
247
+ # If numerrors_warnonly is true, and if either the information matrix is singular or has
248
+ # negative entries on its diagonal, then `notes` will be a list of strings for each
249
+ # value in `m.values`, explaining why the standard error is NaN.
250
+ notes = nothing
251
+ local stderrors
252
+ if numerrors_warnonly
253
+ infmat = StatsBase. informationmatrix (m)
254
+ local vcov
255
+ try
256
+ vcov = inv (infmat)
257
+ catch e
258
+ if isa (e, LinearAlgebra. SingularException)
259
+ stderrors = fill (NaN , length (m. values))
260
+ notes = fill (" Information matrix is singular" , length (m. values))
261
+ else
262
+ rethrow (e)
263
+ end
264
+ else
265
+ vars = LinearAlgebra. diag (vcov)
266
+ stderrors = eltype (vars)[]
267
+ if any (x -> x < 0 , vars)
268
+ notes = []
269
+ end
270
+ for var in vars
271
+ if var >= 0
272
+ push! (stderrors, sqrt (var))
273
+ if notes != = nothing
274
+ push! (notes, " " )
275
+ end
276
+ else
277
+ push! (stderrors, NaN )
278
+ if notes != = nothing
279
+ push! (notes, " Negative variance" )
280
+ end
281
+ end
282
+ end
283
+ end
284
+ else
285
+ stderrors = StatsBase. stderror (m)
286
+ end
236
287
zscore = estimates ./ stderrors
237
288
p = map (z -> StatsAPI. pvalue (Distributions. Normal (), z; tail= :both ), zscore)
238
289
@@ -244,7 +295,7 @@ function StatsBase.coeftable(m::ModeResult; level::Real=0.95)
244
295
level_ = 100 * level
245
296
level_percentage = isinteger (level_) ? Int (level_) : level_
246
297
247
- cols = [estimates, stderrors, zscore, p, ci_low, ci_high]
298
+ cols = Vector [estimates, stderrors, zscore, p, ci_low, ci_high]
248
299
colnms = [
249
300
" Coef." ,
250
301
" Std. Error" ,
@@ -253,6 +304,10 @@ function StatsBase.coeftable(m::ModeResult; level::Real=0.95)
253
304
" Lower $(level_percentage) %" ,
254
305
" Upper $(level_percentage) %" ,
255
306
]
307
+ if notes != = nothing
308
+ push! (cols, notes)
309
+ push! (colnms, " Error notes" )
310
+ end
256
311
return StatsBase. CoefTable (cols, colnms, terms)
257
312
end
258
313
0 commit comments