diff --git a/src/terms.jl b/src/terms.jl index f9a89c17..42f12264 100644 --- a/src/terms.jl +++ b/src/terms.jl @@ -547,8 +547,10 @@ function modelcols(t::InteractionTerm, d::ColumnTable) row_kron_insideout(*, (modelcols(term, d) for term in t.terms)...) end -modelcols(t::InterceptTerm{true}, d::NamedTuple) = ones(size(first(d))) -modelcols(t::InterceptTerm{false}, d) = Matrix{Float64}(undef, size(first(d),1), 0) +# use Bool as the eltype here to avoid promoting e.g. Float32s in other columns +# to Float64 unless it's really necessary +modelcols(t::InterceptTerm{true}, d::NamedTuple) = ones(Bool, size(first(d))) +modelcols(t::InterceptTerm{false}, d) = Matrix{Bool}(undef, size(first(d),1), 0) modelcols(t::FormulaTerm, d::NamedTuple) = (modelcols(t.lhs,d), modelcols(t.rhs, d)) diff --git a/test/modelmatrix.jl b/test/modelmatrix.jl index efa1ff2f..d0f95e86 100644 --- a/test/modelmatrix.jl +++ b/test/modelmatrix.jl @@ -402,5 +402,32 @@ f = apply_schema(@formula(0 ~ a&b&c), schema(t)) @test vec(modelcols(f.rhs, t)) == modelcols.(Ref(f.rhs), Tables.rowtable(t)) end + + @testset "#293 conversion of Float32s" begin + d = (; y=rand(Float32, 4), x=rand(Float32, 4), z=[1:4; ]) + f = @formula(y ~ 1 + x + log(x) * z) + y, x = modelcols(apply_schema(f, schema(d)), d) + @test eltype(y) == eltype(x) == Float32 + + f0 = @formula(y ~ 0 + x + log(x) * z) + y, x = modelcols(apply_schema(f0, schema(d)), d) + @test eltype(y) == eltype(x) == Float32 + + fint = @formula(y ~ 1 + z) + y, x = modelcols(apply_schema(fint, schema(d)), d) + @test eltype(x) == Int + + # currently this is the best way to construct contrasts with Float32s... + dummy_cmat = Float32[1 0 0 + 0 1 0 + 0 0 1 + 0 0 0] + contr = StatsModels.ContrastsCoding(dummy_cmat, [1:4;]) + + sch = schema(f, d, Dict(:z => contr)) + y, x = modelcols(apply_schema(f, sch), d) + @test size(x) == (4, 1 + 1 + 1 + 3 + 3) + @test eltype(x) == eltype(y) == Float32 + end end