Skip to content

Commit 351d388

Browse files
authored
Handle unitless columns in Unit transform (#297)
* Handle unitless columns in Unit transform * Add string column to new test
1 parent cf0d5fc commit 351d388

File tree

2 files changed

+38
-14
lines changed

2 files changed

+38
-14
lines changed

src/transforms/unit.jl

+17-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
"""
66
Unit(unit)
77
8-
Converts the units of all columns in the table to `unit`.
8+
Converts the units of all columns in the table to `unit` from Unitful.jl.
99
1010
Unit(cols₁ => unit₁, cols₂ => unit₂, ..., colsₙ => unitₙ)
1111
1212
Converts the units of selected columns `cols₁`, `cols₂`, ..., `colsₙ`
1313
to `unit₁`, `unit₂`, ... `unitₙ`.
1414
15-
The column selection can be a single column identifier (index or name),
16-
a collection of identifiers or a regular expression (regex).
15+
Unitless columns become unitful if they are explicitly selected.
1716
1817
# Examples
1918
@@ -39,10 +38,6 @@ Unit(pairs::Pair...) = Unit(collect(selector.(first.(pairs))), collect(last.(pai
3938

4039
isrevertible(::Type{<:Unit}) = true
4140

42-
_uconvert(u, x) = _uconvert(nonmissingtype(eltype(x)), u, x)
43-
_uconvert(::Type, _, x) = (x, nothing)
44-
_uconvert(::Type{Q}, u, x) where {Q<:AbstractQuantity} = (map(v -> uconvert(u, v), x), unit(Q))
45-
4641
function applyfeat(transform::Unit, feat, prep)
4742
cols = Tables.columns(feat)
4843
names = Tables.columnnames(cols)
@@ -59,7 +54,7 @@ function applyfeat(transform::Unit, feat, prep)
5954
x = Tables.getcolumn(cols, name)
6055
if haskey(unitdict, name)
6156
u = unitdict[name]
62-
_uconvert(u, x)
57+
_withunit(u, x)
6358
else
6459
(x, nothing)
6560
end
@@ -80,9 +75,22 @@ function revertfeat(::Unit, newfeat, fcache)
8075
ounits = fcache
8176
columns = map(names, ounits) do name, u
8277
x = Tables.getcolumn(cols, name)
83-
isnothing(u) ? x : map(v -> uconvert(u, v), x)
78+
_withoutunit(u, x)
8479
end
8580

8681
𝒯 = (; zip(names, columns)...)
8782
𝒯 |> Tables.materializer(newfeat)
8883
end
84+
85+
_withunit(u, x) = _withunit(nonmissingtype(eltype(x)), u, x)
86+
_withunit(::Type{Q}, u, x) where {Q<:AbstractQuantity} = (map(v -> uconvert(u, v), x), unit(Q))
87+
_withunit(::Type{Q}, u, x) where {Q<:Number} = (x * u, NoUnits)
88+
89+
function _withoutunit(u, x)
90+
if u === NoUnits
91+
map(ustrip, x)
92+
else
93+
map(xᵢ -> uconvert(u, xᵢ), x)
94+
end
95+
end
96+
_withoutunit(::Nothing, x) = x

test/transforms/unit.jl

+21-5
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,23 @@
55
b = [300, 500, missing, 800, missing, 400] * u"cm"
66
c = [8, 2, 5, 7, 9, 4] * u"km"
77
d = [0.3, 0.1, 0.9, 0.2, 0.7, 0.4]
8-
e = ["no", "no", "yes", "yes", "no", "yes"]
9-
t = Table(; a, b, c, d, e)
8+
t = Table(; a, b, c, d)
109

1110
T = Unit(u"m")
1211
n, c = apply(T, t)
1312
@test unit(eltype(n.a)) == u"m"
1413
@test unit(eltype(n.b)) == u"m"
1514
@test unit(eltype(n.c)) == u"m"
16-
@test eltype(n.d) <: Float64
17-
@test eltype(n.e) <: String
15+
@test unit(eltype(n.d)) == u"m"
1816
tₒ = revert(T, n, c)
1917
@test unit(eltype(tₒ.a)) == u"m"
2018
@test unit(eltype(tₒ.b)) == u"cm"
2119
@test unit(eltype(tₒ.c)) == u"km"
20+
@test unit(eltype(tₒ.d)) == NoUnits
2221
@test all(isapprox.(tₒ.a, t.a))
2322
@test all(isapprox.(skipmissing(tₒ.b), skipmissing(t.b)))
2423
@test all(isapprox.(tₒ.c, t.c))
2524
@test tₒ.d == t.d
26-
@test tₒ.e == t.e
2725

2826
a = [2.7, 2.9, 2.2, 1.4, 1.8, 3.3] * u"m"
2927
b = [300, 500, missing, 800, missing, 400] * u"cm"
@@ -160,6 +158,24 @@
160158
@test tₒ.e == t.e
161159
@test tₒ.f == t.f
162160

161+
# table with unitless columns
162+
a = [2.0, 2.0, 3.0] * u"m"
163+
b = [4.0, 5.0, 6.0]
164+
c = [7.0, 8.0, 9.0]
165+
d = ["no", "yes", "no"]
166+
t = Table(; a, b, c, d)
167+
T = Unit("b" => u"kg")
168+
n, c = apply(T, t)
169+
@test unit(eltype(n.a)) == u"m"
170+
@test unit(eltype(n.b)) == u"kg"
171+
@test unit(eltype(n.c)) == NoUnits
172+
@test eltype(n.d) <: String
173+
tₒ = revert(T, n, c)
174+
@test unit(eltype(tₒ.a)) == u"m"
175+
@test unit(eltype(tₒ.b)) == NoUnits
176+
@test unit(eltype(tₒ.c)) == NoUnits
177+
@test eltype(tₒ.d) <: String
178+
163179
# error: cannot create Unit transform without arguments
164180
@test_throws ArgumentError Unit()
165181
end

0 commit comments

Comments
 (0)