diff --git a/src/transforms/utils.jl b/src/transforms/utils.jl index 48092b8b..e3e579c9 100644 --- a/src/transforms/utils.jl +++ b/src/transforms/utils.jl @@ -2,9 +2,9 @@ # Licensed under the MIT License. See LICENSE in the project root. # ------------------------------------------------------------------ -zscore(x, μ, σ) = @. (x - μ) / σ +zscore(x, μ, σ) = iszero(σ) ? fill(zero(μ), length(x)) : @. (x - μ) / σ -revzscore(y, μ, σ) = @. σ * y + μ +revzscore(y, μ, σ) = iszero(σ) ? fill(μ, length(y)) : @. σ * y + μ _assert(cond, msg) = cond || throw(AssertionError(msg)) diff --git a/src/transforms/zscore.jl b/src/transforms/zscore.jl index a86aef08..51a9a041 100644 --- a/src/transforms/zscore.jl +++ b/src/transforms/zscore.jl @@ -41,8 +41,8 @@ assertions(transform::ZScore) = [scitypeassert(Continuous, transform.selector)] isrevertible(::Type{<:ZScore}) = true function colcache(::ZScore, x) - μ = mean(x) - σ = std(x, mean=μ) + μ = mean(skipmissing(x)) + σ = std(skipmissing(x), mean=μ) (μ=μ, σ=σ) end diff --git a/test/data/eigenanalysis-2.png b/test/data/eigenanalysis-2.png index c64e06b9..edf44e9c 100644 Binary files a/test/data/eigenanalysis-2.png and b/test/data/eigenanalysis-2.png differ diff --git a/test/transforms/zscore.jl b/test/transforms/zscore.jl index 9ba249a6..d87d13e6 100644 --- a/test/transforms/zscore.jl +++ b/test/transforms/zscore.jl @@ -87,4 +87,24 @@ @test isapprox(std(n.b), 1; atol=1e-6) tₒ = revert(T, n, c) @test Tables.matrix(t) ≈ Tables.matrix(tₒ) + + # missing values + a = [rand(Normal(7, 10), 99); missing] + t = Table(; a) + T = ZScore() + n, c = apply(T, t) + @test isapprox(mean(skipmissing(n.a)), 0; atol=1e-6) + @test isapprox(std(skipmissing(n.a)), 1; atol=1e-6) + tₒ = revert(T, n, c) + @test t.a[begin:(end - 1)] ≈ tₒ.a[begin:(end - 1)] + @test ismissing(tₒ.a[end]) + + # constant values + a = fill(2.0, 100) + t = Table(; a) + T = ZScore() + n, c = apply(T, t) + @test all(==(0), n.a) + tₒ = revert(T, n, c) + @test all(==(2), tₒ.a) end