From 6d1bc045aa76dd3e1a0994de791bc59de60fd6e7 Mon Sep 17 00:00:00 2001 From: Nicole Epp <nicole.epp@invenia.ca> Date: Wed, 10 Feb 2021 16:03:11 -0600 Subject: [PATCH 1/4] Implement general case non-mutating apply --- src/periodic.jl | 31 ++++------------- src/transformers.jl | 74 +++++++++++++++++++++++++++++++++------- test/periodic.jl | 43 ++++++++++++------------ test/power.jl | 82 ++++++++++++++++++++++++--------------------- 4 files changed, 134 insertions(+), 96 deletions(-) diff --git a/src/periodic.jl b/src/periodic.jl index 0c25ba2..4c953a3 100644 --- a/src/periodic.jl +++ b/src/periodic.jl @@ -35,34 +35,17 @@ Returns a `Periodic` transform with zero phase shift. """ Periodic(f, period::T) where T = Periodic(f, period, zero(T)) -function _apply!(x::AbstractArray{T}, P::Periodic; kwargs...) where T <: Real - x[:] = P.f.(2π .* (x .- P.phase_shift) / P.period) - return x +function _apply(x, P::Periodic; kwargs...) + return P.f.(2π .* (x .- P.phase_shift) / P.period) end -# `U <: Period` needed to avoid method ambiguity with -# `apply(table, P::Periodic{T}; cols=nothing) where T <: Period` -function apply( - x::AbstractArray{T}, - P::Periodic{U}; - kwargs... -) where {T <: TimeType, U <: Period} - return map(xi -> _periodic(P.f, xi, P.period, P.phase_shift), x) +function _apply(x, P::Periodic{T}; kwargs...) where T <: Period + map(xi -> _periodic(P.f, xi, P.period, P.phase_shift), x) end -""" - Transforms.apply(table, ::Periodic{T}; cols=nothing) where T <: Period -> Array - -Applies [`Periodic`](@ref) to each of the specified columns in `table`. -If no `cols` are specified, then [`Periodic`](@ref) is applied to all columns. -Returns an array containing each transformed column, in the same order as `cols`. -""" -function apply(table, P::Periodic{T}; cols=nothing) where T <: Period - Tables.istable(table) || throw(MethodError(apply, (table, P))) - - columntable = Tables.columns(table) - cnames = cols === nothing ? propertynames(columntable) : cols - return [apply(getproperty(columntable, cname), P) for cname in cnames] +function _apply!(x::AbstractArray{T}, P::Periodic; kwargs...) where T <: Real + x[:] = apply(x, P; kwargs...) + return x end """ diff --git a/src/transformers.jl b/src/transformers.jl index 238b8ef..e7a1c1e 100644 --- a/src/transformers.jl +++ b/src/transformers.jl @@ -28,30 +28,80 @@ Non-mutating version of [`transform!`](@ref). function transform end """ - Transforms.apply!(data::T, ::Transform; kwargs...) -> T + apply(data::T, ::Transform; kwargs...) + +Applies the [`Transform`](@ref) to the data. New transforms should usually only extend +`_apply` which this method delegates to. + +Where possible, this should be extended for new data types `T`. +""" +function apply end + +""" + apply!(data::T, ::Transform; kwargs...) -> T + +Applies the [`Transform`](@ref) mutating the input `data`. New transforms should usually +only extend `_apply!` which this method delegates to. -Applies the [`Transform`](@ref) mutating the input `data`. Where possible, this should be extended for new data types `T`. """ function apply! end + """ - Transforms.apply(data::T, ::Transform; kwargs...) -> T + apply(A::AbstractArray, ::Transform; dims=:, inds=:, kwargs...) -Non-mutating version of [`apply!`](@ref), which it delegates to by default. -Does not need to be extended unless a mutating [`Transform`](@ref) is not possible. +Applies the [`Transform`](@ref) to each element of `A`. +Optionally specify the `dims` to apply the [`Transform`](@ref) along certain dimensions +and `inds` will be the indices to apply the Transform to along the `dims` specified. +If `dims` === : (all dimensions), then `inds` will be the global indices of the array, +instead of being relative to a certain dimension. + +Will return the same datatype except for AxisArrays as operations on those do not preserve +type. """ -function apply end +function apply(A::AbstractArray, t::Transform; dims=:, inds=:, kwargs...) + if dims === Colon() + if inds === Colon() + return _apply(A, t; kwargs...) + else + return _apply(A[:][inds], t; kwargs...) + end + end + + return mapslices(x -> _apply(x[inds], t; kwargs...), A, dims=dims) +end """ - apply!(A::AbstractArray{T}, ::Transform; dims=:, kwargs...) where T <: Real + apply(table, ::Transform; cols=nothing, kwargs...) + +Applies the [`Transform`](@ref) to each of the specified columns in the `table`. +If no `cols` are specified, then the [`Transform`](@ref) is applied to all columns. + +Returns an array containing each transformed column, in the same order as `cols`. +""" +function apply(table, t::Transform; cols=nothing, kwargs...) + Tables.istable(table) || throw(MethodError(apply!, (table, t))) + + # Extract a columns iterator that we should be able to use to mutate the data. + # NOTE: Mutation is not guaranteed for all table types, but it avoid copying the data + columntable = Tables.columns(table) + + cnames = cols === nothing ? propertynames(columntable) : cols + return [_apply(getproperty(columntable, cname), t; kwargs...) for cname in cnames] +end + +#TODO: should this be apply! ? +_apply(x, t::Transform; kwargs...) = apply!(_try_copy(x), t; kwargs...) + + +""" + apply!(A::AbstractArray, ::Transform; dims=:, kwargs...) Applies the [`Transform`](@ref) to each element of `A`. Optionally specify the `dims` to apply the [`Transform`](@ref) along certain dimensions. """ -function apply!( - A::AbstractArray{T}, t::Transform; dims=:, kwargs... -) where T <: Real +function apply!(A::AbstractArray, t::Transform; dims=:, kwargs...) dims == Colon() && return _apply!(A, t; kwargs...) for x in eachslice(A; dims=dims) @@ -61,10 +111,8 @@ function apply!( return A end -apply(x, t::Transform; kwargs...) = apply!(_try_copy(x), t; kwargs...) - """ - Transforms.apply!(table::T, ::Transform; cols=nothing)::T where T + apply!(table::T, ::Transform; cols=nothing)::T where T Applies the [`Transform`](@ref) to each of the specified columns in the `table`. If no `cols` are specified, then the [`Transform`](@ref) is applied to all columns. diff --git a/test/periodic.jl b/test/periodic.jl index 2ad8ee1..85147fd 100644 --- a/test/periodic.jl +++ b/test/periodic.jl @@ -127,12 +127,14 @@ @testset "dims = $d" for d in (Colon(), 1, 2) transformed = Transforms.apply(A, p; dims=d) - @test transformed isa AxisArray + # AxisArray doesn't preserve type when operations are performed on it + @test transformed isa AbstractArray @test transformed ≈ A_expected atol=1e-14 end _A = copy(A) Transforms.apply!(_A, p) + @test _A isa AxisArray @test _A ≈ A_expected atol=1e-14 end @@ -163,12 +165,12 @@ @testset "all cols" begin transformed = Transforms.apply(nt, p) - @test transformed isa NamedTuple{(:a, :b)} - @test collect(transformed) ≈ collect(nt_expected) atol=1e-14 - @test collect(p(nt)) ≈ collect(nt_expected) atol=1e-14 + @test transformed ≈ collect(nt_expected) atol=1e-14 + @test p(nt) ≈ collect(nt_expected) atol=1e-14 _nt = deepcopy(nt) Transforms.apply!(_nt, p) + @test _nt isa NamedTuple{(:a, :b)} @test collect(_nt) ≈ collect(nt_expected) atol=1e-14 end @@ -177,12 +179,12 @@ nt_expected_ = merge(nt, nt_mutated) transformed = Transforms.apply(nt, p; cols=[c]) - @test transformed isa NamedTuple{(:a, :b)} # before applying `collect` - @test collect(transformed) ≈ collect(nt_expected_) atol=1e-14 - @test collect(p(nt; cols=[c])) ≈ collect(nt_expected_) atol=1e-14 + @test transformed ≈ [collect(nt_expected_[c])] atol=1e-14 + @test p(nt; cols=[c]) ≈ [collect(nt_expected_[c])] atol=1e-14 _nt = deepcopy(nt) Transforms.apply!(_nt, p; cols=[c]) + @test _nt isa NamedTuple{(:a, :b)} # before applying `collect` @test collect(_nt) ≈ collect(nt_expected_) atol=1e-14 end end @@ -191,23 +193,19 @@ df = DataFrame(:a => collect(0.:2.), :b => collect(3.:5.)) df_expected = DataFrame(:a => expected[1:3], :b => expected[4:6]) - transformed = Transforms.apply(df, p) - @test transformed isa DataFrame - @test transformed ≈ df_expected atol=1e-14 + @test Transforms.apply(df, p) ≈ [df_expected.a, df_expected.b] atol=1e-14 - @test ≈( - Transforms.apply(df, p; cols=[:a]), - DataFrame(:a => expected[1:3], :b => collect(3.:5.)), - atol=1e-14 - ) - @test ≈( - Transforms.apply(df, p; cols=[:b]), - DataFrame(:a => collect(0.:2.), :b => expected[4:6]), - atol=1e-14 - ) + @testset "cols = $c" for c in (:a, :b) + @test ≈( + Transforms.apply(df, p; cols=[c]), + [df_expected[!, c]], + atol=1e-14 + ) + end _df = deepcopy(df) Transforms.apply!(_df, p) + @test _df isa DataFrame @test _df ≈ df_expected atol=1e-14 end end @@ -271,9 +269,12 @@ @testset "dims = $d" for d in (Colon(), 1, 2) transformed = Transforms.apply(A, p; dims=d) - @test transformed isa AxisArray + # AxisArray doesn't preserve type when operations are performed on it + @test transformed isa AbstractArray @test transformed ≈ expected atol=1e-14 end + + # TODO: confirm we don't support mutating periodic for Time Types end @testset "AxisKey" begin diff --git a/test/power.jl b/test/power.jl index a1ccb38..54ec237 100644 --- a/test/power.jl +++ b/test/power.jl @@ -30,44 +30,21 @@ end end - @testset "NamedTuple" begin - nt = (a = [1, 2, 3], b = [4, 5, 6]) - expected = (a = [1, 8, 27], b = [64, 125, 216]) - - @testset "all cols" begin - transformed = Transforms.apply(nt, p) - @test transformed isa NamedTuple{(:a, :b)} - @test transformed == expected - @test p(nt) == expected - - _nt = deepcopy(nt) - Transforms.apply!(_nt, p) - @test _nt == expected - end - - @testset "cols = $c" for c in (:a, :b) - nt_mutated = NamedTuple{(Symbol("$c"), )}((expected[c], )) - nt_expected = merge(nt, nt_mutated) - - @test Transforms.apply(nt, p; cols=[c]) == nt_expected - @test p(nt; cols=[c]) == nt_expected - - _nt = deepcopy(nt) - Transforms.apply!(_nt, p; cols=[c]) - @test _nt == nt_expected - end - end - @testset "AxisArray" begin A = AxisArray([1 2 3; 4 5 6], foo=["a", "b"], bar=["x", "y", "z"]) - expected = AxisArray([1 8 27; 64 125 216], foo=["a", "b"], bar=["x", "y", "z"]) + expected = [1 8 27; 64 125 216] @testset "dims = $d" for d in (Colon(), 1, 2) transformed = Transforms.apply(A, p; dims=d) - @test transformed isa AxisArray + # AxisArray doesn't preserve the type it operates on + @test transformed isa AbstractArray @test transformed == expected end + _A = copy(A) + Transforms.apply!(_A, p) + @test _A isa AxisArray + @test _A == expected end @testset "AxisKey" begin @@ -82,23 +59,52 @@ _A = copy(A) Transforms.apply!(_A, p) + @test _A isa KeyedArray @test _A == expected end + @testset "NamedTuple" begin + nt = (a = [1, 2, 3], b = [4, 5, 6]) + expected = [[1, 8, 27], [64, 125, 216]] + expected_nt = (a = [1, 8, 27], b = [64, 125, 216]) + + @testset "all cols" begin + @test Transforms.apply(nt, p) == expected + @test p(nt) == expected + + _nt = deepcopy(nt) + Transforms.apply!(_nt, p) + @test _nt isa NamedTuple{(:a, :b)} + @test _nt == expected_nt + end + + @testset "cols = $c" for c in (:a, :b) + nt_mutated = NamedTuple{(Symbol("$c"), )}((expected_nt[c], )) + expected_nt_mutated = merge(nt, nt_mutated) + + @test Transforms.apply(nt, p; cols=[c]) == [expected_nt[c]] + @test p(nt; cols=[c]) == [expected_nt[c]] + + _nt = deepcopy(nt) + Transforms.apply!(_nt, p; cols=[c]) + @test _nt == expected_nt_mutated + @test _nt isa NamedTuple + end + end + @testset "DataFrame" begin df = DataFrame(:a => [1, 2, 3], :b => [4, 5, 6]) - expected = DataFrame(:a => [1, 8, 27], :b => [64, 125, 216]) + expected_df = DataFrame(:a => [1, 8, 27], :b => [64, 125, 216]) + expected = [expected_df.a, expected_df.b] - transformed = Transforms.apply(df, p) - @test transformed isa DataFrame - @test transformed == expected + @test Transforms.apply(df, p) == expected - @test Transforms.apply(df, p; cols=[:a]) == DataFrame(:a => [1, 8, 27], :b => [4, 5, 6]) - @test Transforms.apply(df, p; cols=[:b]) == DataFrame(:a => [1, 2, 3], :b => [64, 125, 216]) + @test Transforms.apply(df, p; cols=[:a]) == [expected_df.a] + @test Transforms.apply(df, p; cols=[:b]) ==[expected_df.b] _df = deepcopy(df) Transforms.apply!(_df, p) - @test _df == expected + @test _df isa DataFrame + @test _df == expected_df end - end From e15d02fa26a8a72e8015b80c601568a69f553d81 Mon Sep 17 00:00:00 2001 From: Nicole Epp <nicole.epp@invenia.ca> Date: Thu, 11 Feb 2021 09:32:45 -0600 Subject: [PATCH 2/4] Resolve small PR comments --- src/periodic.jl | 2 +- src/transformers.jl | 6 +++--- test/periodic.jl | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/periodic.jl b/src/periodic.jl index 4c953a3..beaab77 100644 --- a/src/periodic.jl +++ b/src/periodic.jl @@ -44,7 +44,7 @@ function _apply(x, P::Periodic{T}; kwargs...) where T <: Period end function _apply!(x::AbstractArray{T}, P::Periodic; kwargs...) where T <: Real - x[:] = apply(x, P; kwargs...) + x[:] = _apply(x, P; kwargs...) return x end diff --git a/src/transformers.jl b/src/transformers.jl index e7a1c1e..3f131ba 100644 --- a/src/transformers.jl +++ b/src/transformers.jl @@ -57,8 +57,8 @@ and `inds` will be the indices to apply the Transform to along the `dims` specif If `dims` === : (all dimensions), then `inds` will be the global indices of the array, instead of being relative to a certain dimension. -Will return the same datatype except for AxisArrays as operations on those do not preserve -type. +May not return the same data type depending on what the data type is, and what `dims` and +`inds` were specified. """ function apply(A::AbstractArray, t::Transform; dims=:, inds=:, kwargs...) if dims === Colon() @@ -81,7 +81,7 @@ If no `cols` are specified, then the [`Transform`](@ref) is applied to all colum Returns an array containing each transformed column, in the same order as `cols`. """ function apply(table, t::Transform; cols=nothing, kwargs...) - Tables.istable(table) || throw(MethodError(apply!, (table, t))) + Tables.istable(table) || throw(MethodError(apply, (table, t))) # Extract a columns iterator that we should be able to use to mutate the data. # NOTE: Mutation is not guaranteed for all table types, but it avoid copying the data diff --git a/test/periodic.jl b/test/periodic.jl index 85147fd..1afb64f 100644 --- a/test/periodic.jl +++ b/test/periodic.jl @@ -273,8 +273,6 @@ @test transformed isa AbstractArray @test transformed ≈ expected atol=1e-14 end - - # TODO: confirm we don't support mutating periodic for Time Types end @testset "AxisKey" begin From 652bb72ae9897084899a81d700601677a0722fe5 Mon Sep 17 00:00:00 2001 From: Nicole Epp <nicole.epp@invenia.ca> Date: Thu, 11 Feb 2021 14:56:01 -0600 Subject: [PATCH 3/4] Add inds tests --- src/power.jl | 6 +++++- test/periodic.jl | 30 ++++++++++++++++++++++++++++++ test/power.jl | 30 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/power.jl b/src/power.jl index 95010a5..d628e85 100644 --- a/src/power.jl +++ b/src/power.jl @@ -7,7 +7,11 @@ struct Power <: Transform exponent::Real end +function _apply(x::AbstractArray{T}, P::Power; kwargs...) where T <: Real + return x .^ P.exponent +end + function _apply!(x::AbstractArray{T}, P::Power; kwargs...) where T <: Real - x[:] = x .^ P.exponent + x[:] = _apply(x, P; kwargs...) return x end diff --git a/test/periodic.jl b/test/periodic.jl index 1afb64f..0aa81e1 100644 --- a/test/periodic.jl +++ b/test/periodic.jl @@ -98,6 +98,15 @@ _x = copy(x) Transforms.apply!(_x, p) @test _x ≈ expected atol=1e-14 + + @testset "inds" begin + @test Transforms.apply(x, p; inds=2:5) ≈ expected[2:5] atol=1e-14 + @test Transforms.apply(x, p; dims=:) ≈ expected atol=1e-14 + @test Transforms.apply(x, p; dims=1) ≈ expected atol=1e-14 + @test Transforms.apply(x, p; dims=1, inds=[2, 3, 4, 5]) ≈ expected[2:5] atol=1e-14 + + @test_throws BoundsError Transforms.apply(x, p; dims=2) + end end @testset "Matrix" begin @@ -113,6 +122,13 @@ Transforms.apply!(_M, p; dims=d) @test _M ≈ M_expected atol=1e-14 end + + @testset "inds" begin + @test Transforms.apply(M, p; inds=[2, 3]) ≈ M_expected[[2, 3]] atol=1e-14 + @test Transforms.apply(M, p; dims=:, inds=[2, 3]) ≈ M_expected[[2, 3]] atol=1e-14 + @test Transforms.apply(M, p; dims=1, inds=[2]) ≈ reshape(M_expected[[2, 5]], 1, 2) atol=1e-14 + @test Transforms.apply(M, p; dims=2, inds=[2]) ≈ reshape(M_expected[[4, 5, 6]], 3, 1) atol=1e-14 + end end @testset "AxisArray" begin @@ -136,6 +152,13 @@ Transforms.apply!(_A, p) @test _A isa AxisArray @test _A ≈ A_expected atol=1e-14 + + @testset "inds" begin + @test Transforms.apply(A, p; inds=[2, 3]) ≈ A_expected[[2, 3]] atol=1e-14 + @test Transforms.apply(A, p; dims=:, inds=[2, 3]) ≈ A_expected[[2, 3]] atol=1e-14 + @test Transforms.apply(A, p; dims=1, inds=[2]) ≈ reshape(A_expected[[2, 5]], 1, 2) atol=1e-14 + @test Transforms.apply(A, p; dims=2, inds=[2]) ≈ reshape(A_expected[[4, 5, 6]], 3, 1) atol=1e-14 + end end @testset "AxisKey" begin @@ -157,6 +180,13 @@ _A = copy(A) Transforms.apply!(_A, p) @test _A ≈ A_expected atol=1e-14 + + @testset "inds" begin + @test Transforms.apply(A, p; inds=[2, 3]) ≈ [A_expected[2], A_expected[3]] atol=1e-14 + @test Transforms.apply(A, p; dims=:, inds=[2, 3]) ≈ [A_expected[2], A_expected[3]] atol=1e-14 + @test Transforms.apply(A, p; dims=1, inds=[2]) ≈ reshape([A_expected[2], A_expected[5]], 1, 2) atol=1e-14 + @test Transforms.apply(A, p; dims=2, inds=[2]) ≈ reshape([A_expected[4], A_expected[5], A_expected[6]], 3, 1) atol=1e-14 + end end @testset "NamedTuple" begin diff --git a/test/power.jl b/test/power.jl index 54ec237..8ec2066 100644 --- a/test/power.jl +++ b/test/power.jl @@ -14,6 +14,15 @@ _x = copy(x) Transforms.apply!(_x, p) @test _x == expected + + @testset "inds" begin + @test Transforms.apply(x, p; inds=2:5) == expected[2:5] + @test Transforms.apply(x, p; dims=:) == expected + @test Transforms.apply(x, p; dims=1) == expected + @test Transforms.apply(x, p; dims=1, inds=[2, 3, 4, 5]) == expected[2:5] + + @test_throws BoundsError Transforms.apply(x, p; dims=2) + end end @testset "Matrix" begin @@ -28,6 +37,13 @@ Transforms.apply!(_M, p; dims=d) @test _M == expected end + + @testset "inds" begin + @test Transforms.apply(M, p; inds=[2, 3]) == expected[[2, 3]] + @test Transforms.apply(M, p; dims=:, inds=[2, 3]) == expected[[2, 3]] + @test Transforms.apply(M, p; dims=1, inds=[2]) == [64 125 216] + @test Transforms.apply(M, p; dims=2, inds=[2]) == reshape([8, 125], 2, 1) + end end @testset "AxisArray" begin @@ -45,6 +61,13 @@ Transforms.apply!(_A, p) @test _A isa AxisArray @test _A == expected + + @testset "inds" begin + @test Transforms.apply(A, p; inds=[2, 3]) == expected[[2, 3]] + @test Transforms.apply(A, p; dims=:, inds=[2, 3]) == expected[[2, 3]] + @test Transforms.apply(A, p; dims=1, inds=[2]) == [64 125 216] + @test Transforms.apply(A, p; dims=2, inds=[2]) == reshape([8, 125], 2, 1) + end end @testset "AxisKey" begin @@ -61,6 +84,13 @@ Transforms.apply!(_A, p) @test _A isa KeyedArray @test _A == expected + + @testset "inds" begin + @test Transforms.apply(A, p; inds=[2, 3]) == [64, 8] + @test Transforms.apply(A, p; dims=:, inds=[2, 3]) == [64, 8] + @test Transforms.apply(A, p; dims=1, inds=[2]) == [64 125 216] + @test Transforms.apply(A, p; dims=2, inds=[2]) == reshape([8, 125], 2, 1) + end end @testset "NamedTuple" begin From 2becaea1d48b102dea334c1090ae0d0e54d1178e Mon Sep 17 00:00:00 2001 From: Nicole Epp <nicole.epp@invenia.ca> Date: Thu, 11 Feb 2021 15:05:43 -0600 Subject: [PATCH 4/4] Clarify docstrings --- src/transformers.jl | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/transformers.jl b/src/transformers.jl index 3f131ba..a356315 100644 --- a/src/transformers.jl +++ b/src/transformers.jl @@ -33,7 +33,7 @@ function transform end Applies the [`Transform`](@ref) to the data. New transforms should usually only extend `_apply` which this method delegates to. -Where possible, this should be extended for new data types `T`. +Where necessary, this should be extended for new data types `T`. """ function apply end @@ -43,7 +43,7 @@ function apply end Applies the [`Transform`](@ref) mutating the input `data`. New transforms should usually only extend `_apply!` which this method delegates to. -Where possible, this should be extended for new data types `T`. +Where necessary, this should be extended for new data types `T`. """ function apply! end @@ -51,14 +51,17 @@ function apply! end """ apply(A::AbstractArray, ::Transform; dims=:, inds=:, kwargs...) -Applies the [`Transform`](@ref) to each element of `A`. -Optionally specify the `dims` to apply the [`Transform`](@ref) along certain dimensions -and `inds` will be the indices to apply the Transform to along the `dims` specified. -If `dims` === : (all dimensions), then `inds` will be the global indices of the array, +Applies the [`Transform`](@ref) to the elements of `A`. +Provide the `dims` keyword to apply the [`Transform`](@ref) along a certain dimension. +Provide the `inds` keyword to apply the [`Transform`](@ref) to certain indices along the +`dims` specified. + +Note: if `dims === :` (all dimensions), then `inds` will be the global indices of the array, instead of being relative to a certain dimension. -May not return the same data type depending on what the data type is, and what `dims` and -`inds` were specified. +This method does not guarantee the data type of what is returned. It will try to conserve +type but the returned type depends on what the original `A` was, and the `dims` and `inds` +specified. """ function apply(A::AbstractArray, t::Transform; dims=:, inds=:, kwargs...) if dims === Colon() @@ -73,7 +76,7 @@ function apply(A::AbstractArray, t::Transform; dims=:, inds=:, kwargs...) end """ - apply(table, ::Transform; cols=nothing, kwargs...) + apply(table, ::Transform; cols=nothing, kwargs...) -> Vector Applies the [`Transform`](@ref) to each of the specified columns in the `table`. If no `cols` are specified, then the [`Transform`](@ref) is applied to all columns. @@ -91,8 +94,7 @@ function apply(table, t::Transform; cols=nothing, kwargs...) return [_apply(getproperty(columntable, cname), t; kwargs...) for cname in cnames] end -#TODO: should this be apply! ? -_apply(x, t::Transform; kwargs...) = apply!(_try_copy(x), t; kwargs...) +_apply(x, t::Transform; kwargs...) = _apply!(_try_copy(x), t; kwargs...) """