@@ -5,11 +5,10 @@ struct SingleFTestResult
55 pval:: Float64
66end
77
8- mutable struct FTestResult{N}
8+ struct FTestResult{N}
99 nobs:: Int
1010 ssr:: NTuple{N,Float64}
11- dof:: NTuple{N,Int}
12- r2:: NTuple{N,Float64}
11+ dof:: NTuple{N,Float64}
1312 fstat:: NTuple{N,Float64}
1413 pval:: NTuple{N,Float64}
1514end
@@ -79,10 +78,9 @@ For each sequential pair of linear models in `mod...`, perform an F-test to dete
7978the one model fits significantly better than the other. Models must have been fitted
8079on the same data, and be nested either in forward or backward direction.
8180
82- A table is returned containing consumed degrees of freedom (DOF),
83- absolute difference in DOF from the preceding model, sum of squared residuals (SSR),
84- absolute difference in SSR from the preceding model, R², absolute difference in R²
85- from the preceding model, and F-statistic and p-value for the comparison
81+ A table is returned containing residual degrees of freedom (dof),
82+ absolute difference in dof from the preceding model, sum of squared residuals (SSR),
83+ absolute difference in SSR from the preceding model, and F-statistic and p-value for the comparison
8684between the two models.
8785
8886!!! note
@@ -114,22 +112,22 @@ julia> bigmodel = lm(@formula(Result ~ 1 + Treatment + Other), dat);
114112
115113julia> ftest(nullmodel, model)
116114F-test: 2 models fitted on 12 observations
117- ────────────────────────────────────────────────────────────────
118- DOF ΔDOF SSR ΔSSR R² ΔR² F* p(>F)
119- ────────────────────────────────────────────────────────────────
120- [1] 2 3.2292 0.0000
121- [2] 3 1 0.1283 3.1008 0.9603 0.9603 241.6234 <1e-07
122- ────────────────────────────────────────────────────────────────
115+ ───────────────────────────────────────────
116+ SSR dof ΔSSR Δdof F* p(>F)
117+ ───────────────────────────────────────────
118+ 3.2292 11
119+ 0.1283 10 3.1008 1 241.6234 <1e-07
120+ ───────────────────────────────────────────
123121
124122julia> ftest(nullmodel, model, bigmodel)
125123F-test: 3 models fitted on 12 observations
126- ────────────────────────────────────────────────────────────────
127- DOF ΔDOF SSR ΔSSR R² ΔR² F* p(>F)
128- ────────────────────────────────────────────────────────────────
129- [1] 2 3.2292 0.0000
130- [2] 3 1 0.1283 3.1008 0.9603 0.9603 241.6234 <1e-07
131- [3] 5 2 0.1017 0. 0266 0.9685 0.0082 1.0456 0.3950
132- ────────────────────────────────────────────────────────────────
124+ ───────────────────────────────────────────
125+ SSR dof ΔSSR Δdof F* p(>F)
126+ ───────────────────────────────────────────
127+ 3.2292 11
128+ 0.1283 10 3.1008 1 241.6234 <1e-07
129+ 0.1017 8 0. 0266 2 1.0456 0.3950
130+ ───────────────────────────────────────────
133131```
134132"""
135133function ftest(mods::LinearModel...; atol::Real=0.0)
@@ -156,23 +154,22 @@ function ftest(mods::LinearModel...; atol::Real=0.0)
156154
157155 SSR = deviance.(mods)
158156
159- df = dof .(mods)
157+ df = dof_residual .(mods)
160158 Δdf = abs.(_diff(df))
161- dfr = Int.(dof_residual.(mods))
162159 MSR1 = _diffn(SSR) ./ Δdf
163- MSR2 = (SSR ./ dfr )
160+ MSR2 = (SSR ./ df )
164161 if forward
165162 MSR2 = MSR2[2:end]
166- dfr_big = dfr [2:end]
163+ dfr_big = df [2:end]
167164 else
168165 MSR2 = MSR2[1:(end - 1)]
169- dfr_big = dfr [1:(end - 1)]
166+ dfr_big = df [1:(end - 1)]
170167 end
171168
172169 fstat = abs.((NaN, (MSR1 ./ MSR2)...))
173170 pval = (NaN, ccdf.(FDist.(Δdf, dfr_big), fstat[2:end])...)
174171
175- return FTestResult(Int(nobs(mods[1])), SSR, df, r2.(mods ), fstat, pval)
172+ return FTestResult(Int(nobs(mods[1])), SSR, float.(df ), fstat, pval)
176173end
177174
178175function show(io::IO, ftr::SingleFTestResult)
@@ -182,37 +179,34 @@ function show(io::IO, ftr::SingleFTestResult)
182179 return print(io, "p-value: ", PValue(ftr.pval))
183180end
184181
185- function show(io::IO, ftr::FTestResult{N}) where {N}
182+ function show(io::IO, ::MIME"text/plain", ftr::FTestResult{N}) where {N}
186183 Δdof = abs.(_diff(ftr.dof))
187184 Δssr = abs.(_diff(ftr.ssr))
188- ΔR² = abs.(_diff(ftr.r2))
189185
190- nc = 9
186+ nc = 6
191187 nr = N
192188 outrows = Matrix{String}(undef, nr + 1, nc)
193189
194- outrows[1, :] = ["", "DOF", "ΔDOF", "SSR", "ΔSSR",
195- "R²", "ΔR²", "F*", "p(>F)"]
190+ outrows[1, :] = ["SSR", "dof", "ΔSSR", "Δdof", "F*", "p(>F)"]
196191
197- # get rid of negative zero -- doesn' t matter mathematically,
198- # but messes up doctests and various other things
199- # cf. Issue #461
200- r2vals = [replace(@sprintf(" %.4f" , val), " -0.0000" => " 0.0000" ) for val in ftr. r2]
201-
202- outrows[2 , :] = [" [1]" , @sprintf(" %.0d" , ftr. dof[1 ]), " " ,
203- @sprintf(" %.4f" , ftr. ssr[1 ]), " " ,
204- r2vals[1 ], " " , " " , " " ]
192+ outrows[2, :] = [@sprintf("%.4f", ftr.ssr[1]),
193+ @sprintf("%.0d", ftr.dof[1]),
194+ " ",
195+ " ",
196+ " ",
197+ " "]
205198
206199 for i in 2:nr
207- outrows[i + 1 , :] = [" [$i ]" ,
208- @sprintf(" %.0d" , ftr. dof[i]), @sprintf(" %.0d" , Δdof[i - 1 ]),
209- @sprintf(" %.4f" , ftr. ssr[i]), @sprintf(" %.4f" , Δssr[i - 1 ]),
210- r2vals[i], @sprintf(" %.4f" , ΔR²[i - 1 ]),
211- @sprintf(" %.4f" , ftr. fstat[i]), string(PValue(ftr. pval[i]))]
200+ outrows[i + 1, :] = [@sprintf("%.4f", ftr.ssr[i]),
201+ @sprintf("%.0d", ftr.dof[i]),
202+ @sprintf("%.4f", Δssr[i - 1]),
203+ @sprintf("%.0d", Δdof[i - 1]),
204+ @sprintf("%.4f", ftr.fstat[i]),
205+ string(PValue(ftr.pval[i]))]
212206 end
213207 colwidths = length.(outrows)
214208 max_colwidths = [maximum(view(colwidths, :, i)) for i in 1:nc]
215- totwidth = sum(max_colwidths) + 2 * 8
209+ totwidth = sum(max_colwidths) + 2 * (nc - 1)
216210
217211 println(io, "F-test: $N models fitted on $(ftr.nobs) observations")
218212 println(io, ' ─' ^totwidth)
0 commit comments