Skip to content

Commit

Permalink
Fix intercept detector traits and hasresponse (#144)
Browse files Browse the repository at this point in the history
* tests for intercepts/responses

* has/omitsintercept(::FormulaTerm), widen hasresponse

* use TermOrTerms for traits, instance vs. type for response

* more thorough tests of intercept/response traits

* use !== because we really mean it
  • Loading branch information
kleinschmidt committed Sep 28, 2019
1 parent c7f0db7 commit a8217fa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 8 deletions.
13 changes: 10 additions & 3 deletions src/terms.jl
Expand Up @@ -559,14 +559,21 @@ StatsBase.coefnames(t::InteractionTerm) =
################################################################################
# old Terms features:

hasintercept(t::AbstractTerm) = InterceptTerm{true}() terms(t) || ConstantTerm(1) terms(t)
omitsintercept(t::AbstractTerm) =
hasintercept(f::FormulaTerm) = hasintercept(f.rhs)
hasintercept(t::TermOrTerms) =
InterceptTerm{true}() terms(t) ||
ConstantTerm(1) terms(t)
omitsintercept(f::FormulaTerm) = omitsintercept(f.rhs)
omitsintercept(t::TermOrTerms) =
InterceptTerm{false}() terms(t) ||
ConstantTerm(0) terms(t) ||
ConstantTerm(-1) terms(t)

hasresponse(t) = false
hasresponse(t::FormulaTerm{LHS}) where {LHS} = LHS !== nothing
hasresponse(t::FormulaTerm) =
t.lhs !== nothing &&
t.lhs !== ConstantTerm(0) &&
t.lhs !== InterceptTerm{false}()

# convenience converters
"""
Expand Down
18 changes: 13 additions & 5 deletions test/formula.jl
Expand Up @@ -5,16 +5,24 @@
y, x1, x2, x3, a, b, c, onet = term.((:y, :x1, :x2, :x3, :a, :b, :c, 1))

## totally empty
@test_broken t = @eval @formula $(:($nothing ~ 0))
@test_broken hasresponse(t) == false
@test_broken hasintercept(t) == false
@test_broken t.rhs == ConstantTerm(0)
@test_broken issetequal(terms(t), [ConstantTerm(0)])
t = @formula(0 ~ 0)
@test !hasresponse(t)
@test !hasintercept(t)
@test omitsintercept(t)
@test t.rhs == ConstantTerm(0)
@test issetequal(terms(t), [ConstantTerm(0)])

## empty lhs, intercept on rhs
t = @formula(0 ~ 1)
@test !hasresponse(t)
@test hasintercept(t)
@test !omitsintercept(t)

## empty RHS
t = @formula(y ~ 0)
@test hasintercept(t) == false
@test omitsintercept(t) == true
@test hasresponse(t)
@test t.rhs == ConstantTerm(0)
@test issetequal(terms(t), term.((:y, 0)))

Expand Down
57 changes: 57 additions & 0 deletions test/terms.jl
Expand Up @@ -92,4 +92,61 @@ StatsModels.apply_schema(mt::MultiTerm, sch::StatsModels.Schema, Mod::Type) =

@test terms2 == terms3
end

@testset "Intercept and response traits" begin

has_responses = [term(:y), term(1), InterceptTerm{true}(), term(:y)+term(:z),
term(:y) + term(0), term(:y) + InterceptTerm{false}()]
no_responses = [term(0), InterceptTerm{false}()]

has_intercepts = [term(1), InterceptTerm{true}()]
omits_intercepts = [term(0), term(-1), InterceptTerm{false}()]

using StatsModels: hasresponse, hasintercept, omitsintercept

a = term(:a)

for lhs in has_responses, rhs in has_intercepts
@test hasresponse(lhs ~ rhs)
@test hasintercept(lhs ~ rhs)
@test !omitsintercept(lhs ~ rhs)

@test hasresponse(lhs ~ rhs + a)
@test hasintercept(lhs ~ rhs + a)
@test !omitsintercept(lhs ~ rhs + a)

end

for lhs in no_responses, rhs in has_intercepts
@test !hasresponse(lhs ~ rhs)
@test hasintercept(lhs ~ rhs)
@test !omitsintercept(lhs ~ rhs)

@test !hasresponse(lhs ~ rhs + a)
@test hasintercept(lhs ~ rhs + a)
@test !omitsintercept(lhs ~ rhs + a)
end

for lhs in has_responses, rhs in omits_intercepts
@test hasresponse(lhs ~ rhs)
@test !hasintercept(lhs ~ rhs)
@test omitsintercept(lhs ~ rhs)

@test hasresponse(lhs ~ rhs + a)
@test !hasintercept(lhs ~ rhs + a)
@test omitsintercept(lhs ~ rhs + a)
end

for lhs in no_responses, rhs in omits_intercepts
@test !hasresponse(lhs ~ rhs)
@test !hasintercept(lhs ~ rhs)
@test omitsintercept(lhs ~ rhs)

@test !hasresponse(lhs ~ rhs + a)
@test !hasintercept(lhs ~ rhs + a)
@test omitsintercept(lhs ~ rhs + a)
end

end

end

0 comments on commit a8217fa

Please sign in to comment.