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