Skip to content

Commit 5356e6c

Browse files
authored
Refactor name generation of the Map transform (#272)
* Refactor name generation of the 'Map' transform * Update docstring
1 parent e9f97db commit 5356e6c

File tree

2 files changed

+72
-13
lines changed

2 files changed

+72
-13
lines changed

src/transforms/map.jl

+20-4
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ The column selection can be a single column identifier (index or name),
1212
a collection of identifiers or a regular expression (regex).
1313
1414
Passing a target column name is optional and when omitted a new name
15-
is generated by joining the selected column names with the function name.
15+
is generated by joining the function name with the selected column names.
1616
If the target column already exists in the table, the original
1717
column will be replaced.
1818
1919
# Examples
2020
2121
```julia
2222
Map(1 => sin)
23-
Map(:a => sin, "b" => cos => :b_cos)
23+
Map(:a => sin, "b" => cos => :cos_b)
2424
Map([2, 3] => ((b, c) -> 2b + c))
2525
Map([:a, :c] => ((a, c) -> 2a * 3c) => :col1)
2626
Map(["c", "a"] => ((c, a) -> 3c / a) => :col1, "c" => tan)
@@ -29,7 +29,12 @@ Map(r"[abc]" => ((a, b, c) -> a^2 - 2b + c) => "col1")
2929
3030
## Notes
3131
32-
* Anonymous functions must be passed with parentheses as in the examples above.
32+
* Anonymous functions must be passed with parentheses as in the examples above;
33+
* Some function names are treated in a special way, they are:
34+
* Anonymous functions: `#1` -> `f1`;
35+
* Composed functions: `outer ∘ inner` -> `outer_inner`;
36+
* `Base.Fix1` functions: `Base.Fix1(f, x)` -> `fix1_f`;
37+
* `Base.Fix2` functions: `Base.Fix2(f, x)` -> `fix2_f`;
3338
"""
3439
struct Map <: StatelessFeatureTransform
3540
selectors::Vector{ColumnSelector}
@@ -59,7 +64,18 @@ end
5964

6065
isrevertible(::Type{Map}) = false
6166

62-
_makename(snames, fun) = Symbol(join([snames; nameof(fun)], "_"))
67+
_funname(fun::Base.Fix1) = "fix1_" * _funname(fun.f)
68+
_funname(fun::Base.Fix2) = "fix2_" * _funname(fun.f)
69+
_funname(fun::ComposedFunction) = _funname(fun.outer) * "_" * _funname(fun.inner)
70+
_funname(fun) = string(fun)
71+
72+
function _makename(snames, fun)
73+
funname = _funname(fun)
74+
if contains(funname, "#") # anonymous functions
75+
funname = replace(funname, "#" => "f")
76+
end
77+
Symbol(funname, :_, join(snames, "_"))
78+
end
6379

6480
function applyfeat(transform::Map, feat, prep)
6581
cols = Tables.columns(feat)

test/transforms/map.jl

+52-9
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99

1010
T = Map(1 => sin)
1111
n, c = apply(T, t)
12-
@test Tables.schema(n).names == (:a, :b, :c, :d, :a_sin)
13-
@test n.a_sin == sin.(t.a)
12+
@test Tables.schema(n).names == (:a, :b, :c, :d, :sin_a)
13+
@test n.sin_a == sin.(t.a)
1414

1515
T = Map(:b => cos)
1616
n, c = apply(T, t)
17-
@test Tables.schema(n).names == (:a, :b, :c, :d, :b_cos)
18-
@test n.b_cos == cos.(t.b)
17+
@test Tables.schema(n).names == (:a, :b, :c, :d, :cos_b)
18+
@test n.cos_b == cos.(t.b)
1919

2020
T = Map("c" => tan)
2121
n, c = apply(T, t)
22-
@test Tables.schema(n).names == (:a, :b, :c, :d, :c_tan)
23-
@test n.c_tan == tan.(t.c)
22+
@test Tables.schema(n).names == (:a, :b, :c, :d, :tan_c)
23+
@test n.tan_c == tan.(t.c)
2424

2525
T = Map(:a => sin => :a)
2626
n, c = apply(T, t)
@@ -44,15 +44,58 @@
4444

4545
T = Map(["c", "a"] => ((c, a) -> 3c / a) => :op1, "c" => tan)
4646
n, c = apply(T, t)
47-
@test Tables.schema(n).names == (:a, :b, :c, :d, :op1, :c_tan)
47+
@test Tables.schema(n).names == (:a, :b, :c, :d, :op1, :tan_c)
4848
@test n.op1 == @. 3 * t.c / t.a
49-
@test n.c_tan == tan.(t.c)
49+
@test n.tan_c == tan.(t.c)
5050

5151
T = Map(r"[abc]" => ((a, b, c) -> a^2 - 2b + c) => "op1")
5252
n, c = apply(T, t)
5353
@test Tables.schema(n).names == (:a, :b, :c, :d, :op1)
5454
@test n.op1 == @. t.a^2 - 2 * t.b + t.c
5555

56-
# throws
56+
# generated names
57+
# normal function
58+
T = Map([:c, :d] => hypot)
59+
n, c = apply(T, t)
60+
@test Tables.schema(n).names == (:a, :b, :c, :d, :hypot_c_d)
61+
@test n.hypot_c_d == hypot.(t.c, t.d)
62+
63+
# anonymous function
64+
f = a -> a^2 + 3
65+
fname = replace(string(f), "#" => "f")
66+
colname = Symbol(fname, :_a)
67+
T = Map(:a => f)
68+
n, c = apply(T, t)
69+
@test Tables.schema(n).names == (:a, :b, :c, :d, colname)
70+
@test Tables.getcolumn(n, colname) == f.(t.a)
71+
72+
# composed function
73+
f = sin cos
74+
T = Map(:b => f)
75+
n, c = apply(T, t)
76+
@test Tables.schema(n).names == (:a, :b, :c, :d, :sin_cos_b)
77+
@test n.sin_cos_b == f.(t.b)
78+
79+
f = sin cos tan
80+
T = Map(:c => sin cos tan)
81+
n, c = apply(T, t)
82+
@test Tables.schema(n).names == (:a, :b, :c, :d, :sin_cos_tan_c)
83+
@test n.sin_cos_tan_c == f.(t.c)
84+
85+
# Base.Fix1
86+
f = Base.Fix1(hypot, 2)
87+
T = Map(:d => f)
88+
n, c = apply(T, t)
89+
@test Tables.schema(n).names == (:a, :b, :c, :d, :fix1_hypot_d)
90+
@test n.fix1_hypot_d == f.(t.d)
91+
92+
# Base.Fix2
93+
f = Base.Fix2(hypot, 2)
94+
T = Map(:a => f)
95+
n, c = apply(T, t)
96+
@test Tables.schema(n).names == (:a, :b, :c, :d, :fix2_hypot_a)
97+
@test n.fix2_hypot_a == f.(t.a)
98+
99+
# error: cannot create Map transform without arguments
57100
@test_throws ArgumentError Map()
58101
end

0 commit comments

Comments
 (0)