Can I do linear regression over physical data with Unitful?

Hi all!
I want to fit a multiple linear model on some data I collected. I decorated my data with units of measure using Unitful.jl, and I use GLM.jl’s lm function to produce the model. However, I can’t make it work. To not clutter too much with my real code, here’s a toy MWE:

using DataFrames;
using Unitful;   
using GLM;
using Plots;
using MLJ: partition;

function splitDataFrame(df::AbstractDataFrame, r::Number)
    train, test = partition(df, r, shuffle=true)
end

x = range(1,100) .* u"W"
data = 50u"W" .+ 2x + 1u"W" * rand(100)
df = DataFrame([x, data], [:x, :data])
plot(x, data)
train, test = splitDataFrame(df, 0.8)
formula = @formula(data ~ 1 + x)
model = lm(formula, train)     # here's the problem

Specifically, I get

ERROR: promotion of types Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}} and Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}} failed to change any arguments
Stacktrace:
  [1] error(::String, ::String, ::String)
    @ Base ./error.jl:44
  [2] sametype_error(input::Tuple{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}})
    @ Base ./promotion.jl:405
  [3] not_sametype(x::Tuple{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, y::Tuple{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}})
    @ Base ./promotion.jl:399
  [4] promote(x::Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, y::Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}, z::Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}, a::Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}})
    @ Base ./promotion.jl:393
  [5] concrete_term(t::Term, xs::Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, #unused#::Type{ContinuousTerm})
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:204
  [6] concrete_term(t::Term, xs::Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, #unused#::Nothing)
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:200
  [7] concrete_term(t::Term, dt::NamedTuple{(:data, :x), Tuple{Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, Vector{Quantity{Int64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}}}, hints::Dict{Symbol, Any})
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:186
  [8] (::StatsModels.var"#60#61"{NamedTuple{(:data, :x), Tuple{Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, Vector{Quantity{Int64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}}}, Dict{Symbol, Any}})(t::Term)
    @ StatsModels ./none:0
  [9] iterate
    @ ./generator.jl:47 [inlined]
 [10] Dict{Term, AbstractTerm}(kv::Base.Generator{Vector{AbstractTerm}, StatsModels.var"#60#61"{NamedTuple{(:data, :x), Tuple{Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, Vector{Quantity{Int64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}}}, Dict{Symbol, Any}}})
    @ Base ./dict.jl:83
 [11] Schema
    @ ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:37 [inlined]
 [12] schema
    @ ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:125 [inlined]
 [13] schema(f::FormulaTerm{Term, Tuple{ConstantTerm{Int64}, Term}}, data::NamedTuple{(:data, :x), Tuple{Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, Vector{Quantity{Int64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}}}, hints::Dict{Symbol, Any})
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/schema.jl:128
 [14] ModelFrame(f::FormulaTerm{Term, Tuple{ConstantTerm{Int64}, Term}}, data::NamedTuple{(:x, :data), Tuple{Vector{Quantity{Int64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}, Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}}}; model::Type{LinearModel}, contrasts::Dict{Symbol, Any})
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/modelframe.jl:83
 [15] fit(::Type{LinearModel}, f::FormulaTerm{Term, Tuple{ConstantTerm{Int64}, Term}}, data::DataFrame, args::Nothing; contrasts::Dict{Symbol, Any}, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ StatsModels ~/.julia/packages/StatsModels/Wzvuu/src/statsmodel.jl:85
 [16] fit
    @ ~/.julia/packages/StatsModels/Wzvuu/src/statsmodel.jl:78 [inlined]
 [17] #lm#5
    @ ~/.julia/packages/GLM/6ycOV/src/lm.jl:157 [inlined]
 [18] lm
    @ ~/.julia/packages/GLM/6ycOV/src/lm.jl:157 [inlined]
 [19] lm(X::FormulaTerm{Term, Tuple{ConstantTerm{Int64}, Term}}, y::DataFrame)
    @ GLM ~/.julia/packages/GLM/6ycOV/src/lm.jl:157
 [20] top-level scope
    @ REPL[12]:1

Can I integrate Unitful and GLM? Or are they incompatible?

Thanks!

1 Like