diff --git a/Project.toml b/Project.toml index b44a5a8..fbcb05b 100644 --- a/Project.toml +++ b/Project.toml @@ -5,7 +5,6 @@ version = "1.1.0" [deps] AxisArrays = "39de3d68-74b9-583c-8d2d-e117c070f3a9" -DataScienceTraits = "6cb2f572-2d2b-4ba6-bdb3-e710fa044d6c" Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" @@ -15,17 +14,14 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -TableTransforms = "0d432bfd-3ee1-4ac1-886a-39f05cc69a3e" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" [compat] AxisArrays = "0.4" -DataScienceTraits = "0.1" Distances = "0.10" Distributions = "0.25" FillArrays = "1.6" StaticArrays = "1.6" StatsBase = "0.34" -TableTransforms = "1.16" Tables = "1.11" julia = "1.9" diff --git a/README.md b/README.md index e2889d1..9753d49 100644 --- a/README.md +++ b/README.md @@ -143,9 +143,9 @@ julia> c == cā‚’ false ``` -### Transforms +### Log-ratio transformations -Currently, the following transforms are implemented: +Currently, the following log-ratio transformations are implemented: ```julia julia> alr(c) @@ -167,8 +167,8 @@ julia> ilr(c) and their inverses `alrinv`, `clrinv` and `ilrinv`. -The package also defines transforms for tables following to the -[TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) interface, including `Closure`, `Remainder`, `ALR`, `CLR`, `ILR`. +The transforms for tables are defined in the [TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) +package, they are: `Closure`, `Remainder`, `ALR`, `CLR`, `ILR`. These transforms are functors that can be used as follows: ```julia diff --git a/src/CoDa.jl b/src/CoDa.jl index 29631fa..4a3f922 100644 --- a/src/CoDa.jl +++ b/src/CoDa.jl @@ -5,36 +5,27 @@ module CoDa using Tables -using TableTransforms -using Distributions using StatsBase -using StaticArrays +using Statistics +using Distributions using LinearAlgebra +using StaticArrays using FillArrays using AxisArrays -using Statistics using Random using Printf -import Tables -import DataScienceTraits as DST -import TableTransforms: FeatureTransform -import TableTransforms: StatelessFeatureTransform -import TableTransforms: SciTypeAssertion -import TableTransforms: assertions, isrevertible -import TableTransforms: applyfeat, revertfeat -import TableTransforms: preprocess, reapply -import Distances: Metric, result_type import Base: +, -, *, /, == import Base: zero, adjoint, inv +import Distances: Metric, result_type import Statistics: mean, var, std -import LinearAlgebra: norm, ā‹… +import LinearAlgebra: norm, dot import Random: rand include("compositions.jl") include("codaarrays.jl") include("distances.jl") -include("transforms.jl") +include("logratio.jl") include("covariances.jl") include("matrices.jl") @@ -44,6 +35,7 @@ export parts, components, norm, + dot, ā‹…, smooth, š’ž, @@ -59,13 +51,7 @@ export Aitchison, aitchison, - # transforms - Closure, - Remainder, - LogRatio, - ALR, - CLR, - ILR, + # log-ratio alr, alrinv, clr, @@ -90,4 +76,5 @@ export G, HMatrix, H + end diff --git a/src/codaarrays.jl b/src/codaarrays.jl index 647a456..d26b443 100644 --- a/src/codaarrays.jl +++ b/src/codaarrays.jl @@ -40,25 +40,26 @@ Parts in compositional `array`. parts(::CoDaArray{D,PARTS}) where {D,PARTS} = PARTS """ - compose(table, cols; keepcols=true, as=:coda) + compose(table, colnames; keepcols=true, as=:coda) -Convert columns `cols` of `table` into parts of a +Convert columns `colnames` of `table` into parts of a composition and save the result in a [`CoDaArray`](@ref). If `keepcols` is set to `true`, then save the result `as` a column in a new table with all other columns preserved. """ -function compose(table, cols=Tables.columnnames(table); keepcols=true, as=:coda) +function compose(table, colnames=Tables.columnnames(Tables.columns(table)); keepcols=true, as=:coda) + cols = Tables.columns(table) + names = Tables.columnnames(cols) + scols = (nm => Tables.getcolumn(cols, nm) for nm in colnames) # construct compositional array from selected columns - coda = table |> Select(cols) |> CoDaArray + coda = (; scols...) |> CoDaArray # different types of return if keepcols - other = setdiff(Tables.columnnames(table), cols) - osel = table |> Select(other) - ocol = [o => Tables.getcolumn(osel, o) for o in other] + other = setdiff(names, colnames) + ocols = (nm => Tables.getcolumn(cols, nm) for nm in other) # preserve input table type - š’Æ = Tables.materializer(table) - š’Æ((; ocol..., as => coda)) + (; ocols..., as => coda) |> Tables.materializer(table) else coda end @@ -76,4 +77,4 @@ Tables.rows(array::CoDaArray) = array # implement row interface for Composition Tables.getcolumn(c::Composition, i::Int) = getfield(c, :data)[i] Tables.getcolumn(c::Composition, n::Symbol) = getfield(c, :data)[n] -Tables.columnnames(c::Composition{D,PARTS}) where {D,PARTS} = PARTS +Tables.columnnames(::Composition{D,PARTS}) where {D,PARTS} = PARTS diff --git a/src/compositions.jl b/src/compositions.jl index 3358fd4..eaa329a 100644 --- a/src/compositions.jl +++ b/src/compositions.jl @@ -22,8 +22,7 @@ julia> Composition((:a, :b), (0.2, 0.8)) ``` When the names of the parts are not specified, the -constructor uses default names `part1`, `part2`, -..., `partD`: +constructor uses default names `w1`, `w2`, ..., `wD`: ``` julia> Composition(0.1, 0.8) @@ -40,7 +39,7 @@ Composition(; data...) = Composition((; data...)) Composition(parts::NTuple, comps) = Composition((; zip(parts, Tuple(comps))...)) -Composition(comps) = Composition(ntuple(i -> Symbol("w$i"), length(comps)), comps) +Composition(comps) = Composition(ntuple(i -> Symbol(:w, i), length(comps)), comps) Composition(comp::Real, comps...) = Composition((comp, comps...)) @@ -81,7 +80,7 @@ zero(T::Type{<:Composition{D}}) where {D} = Composition(parts(T), ntuple(i -> 1 ==(cā‚::Composition, cā‚‚::Composition) = parts(cā‚) == parts(cā‚‚) && š’ž(components(cā‚)) ā‰ˆ š’ž(components(cā‚‚)) -ā‹…(cā‚::Composition{D}, cā‚‚::Composition{D}) where {D} = begin +function dot(cā‚::Composition{D}, cā‚‚::Composition{D}) where {D} x, y = components(cā‚), components(cā‚‚) sum(log(x[i] / x[j]) * log(y[i] / y[j]) for j in 1:D for i in (j + 1):D) / D end @@ -147,7 +146,4 @@ end # IO METHODS # ----------- -function Base.show(io::IO, c::Composition) - w = [(@sprintf "%.03f" w) for w in components(c)] - show(io, join(w, " : ")) -end +Base.show(io::IO, c::Composition) = join(io, (@sprintf("%.03f", w) for w in components(c)), " : ") diff --git a/src/covariances.jl b/src/covariances.jl index 26205e3..55456e8 100644 --- a/src/covariances.jl +++ b/src/covariances.jl @@ -11,7 +11,6 @@ Return the variation matrix `Ī¤` of the `table` such that: """ function variation(table) X = Tables.matrix(table) - n = Tables.columnnames(table) |> collect D = size(X, 2) L = log.(X .+ eps()) @@ -27,7 +26,9 @@ function variation(table) end end - AxisArray(T, row=n, col=n) + cols = Tables.columns(table) + names = Tables.columnnames(cols) |> collect + AxisArray(T, row=names, col=names) end """ @@ -38,12 +39,14 @@ Return the log-ratio covariance matrix `Ī£` of the `table` such that: - `Ī£[i,j] = cov(log(x[i]/x[D]), log(x[j]/x[D]))` for `i, j = 1, ..., d` """ function alrcov(table) - alrtable = table |> ALR() - - Ī£ = cov(Tables.matrix(alrtable), dims=1) + X = Tables.matrix(table) + Y = mapslices(alr āˆ˜ Composition, X, dims=2) + Ī£ = cov(Y, dims=1) - vars = Tables.columnnames(alrtable) |> collect - AxisArray(Ī£, row=vars, col=vars) + cols = Tables.columns(table) + names = Tables.columnnames(cols) |> collect + names = names[begin:(end - 1)] + AxisArray(Ī£, row=names, col=names) end """ @@ -55,12 +58,13 @@ Return the centered log-ratio covariance matrix `Ī“` of the `table` such that: where `g(x)` is the geometric mean. """ function clrcov(table) - clrtable = table |> CLR() - - Ī“ = cov(Tables.matrix(clrtable), dims=1) + X = Tables.matrix(table) + Y = mapslices(clr āˆ˜ Composition, X, dims=2) + Ī“ = cov(Y, dims=1) - vars = Tables.columnnames(clrtable) |> collect - AxisArray(Ī“, row=vars, col=vars) + cols = Tables.columns(table) + names = Tables.columnnames(cols) |> collect + AxisArray(Ī“, row=names, col=names) end """ @@ -87,6 +91,7 @@ function lrarray(table) A[i, i] = 0.0 end - vars = Tables.columnnames(table) |> collect - AxisArray(A, row=vars, col=vars) + cols = Tables.columns(table) + names = Tables.columnnames(cols) |> collect + AxisArray(A, row=names, col=names) end diff --git a/src/logratio.jl b/src/logratio.jl new file mode 100644 index 0000000..c128b0b --- /dev/null +++ b/src/logratio.jl @@ -0,0 +1,7 @@ +# ------------------------------------------------------------------ +# Licensed under the MIT License. See LICENCE in the project root. +# ------------------------------------------------------------------ + +include("logratio/alr.jl") +include("logratio/clr.jl") +include("logratio/ilr.jl") diff --git a/src/logratio/alr.jl b/src/logratio/alr.jl new file mode 100644 index 0000000..f83fac3 --- /dev/null +++ b/src/logratio/alr.jl @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Licensed under the MIT License. See LICENCE in the project root. +# ------------------------------------------------------------------ + +""" + alr(c) + +Additive log-ratio transformation of composition `c`. +""" +function alr(c::Composition{D}) where {D} + w = components(c) .+ eps() + SVector(ntuple(i -> log(w[i] / w[D]), D - 1)) +end + +""" + alrinv(x) + +Inverse alr transformation of coordinates `x`. +""" +alrinv(x::SVector{D,T}) where {D,T<:Real} = Composition(š’ž([exp.(x); SVector(one(T))])) + +alrinv(x::AbstractVector) = alrinv(SVector{length(x)}(x)) diff --git a/src/transforms/clr.jl b/src/logratio/clr.jl similarity index 52% rename from src/transforms/clr.jl rename to src/logratio/clr.jl index e8159c8..3afbb63 100644 --- a/src/transforms/clr.jl +++ b/src/logratio/clr.jl @@ -2,10 +2,6 @@ # Licensed under the MIT License. See LICENCE in the project root. # ------------------------------------------------------------------ -# ------------- -# COMPOSITIONS -# ------------- - """ clr(c) @@ -25,34 +21,3 @@ Inverse clr transformation of coordinates `x`. clrinv(x::SVector{D,T}) where {D,T<:Real} = Composition(š’ž(exp.(x))) clrinv(x::AbstractVector) = clrinv(SVector{length(x)}(x)) - -# ------- -# TABLES -# ------- - -""" - CLR() - -Centered log-ratio transform following the -[TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) -interface. -""" -struct CLR <: LogRatio end - -refvar(::CLR, vars) = last(vars) - -newvars(::CLR, n) = collect(n) - -oldvars(::CLR, vars, rvar) = collect(vars) - -function applymatrix(::CLR, X) - Ī¼ = geomean.(eachrow(X)) - L = log.(X .+ eps()) - l = log.(Ī¼ .+ eps()) - L .- l -end - -function revertmatrix(::CLR, Y) - E = exp.(Y) - mapslices(š’ž, E, dims=2) -end diff --git a/src/transforms/ilr.jl b/src/logratio/ilr.jl similarity index 58% rename from src/transforms/ilr.jl rename to src/logratio/ilr.jl index 1e1ead7..b8f89ed 100644 --- a/src/transforms/ilr.jl +++ b/src/logratio/ilr.jl @@ -2,10 +2,6 @@ # Licensed under the MIT License. See LICENCE in the project root. # ------------------------------------------------------------------ -# ------------- -# COMPOSITIONS -# ------------- - """ ilr(c) @@ -54,37 +50,3 @@ function ilrinv(x::SVector{D}) where {D} end ilrinv(x::AbstractVector) = ilrinv(SVector{length(x)}(x)) - -# ------- -# TABLES -# ------- - -""" - ILR([refvar]) - -Isometric log-ratio transform following the -[TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) -interface. - -Optionally, specify the reference variable `refvar` for the ratios. -Default to the last column of the input table. -""" -struct ILR <: LogRatio - refvar::Union{Symbol,Nothing} -end - -ILR() = ILR(nothing) - -refvar(transform::ILR, vars) = isnothing(transform.refvar) ? last(vars) : transform.refvar - -newvars(::ILR, n) = collect(n)[begin:(end - 1)] - -oldvars(::ILR, vars, rvar) = [collect(vars); rvar] - -applymatrix(::ILR, X) = mapslices(ilr āˆ˜ Composition, X, dims=2) - -function revertmatrix(::ILR, Y) - D = size(Y, 2) - f = components āˆ˜ ilrinv āˆ˜ SVector{D} - mapslices(f, Y, dims=2) -end diff --git a/src/transforms.jl b/src/transforms.jl deleted file mode 100644 index cacc75f..0000000 --- a/src/transforms.jl +++ /dev/null @@ -1,93 +0,0 @@ -# ------------------------------------------------------------------ -# Licensed under the MIT License. See LICENCE in the project root. -# ------------------------------------------------------------------ - -# ----------------- -# BASIC TRANSFORMS -# ----------------- - -include("transforms/closure.jl") -include("transforms/remainder.jl") - -# --------------------- -# LOG-RATIO TRANSFORMS -# --------------------- - -""" - LogRatio - -A log-ratio transform following the -[TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) -interface. - -See also [`ALR`](@ref), [`CLR`](@ref), [`ILR`](@ref). -""" -abstract type LogRatio <: StatelessFeatureTransform end - -isrevertible(::Type{<:LogRatio}) = true - -assertions(::Type{<:LogRatio}) = [SciTypeAssertion{DST.Continuous}()] - -function applyfeat(transform::LogRatio, table, prep) - # original variable names - vars = Tables.columnnames(table) - - # reference variable - rvar = refvar(transform, vars) - @assert rvar āˆˆ vars "invalid reference variable" - rind = first(indexin([rvar], collect(vars))) - - # permute columns if necessary - ovars = setdiff(vars, (rvar,)) - pvars = [ovars; rvar] - ptable = table |> Select(pvars) - - # transformation - X = Tables.matrix(ptable) - Y = applymatrix(transform, X) - - # new variable names - n = newvars(transform, pvars) - - # return same table type - š’Æ = (; zip(n, eachcol(Y))...) - newtable = š’Æ |> Tables.materializer(table) - - newtable, (rvar, rind) -end - -function revertfeat(transform::LogRatio, table, fcache) - # retrieve cache - rvar, rind = fcache - - # trasformation - Y = Tables.matrix(table) - X = revertmatrix(transform, Y) - - # original variable names - vars = Tables.columnnames(table) - n = oldvars(transform, vars, rvar) - - # permute reference variable - n[[rind, end]] .= n[[end, rind]] - X[:, [rind, end]] .= X[:, [end, rind]] - - # return same table type - š’Æ = (; zip(n, eachcol(X))...) - š’Æ |> Tables.materializer(table) -end - -# to be implemented by log-ratio transforms -function refvar end -function newvars end -function oldvars end -function applymatrix end -function revertmatrix end - -# ---------------- -# IMPLEMENTATIONS -# ---------------- - -include("transforms/alr.jl") -include("transforms/clr.jl") -include("transforms/ilr.jl") diff --git a/src/transforms/alr.jl b/src/transforms/alr.jl deleted file mode 100644 index 402c261..0000000 --- a/src/transforms/alr.jl +++ /dev/null @@ -1,62 +0,0 @@ -# ------------------------------------------------------------------ -# Licensed under the MIT License. See LICENCE in the project root. -# ------------------------------------------------------------------ - -# ------------- -# COMPOSITIONS -# ------------- - -""" - alr(c) - -Additive log-ratio transformation of composition `c`. -""" -function alr(c::Composition{D}) where {D} - w = components(c) .+ eps() - SVector(ntuple(i -> log(w[i] / w[D]), D - 1)) -end - -""" - alrinv(x) - -Inverse alr transformation of coordinates `x`. -""" -alrinv(x::SVector{D,T}) where {D,T<:Real} = Composition(š’ž([exp.(x); SVector(one(T))])) - -alrinv(x::AbstractVector) = alrinv(SVector{length(x)}(x)) - -# ------- -# TABLES -# ------- - -""" - ALR([refvar]) - -Additive log-ratio transform following the -[TableTransforms.jl](https://github.com/JuliaML/TableTransforms.jl) -interface. - -Optionally, specify the reference variable `refvar` for the ratios. -Default to the last column of the input table. -""" -struct ALR <: LogRatio - refvar::Union{Symbol,Nothing} -end - -ALR() = ALR(nothing) - -refvar(transform::ALR, vars) = isnothing(transform.refvar) ? last(vars) : transform.refvar - -newvars(::ALR, n) = collect(n)[begin:(end - 1)] - -oldvars(::ALR, vars, rvar) = [collect(vars); rvar] - -function applymatrix(::ALR, X) - L = log.(X .+ eps()) - L[:, begin:(end - 1)] .- L[:, end] -end - -function revertmatrix(::ALR, Y) - E = [exp.(Y) ones(size(Y, 1))] - mapslices(š’ž, E, dims=2) -end diff --git a/src/transforms/closure.jl b/src/transforms/closure.jl deleted file mode 100644 index ca158f3..0000000 --- a/src/transforms/closure.jl +++ /dev/null @@ -1,54 +0,0 @@ -# ------------------------------------------------------------------ -# Licensed under the MIT License. See LICENCE in the project root. -# ------------------------------------------------------------------ - -""" - Closure() - -The transform that applies the closure operation š’ž -to all rows of the input table. The rows of the -output table sum to one. - -See also [`Remainder`](@ref). -""" -struct Closure <: StatelessFeatureTransform end - -isrevertible(::Type{Closure}) = true - -assertions(::Type{Closure}) = [SciTypeAssertion{DST.Continuous}()] - -function applyfeat(transform::Closure, table, prep) - # original column names - names = Tables.columnnames(table) - - # table as matrix and get the sum acros dims 2 - X = Tables.matrix(table) - S = sum(X, dims=2) - - # divides each row by its sum (closure operation) - Z = X ./ S - - # table with the old columns and the new values - š’Æ = (; zip(names, eachcol(Z))...) - newtable = š’Æ |> Tables.materializer(table) - - newtable, S -end - -function revertfeat(::Closure, newtable, fcache) - # transformed column names - names = Tables.columnnames(newtable) - - # table as matrix - Z = Tables.matrix(newtable) - - # retrieve cache - S = fcache - - # undo operation - X = Z .* S - - # table with original columns - š’Æ = (; zip(names, eachcol(X))...) - š’Æ |> Tables.materializer(newtable) -end diff --git a/src/transforms/remainder.jl b/src/transforms/remainder.jl deleted file mode 100644 index 9cf7f9f..0000000 --- a/src/transforms/remainder.jl +++ /dev/null @@ -1,77 +0,0 @@ -# ------------------------------------------------------------------ -# Licensed under the MIT License. See LICENCE in the project root. -# ------------------------------------------------------------------ - -""" - Remainder([total]) - -The transform that takes a table with columns `xā‚, xā‚‚, ā€¦, xā‚™` -and returns a new table with an additional column containing the -remainder value `xā‚™ā‚Šā‚ = total .- (xā‚ + xā‚‚ + ā‹Æ + xā‚™)` If the `total` -value is not specified, then default to the maximum sum across rows. - -See also [`Closure`](@ref). -""" -struct Remainder <: FeatureTransform - total::Union{Float64,Nothing} -end - -Remainder() = Remainder(nothing) - -isrevertible(::Type{Remainder}) = true - -assertions(::Type{Remainder}) = [SciTypeAssertion{DST.Continuous}()] - -function preprocess(transform::Remainder, table) - # find total across rows - if isnothing(transform.total) - feat, meta = TableTransforms.divide(table) - X = Tables.matrix(feat) - maximum(sum(X, dims=2)) - else - transform.total - end -end - -function applyfeat(transform::Remainder, table, prep) - # basic checks - for assertion in assertions(transform) - assertion(table) - end - - # design matrix - X = Tables.matrix(table) - - # retrieve the total - total = prep - - # make sure that the total is valid - @assert all(x -> x ā‰¤ total, sum(X, dims=2)) "the sum for each row must be less than total" - - # original column names - names = Tables.columnnames(table) - - # create a column with the remainder - S = sum(X, dims=2) - Z = [X (total .- S)] - - # create new column name - rname = :remainder - while rname āˆˆ names - rname = Symbol(rname, :_) - end - names = (names..., rname) - - # table with new column - š’Æ = (; zip(names, eachcol(Z))...) - newtable = š’Æ |> Tables.materializer(table) - - newtable, total -end - -function revertfeat(::Remainder, newtable, fcache) - names = Tables.columnnames(newtable) - Reject(last(names))(newtable) -end - -reapply(transform::Remainder, table, cache) = applyfeat(transform, table, first(cache)) |> first diff --git a/test/Project.toml b/test/Project.toml index 331c431..5679f9a 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -5,6 +5,5 @@ Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" RData = "df47a6cb-8c03-5eed-afd8-b6050d6c41da" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -TableTransforms = "0d432bfd-3ee1-4ac1-886a-39f05cc69a3e" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/logratio.jl b/test/logratio.jl new file mode 100644 index 0000000..9559620 --- /dev/null +++ b/test/logratio.jl @@ -0,0 +1,13 @@ +@testset "log-ratio" begin + # compositions + for c in [Composition(1, 2, 3), Composition(0, 2, 3), Composition(1, 2, 0)] + @test alrinv(alr(c)) == c + @test clrinv(clr(c)) == c + @test ilrinv(ilr(c)) == c + end + + # convenience methods for heap-allocated vectors + @test alrinv([1, 2, 3]) isa Composition{4} + @test clrinv([1, 2, 3]) isa Composition{3} + @test ilrinv([1, 2, 3]) isa Composition{4} +end diff --git a/test/runtests.jl b/test/runtests.jl index 875ac02..db45910 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,7 +4,6 @@ using RData using Tables using DataDeps using Distances -using TableTransforms using LinearAlgebra using Test, Random @@ -28,7 +27,7 @@ jura = RData.load(rda)["juraset"] CSV.write(joinpath(datadir, "jura.csv"), jura) # list of tests -testfiles = ["compositions.jl", "codaarrays.jl", "distances.jl", "transforms.jl", "covariances.jl", "matrices.jl"] +testfiles = ["compositions.jl", "codaarrays.jl", "distances.jl", "logratio.jl", "covariances.jl", "matrices.jl"] @testset "CoDa.jl" begin for testfile in testfiles diff --git a/test/transforms.jl b/test/transforms.jl deleted file mode 100644 index a477e10..0000000 --- a/test/transforms.jl +++ /dev/null @@ -1,68 +0,0 @@ -@testset "Transforms" begin - # compositions - for c in [Composition(1, 2, 3), Composition(0, 2, 3), Composition(1, 2, 0)] - @test alrinv(alr(c)) == c - @test clrinv(clr(c)) == c - @test ilrinv(ilr(c)) == c - end - - # convenience methods for heap-allocated vectors - @test alrinv([1, 2, 3]) isa Composition{4} - @test clrinv([1, 2, 3]) isa Composition{3} - @test ilrinv([1, 2, 3]) isa Composition{4} - - # TableTransform.jl API - t = (a=[1.0, 0.0, 1.0], b=[2.0, 2.0, 2.0], c=[3.0, 3.0, 0.0]) - n, c = apply(ALR(), t) - talr = revert(ALR(), n, c) - n, c = apply(CLR(), t) - tclr = revert(CLR(), n, c) - n, c = apply(ILR(), t) - tilr = revert(ILR(), n, c) - @test Tables.matrix(talr) ā‰ˆ Tables.matrix(tclr) - @test Tables.matrix(tclr) ā‰ˆ Tables.matrix(tilr) - @test Tables.matrix(talr) ā‰ˆ Tables.matrix(tilr) - - n, c = apply(ALR(:b), t) - talr = revert(ALR(:b), n, c) - @test n |> Tables.columnnames |> collect == [:a, :c] - @test talr |> Tables.columnnames |> collect == [:a, :b, :c] - - n, c = apply(ILR(:b), t) - tilr = revert(ILR(:b), n, c) - @test n |> Tables.columnnames |> collect == [:a, :c] - @test tilr |> Tables.columnnames |> collect == [:a, :b, :c] - - # Tests for Closure - t = (a=[2.0, 66.0, 0.0], b=[4.0, 22.0, 2.0], c=[4.0, 12.0, 98.0]) - n, c = apply(Closure(), t) - tcls = revert(Closure(), n, c) - @test Tables.matrix(n) ā‰ˆ [0.2 0.4 0.4; 0.66 0.22 0.12; 0.00 0.02 0.98] - @test Tables.matrix(tcls) ā‰ˆ Tables.matrix(t) - - # Tests for Remainder - t = (a=[2.0, 66.0, 0.0], b=[4.0, 22.0, 2.0], c=[4.0, 12.0, 98.0]) - n, c = apply(Remainder(), t) - total = first(c) - trem = revert(Remainder(), n, c) - Xt = Tables.matrix(t) - Xn = Tables.matrix(n) - @test Xn[:, 1:(end - 1)] == Xt - @test all(x -> 0 ā‰¤ x ā‰¤ total, Xn[:, end]) - @test n |> Tables.columnnames |> collect == [:a, :b, :c, :remainder] - @test trem |> Tables.columnnames |> collect == [:a, :b, :c] - - t = (a=[1.0, 10.0, 0.0], b=[1.0, 5.0, 0.0], c=[4.0, 2.0, 1.0]) - n = reapply(Remainder(), t, c) - Xn = Tables.matrix(n) - @test all(x -> 0 ā‰¤ x ā‰¤ total, Xn[:, end]) - - t = (a=[1.0, 10.0, 0.0], b=[1.0, 5.0, 0.0], remainder=[4.0, 2.0, 1.0]) - names = t |> Remainder() |> Tables.columnnames |> collect - @test names == [:a, :b, :remainder, :remainder_] - - t = (a=[1.0, 10.0, 0.0], b=[1.0, 5.0, 0.0], remainder=[4.0, 2.0, 1.0]) - n1, c1 = apply(Remainder(), t) - n2 = reapply(Remainder(), t, c1) - @test n1 == n2 -end