Skip to content

Commit

Permalink
added has_intercept (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pietro Vertechi authored and nalimilan committed Dec 14, 2017
1 parent ec5ed7b commit 5896a9f
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/statsmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,28 @@ struct DataFrameRegressionModel{M,T} <: RegressionModel
mm::ModelMatrix{T}
end

"""
drop_intercept(::Type)
Define whether a given model automatically drops the intercept. Return `false` by default.
To specify that a model type `T` drops the intercept, overload this function for the
corresponding type: `drop_intercept(::Type{T}) = true`
Models that drop the intercept will be fitted without one: the intercept term will be
removed even if explicitly provided by the user. Categorical variables will be expanded
in the rank-reduced form (contrasts for `n` levels will only produce `n-1` columns).
"""
drop_intercept(::Type) = false

for (modeltype, dfmodeltype) in ((:StatisticalModel, DataFrameStatisticalModel),
(:RegressionModel, DataFrameRegressionModel))
@eval begin
function StatsBase.fit(::Type{T}, f::Formula, df::AbstractDataFrame,
args...; contrasts::Dict = Dict(), kwargs...) where T<:$modeltype
mf = ModelFrame(f, df, contrasts=contrasts)
trms = Terms(f)
drop_intercept(T) && (trms.intercept = true)
mf = ModelFrame(trms, df, contrasts=contrasts)
drop_intercept(T) && (mf.terms.intercept = false)
mm = ModelMatrix(mf)
y = model_response(mf)
$dfmodeltype(fit(T, mm.m, y, args...; kwargs...), mf, mm)
Expand Down
35 changes: 35 additions & 0 deletions test/statsmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,41 @@ fit(DummyMod, f3, d, contrasts = Dict(:x1p => EffectsCoding(),
@test_throws Exception fit(DummyMod, f3, d, contrasts = Dict(:x1p => EffectsCoding(),
:x2p => 1))

# A dummy RegressionModel type that does not support intercept
struct DummyModNoIntercept <: RegressionModel
beta::Vector{Float64}
x::Matrix
y::Vector
end

StatsModels.drop_intercept(::Type{DummyModNoIntercept}) = true

## dumb fit method: just copy the x and y input over
StatsBase.fit(::Type{DummyModNoIntercept}, x::Matrix, y::Vector) =
DummyModNoIntercept(collect(1:size(x, 2)), x, y)
StatsBase.model_response(mod::DummyModNoIntercept) = mod.y
## dumb coeftable: just prints the "beta" values
StatsBase.coeftable(mod::DummyModNoIntercept) =
CoefTable(reshape(mod.beta, (size(mod.beta,1), 1)),
["'beta' value"],
["" for n in 1:size(mod.x,2)],
0)

f1 = @formula(y ~ 1 + x1 * x2)
f2 = @formula(y ~ 0 + x1 * x2)
m1 = fit(DummyModNoIntercept, f1, d)
m2 = fit(DummyModNoIntercept, f2, d)
ct1 = coeftable(m1)
ct2 = coeftable(m2)
@test ct1.rownms == ct2.rownms == ["x1", "x2", "x1 & x2"]

f1 = @formula(y ~ 1 + x1p)
f2 = @formula(y ~ 0 + x1p)
m1 = fit(DummyModNoIntercept, f1, d)
m2 = fit(DummyModNoIntercept, f2, d)
ct1 = coeftable(m1)
ct2 = coeftable(m2)
@test ct1.rownms == ct2.rownms == ["x1p: 6", "x1p: 7", "x1p: 8"]

## Another dummy model type to test fall-through show method
struct DummyModTwo <: RegressionModel
Expand Down

0 comments on commit 5896a9f

Please sign in to comment.