diff --git a/src/statmodels.jl b/src/statmodels.jl index b0644fac5..960c6fd8a 100644 --- a/src/statmodels.jl +++ b/src/statmodels.jl @@ -277,7 +277,7 @@ Adjusted pseudo-coefficient of determination (adjusted pseudo R-squared). For nonlinear models, one of the several pseudo R² definitions must be chosen via `variant`. The only currently supported variants are `:MacFadden`, defined as ``1 - (\\log (L) - k)/\\log (L0)`` and -`:devianceratio`, defined as ``1 - (D/(n-k))/(D_0/(n-1))``. +`:devianceratio`, defined as ``1 - (D/(n-k))/(D_0/(n-1))``. In these formulas, ``L`` is the likelihood of the model, ``L0`` that of the null model (the model including only the intercept), ``D`` is the deviance of the model, ``D_0`` is the deviance of the null model, ``n`` is the number of observations (given by [`nobs`](@ref)) and @@ -319,7 +319,7 @@ response(model::RegressionModel) = error("response is not defined for $(typeof(m """ responsename(model::RegressionModel) - + Return the name of the model response (a.k.a. the dependent variable). """ responsename(model::RegressionModel) = error("responsename is not defined for $(typeof(model)).") @@ -451,7 +451,7 @@ end Show a p-value using 6 characters, either using the standard 0.XXXX representation or as , :≥, :(isless), :(isequal)] # isless and < to place nice with NaN + @eval begin + Base.$op(x::Union{TestStat, PValue}, y::Real) = $op(x.v, y) + Base.$op(y::Real, x::Union{TestStat, PValue}) = $op(y, x.v) + Base.$op(x1::Union{TestStat, PValue}, x2::Union{TestStat, PValue}) = $op(x1.v, x2.v) + end +end + +# necessary to avoid a method ambiguity with isless(::TestStat, NaN) +Base.isless(x::Union{TestStat, PValue}, y::AbstractFloat) = isless(x.v, y) +Base.isless(y::AbstractFloat, x::Union{TestStat, PValue},) = isless(y, x.v) +Base.isequal(y::AbstractFloat, x::Union{TestStat, PValue}) = isequal(y, x.v) +Base.isequal(x::Union{TestStat, PValue}, y::AbstractFloat) = isequal(x.v, y) + + +Base.isapprox(x::Union{TestStat, PValue}, y::Real; kwargs...) = isapprox(x.v, y; kwargs...) +Base.isapprox(y::Real, x::Union{TestStat, PValue}; kwargs...) = isapprox(y, x.v; kwargs...) +Base.isapprox(x1::Union{TestStat, PValue}, x2::Union{TestStat, PValue}; kwargs...) = isapprox(x1.v, x2.v; kwargs...) + """Wrap a string so that show omits quotes""" struct NoQuote @@ -493,7 +516,7 @@ function show(io::IO, ct::CoefTable) rownms = [lpad("[$i]",floor(Integer, log10(nr))+3) for i in 1:nr] end mat = [j == 1 ? NoQuote(rownms[i]) : - j-1 == ct.pvalcol ? PValue(cols[j-1][i]) : + j-1 == ct.pvalcol ? NoQuote(sprint(show, PValue(cols[j-1][i]))) : j-1 in ct.teststatcol ? TestStat(cols[j-1][i]) : cols[j-1][i] isa AbstractString ? NoQuote(cols[j-1][i]) : cols[j-1][i] for i in 1:nr, j in 1:nc+1] diff --git a/test/statmodels.jl b/test/statmodels.jl index 918d89f70..82234d9bd 100644 --- a/test/statmodels.jl +++ b/test/statmodels.jl @@ -1,5 +1,5 @@ using StatsBase -using StatsBase: PValue +using StatsBase: PValue, TestStat using Test, Random v1 = [1.45666, -23.14, 1.56734e-13] @@ -63,6 +63,73 @@ end @test_throws ErrorException PValue(-0.1) @test_throws ErrorException PValue(1.1) @test PValue(PValue(0.05)) === PValue(0.05) +@test isless(PValue(0.01), 0.05) +@test isless(PValue(0.01), NaN) == isless(0.01, NaN) +@test (PValue(0.01) < NaN) == (0.01 < NaN) +@test isless(NaN, PValue(0.01)) == isless(NaN, 0.01) +@test (NaN < PValue(0.01)) == (NaN < 0.01) +@test isequal(NaN, PValue(0.01)) == isequal(NaN, 0.01) +@test (NaN == PValue(0.01)) == (NaN == 0.01) +@test isequal(PValue(0.01), NaN) == isequal(0.01, NaN) +@test (PValue(0.01) == NaN) == (0.01 == NaN) +@test isequal(PValue(0.05), 0.05) +@test isapprox(PValue(0.05), 0.05) +@test PValue(0.05) <= 0.05 +@test PValue(0.1) > 0.05 +@test PValue(0.1) >= PValue(0.05) +@test PValue(0.05) <= PValue(0.05) +@test PValue(0.1) > PValue(0.05) +@test PValue(0.1) >= PValue(0.05) +@test 0.1 >= PValue(0.05) +@test 0.05 <= PValue(0.05) +@test 0.1 > PValue(0.05) +@test 0.1 >= PValue(0.05) +# exact equality should hold here since it's the exact same atomic operations +@test float(PValue(Rational(1,3))) == float(1/3) +@test PValue(Rational(1,3)) == Rational(1,3) +@test PValue(Rational(1,3)) ≈ 1/3 +@test PValue(Rational(1,3)) == PValue(Rational(1,3)) +@test PValue(Rational(1,3)) ≈ PValue(1/3) +@test Rational(1,3) == PValue(Rational(1,3)) +@test Rational(1,3) ≈ PValue(1/3) atol=0.01 +@test PValue(Rational(1,3)) isa Real + +@test sprint(show, TestStat(1e-1)) == "0.10" +@test sprint(show, TestStat(1e-5)) == "0.00" +@test sprint(show, TestStat(π)) == "3.14" +@test TestStat(TestStat(0.05)) === TestStat(0.05) +@test isless(TestStat(0.01), 0.05) +@test isless(TestStat(0.01), NaN) == isless(0.01, NaN) +@test (TestStat(0.01) < NaN) == (0.01 < NaN) +@test isless(NaN, TestStat(0.01)) == isless(NaN, 0.01) +@test (NaN < TestStat(0.01)) == (NaN < 0.01) +@test isequal(TestStat(0.01), NaN) == isequal(0.01, NaN) +@test (TestStat(0.01) == NaN) == (0.01 == NaN) +@test isequal(NaN, TestStat(0.01)) == isequal(NaN, 0.01) +@test (NaN == TestStat(0.01)) == (NaN == 0.01) +@test isequal(TestStat(0.05), 0.05) + +@test isapprox(TestStat(0.05), 0.05) +@test TestStat(0.05) <= 0.05 +@test TestStat(0.1) > 0.05 +@test TestStat(0.1) >= TestStat(0.05) +@test TestStat(0.05) <= TestStat(0.05) +@test TestStat(0.1) > TestStat(0.05) +@test TestStat(0.1) >= TestStat(0.05) +@test 0.1 >= TestStat(0.05) +@test 0.05 <= TestStat(0.05) +@test 0.1 > TestStat(0.05) +@test 0.1 >= TestStat(0.05) +# exact equality should hold here since it's the exact same atomic operations +@test float(TestStat(Rational(1,3))) == float(1/3) +@test TestStat(Rational(1,3)) == Rational(1,3) +@test TestStat(Rational(1,3)) ≈ 1/3 +@test TestStat(Rational(1,3)) == TestStat(Rational(1,3)) +@test TestStat(Rational(1,3)) ≈ TestStat(1/3) +@test Rational(1,3) == TestStat(Rational(1,3)) +@test Rational(1,3) ≈ TestStat(1/3) +@test TestStat(Rational(1,3)) isa Real +@test TestStat(π) ≈ 3.14 atol=0.01 @test sprint(showerror, ConvergenceException(10)) == "failure to converge after 10 iterations."