From ac932d57a44fa66bb8dac09953ccdbe38c8d595d Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Fri, 26 Aug 2022 22:23:09 +0200 Subject: [PATCH 01/15] Copy `mean`, `std` and `var` from Statistics This copies the code for these three methods from the Statistics stdlib module. Only changes are: - add compatibility note to docstrings - remove references to `Statistics` - change tests to use the `mean` keyword argument instead of `stdm`/`varm` - do not test sparse matrices as they are not available in Base --- base/Base.jl | 2 + base/exports.jl | 6 + base/statistics.jl | 438 +++++++++++++++++++++++++++++++++++++ doc/make.jl | 1 + doc/src/base/statistics.md | 8 + test/choosetests.jl | 1 + test/statistics.jl | 266 ++++++++++++++++++++++ 7 files changed, 722 insertions(+) create mode 100644 base/statistics.jl create mode 100644 doc/src/base/statistics.md create mode 100644 test/statistics.jl diff --git a/base/Base.jl b/base/Base.jl index 5c84cd8b063a7..9e8bb64dfda5a 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -410,6 +410,8 @@ include("util.jl") include("asyncmap.jl") +include("statistics.jl") + # deprecated functions include("deprecated.jl") diff --git a/base/exports.jl b/base/exports.jl index f64c3b2913260..33f3feb5b8896 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -982,6 +982,12 @@ export rand, randn, +# statistics + mean, + mean!, + std, + var, + # Macros # parser internal @__FILE__, diff --git a/base/statistics.jl b/base/statistics.jl new file mode 100644 index 0000000000000..72d7aabf336d9 --- /dev/null +++ b/base/statistics.jl @@ -0,0 +1,438 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +##### mean ##### + +""" + mean(itr) + +Compute the mean of all elements in a collection. + +!!! note + If `itr` contains `NaN` or [`missing`](@ref) values, the result is also + `NaN` or `missing` (`missing` takes precedence if array contains both). + Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the + mean of non-missing values. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> mean(1:20) +10.5 + +julia> mean([1, missing, 3]) +missing + +julia> mean(skipmissing([1, missing, 3])) +2.0 +``` +""" +mean(itr) = mean(identity, itr) + +""" + mean(f, itr) + +Apply the function `f` to each element of collection `itr` and take the mean. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> mean(√, [1, 2, 3]) +1.3820881233139908 + +julia> mean([√1, √2, √3]) +1.3820881233139908 +``` +""" +function mean(f, itr) + y = iterate(itr) + if y === nothing + return Base.mapreduce_empty_iter(f, +, itr, + Base.IteratorEltype(itr)) / 0 + end + count = 1 + value, state = y + f_value = f(value)/1 + total = Base.reduce_first(+, f_value) + y = iterate(itr, state) + while y !== nothing + value, state = y + total += _mean_promote(total, f(value)) + count += 1 + y = iterate(itr, state) + end + return total/count +end + +""" + mean(f, A::AbstractArray; dims) + +Apply the function `f` to each element of array `A` and take the mean over dimensions `dims`. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +```jldoctest +julia> mean(√, [1, 2, 3]) +1.3820881233139908 + +julia> mean([√1, √2, √3]) +1.3820881233139908 + +julia> mean(√, [1 2 3; 4 5 6], dims=2) +2×1 Matrix{Float64}: + 1.3820881233139908 + 2.2285192400943226 +``` +""" +mean(f, A::AbstractArray; dims=:) = _mean(f, A, dims) + +""" + mean!(r, v) + +Compute the mean of `v` over the singleton dimensions of `r`, and write results to `r`. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> v = [1 2; 3 4] +2×2 Matrix{Int64}: + 1 2 + 3 4 + +julia> mean!([1., 1.], v) +2-element Vector{Float64}: + 1.5 + 3.5 + +julia> mean!([1. 1.], v) +1×2 Matrix{Float64}: + 2.0 3.0 +``` +""" +function mean!(R::AbstractArray, A::AbstractArray) + sum!(R, A; init=true) + x = max(1, length(R)) // length(A) + R .= R .* x + return R +end + +""" + mean(A::AbstractArray; dims) + +Compute the mean of an array over the given dimensions. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> A = [1 2; 3 4] +2×2 Matrix{Int64}: + 1 2 + 3 4 + +julia> mean(A, dims=1) +1×2 Matrix{Float64}: + 2.0 3.0 + +julia> mean(A, dims=2) +2×1 Matrix{Float64}: + 1.5 + 3.5 +``` +""" +mean(A::AbstractArray; dims=:) = _mean(identity, A, dims) + +_mean_promote(x::T, y::S) where {T,S} = convert(promote_type(T, S), y) + +# ::Dims is there to force specializing on Colon (as it is a Function) +function _mean(f, A::AbstractArray, dims::Dims=:) where Dims + isempty(A) && return sum(f, A, dims=dims)/0 + if dims === (:) + n = length(A) + else + n = mapreduce(i -> size(A, i), *, unique(dims); init=1) + end + x1 = f(first(A)) / 1 + result = sum(x -> _mean_promote(x1, f(x)), A, dims=dims) + if dims === (:) + return result / n + else + return result ./= n + end +end + +function mean(r::AbstractRange{<:Real}) + isempty(r) && return oftype((first(r) + last(r)) / 2, NaN) + (first(r) + last(r)) / 2 +end + + +##### variances ##### + +# faster computation of real(conj(x)*y) +realXcY(x::Real, y::Real) = x*y +realXcY(x::Complex, y::Complex) = real(x)*real(y) + imag(x)*imag(y) + +var(iterable; corrected::Bool=true, mean=nothing) = _var(iterable, corrected, mean) + +function _var(iterable, corrected::Bool, mean) + y = iterate(iterable) + if y === nothing + T = eltype(iterable) + return oftype((abs2(zero(T)) + abs2(zero(T)))/2, NaN) + end + count = 1 + value, state = y + y = iterate(iterable, state) + if mean === nothing + # Use Welford algorithm as seen in (among other places) + # Knuth's TAOCP, Vol 2, page 232, 3rd edition. + M = value / 1 + S = real(zero(M)) + while y !== nothing + value, state = y + y = iterate(iterable, state) + count += 1 + new_M = M + (value - M) / count + S = S + realXcY(value - M, value - new_M) + M = new_M + end + return S / (count - Int(corrected)) + elseif isa(mean, Number) # mean provided + # Cannot use a compensated version, e.g. the one from + # "Updating Formulae and a Pairwise Algorithm for Computing Sample Variances." + # by Chan, Golub, and LeVeque, Technical Report STAN-CS-79-773, + # Department of Computer Science, Stanford University, + # because user can provide mean value that is different to mean(iterable) + sum2 = abs2(value - mean::Number) + while y !== nothing + value, state = y + y = iterate(iterable, state) + count += 1 + sum2 += abs2(value - mean) + end + return sum2 / (count - Int(corrected)) + else + throw(ArgumentError("invalid value of mean, $(mean)::$(typeof(mean))")) + end +end + +centralizedabs2fun(m) = x -> abs2.(x - m) +centralize_sumabs2(A::AbstractArray, m) = + mapreduce(centralizedabs2fun(m), +, A) +centralize_sumabs2(A::AbstractArray, m, ifirst::Int, ilast::Int) = + Base.mapreduce_impl(centralizedabs2fun(m), +, A, ifirst, ilast) + +function centralize_sumabs2!(R::AbstractArray{S}, A::AbstractArray, means::AbstractArray) where S + # following the implementation of _mapreducedim! at base/reducedim.jl + lsiz = Base.check_reducedims(R,A) + for i in 1:max(ndims(R), ndims(means)) + if axes(means, i) != axes(R, i) + throw(DimensionMismatch("dimension $i of `mean` should have indices $(axes(R, i)), but got $(axes(means, i))")) + end + end + isempty(R) || fill!(R, zero(S)) + isempty(A) && return R + + if Base.has_fast_linear_indexing(A) && lsiz > 16 && !Base.has_offset_axes(R, means) + nslices = div(length(A), lsiz) + ibase = first(LinearIndices(A))-1 + for i = 1:nslices + @inbounds R[i] = centralize_sumabs2(A, means[i], ibase+1, ibase+lsiz) + ibase += lsiz + end + return R + end + indsAt, indsRt = Base.safe_tail(axes(A)), Base.safe_tail(axes(R)) # handle d=1 manually + keep, Idefault = Broadcast.shapeindexer(indsRt) + if Base.reducedim1(R, A) + i1 = first(Base.axes1(R)) + @inbounds for IA in CartesianIndices(indsAt) + IR = Broadcast.newindex(IA, keep, Idefault) + r = R[i1,IR] + m = means[i1,IR] + @simd for i in axes(A, 1) + r += abs2(A[i,IA] - m) + end + R[i1,IR] = r + end + else + @inbounds for IA in CartesianIndices(indsAt) + IR = Broadcast.newindex(IA, keep, Idefault) + @simd for i in axes(A, 1) + R[i,IR] += abs2(A[i,IA] - means[i,IR]) + end + end + end + return R +end + +function varm!(R::AbstractArray{S}, A::AbstractArray, m::AbstractArray; corrected::Bool=true) where S + if isempty(A) + fill!(R, convert(S, NaN)) + else + rn = div(length(A), length(R)) - Int(corrected) + centralize_sumabs2!(R, A, m) + R .= R .* (1 // rn) + end + return R +end + +varm(A::AbstractArray, m::AbstractArray; corrected::Bool=true, dims=:) = _varm(A, m, corrected, dims) + +_varm(A::AbstractArray{T}, m, corrected::Bool, region) where {T} = + varm!(Base.reducedim_init(t -> abs2(t)/2, +, A, region), A, m; corrected=corrected) + +varm(A::AbstractArray, m; corrected::Bool=true) = _varm(A, m, corrected, :) + +function _varm(A::AbstractArray{T}, m, corrected::Bool, ::Colon) where T + n = length(A) + n == 0 && return oftype((abs2(zero(T)) + abs2(zero(T)))/2, NaN) + return centralize_sumabs2(A, m) / (n - Int(corrected)) +end + + +""" + var(itr; corrected::Bool=true, mean=nothing[, dims]) + +Compute the sample variance of collection `itr`. + +The algorithm returns an estimator of the generative distribution's variance +under the assumption that each entry of `itr` is a sample drawn from the same +unknown distribution, with the samples uncorrelated. +For arrays, this computation is equivalent to calculating +`sum((itr .- mean(itr)).^2) / (length(itr) - 1)`. +If `corrected` is `true`, then the sum is scaled with `n-1`, +whereas the sum is scaled with `n` if `corrected` is +`false` where `n` is the number of elements in `itr`. + +If `itr` is an `AbstractArray`, `dims` can be provided to compute the variance +over dimensions. + +A pre-computed `mean` may be provided. When `dims` is specified, `mean` must be +an array with the same shape as `mean(itr, dims=dims)` (additional trailing +singleton dimensions are allowed). + +!!! note + If array contains `NaN` or [`missing`](@ref) values, the result is also + `NaN` or `missing` (`missing` takes precedence if array contains both). + Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the + variance of non-missing values. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. +""" +var(A::AbstractArray; corrected::Bool=true, mean=nothing, dims=:) = _var(A, corrected, mean, dims) + +function _var(A::AbstractArray, corrected::Bool, m, dims) + if m === nothing + m = mean(A, dims=dims) + end + return varm(A, m; corrected=corrected, dims=dims) +end + +function _var(A::AbstractArray, corrected::Bool, m, ::Colon) + if m === nothing + m = mean(A) + end + return real(varm(A, m; corrected=corrected)) +end + +varm(iterable, m; corrected::Bool=true) = _var(iterable, corrected, m) + +## variances over ranges + +varm(v::AbstractRange, m::AbstractArray) = range_varm(v, m) +varm(v::AbstractRange, m) = range_varm(v, m) + +function range_varm(v::AbstractRange, m) + f = first(v) - m + s = step(v) + l = length(v) + vv = f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 + if l == 0 || l == 1 + return typeof(vv)(NaN) + end + return vv +end + +function var(v::AbstractRange) + s = step(v) + l = length(v) + vv = abs2(s) * (l + 1) * l / 12 + if l == 0 || l == 1 + return typeof(vv)(NaN) + end + return vv +end + + +##### standard deviation ##### + +function sqrt!(A::AbstractArray) + for i in eachindex(A) + @inbounds A[i] = sqrt(A[i]) + end + A +end + +""" + std(itr; corrected::Bool=true, mean=nothing[, dims]) + +Compute the sample standard deviation of collection `itr`. + +The algorithm returns an estimator of the generative distribution's standard +deviation under the assumption that each entry of `itr` is a sample drawn from +the same unknown distribution, with the samples uncorrelated. +For arrays, this computation is equivalent to calculating +`sqrt(sum((itr .- mean(itr)).^2) / (length(itr) - 1))`. +If `corrected` is `true`, then the sum is scaled with `n-1`, +whereas the sum is scaled with `n` if `corrected` is +`false` with `n` the number of elements in `itr`. + +If `itr` is an `AbstractArray`, `dims` can be provided to compute the standard deviation +over dimensions, and `means` may contain means for each dimension of `itr`. + +A pre-computed `mean` may be provided. When `dims` is specified, `mean` must be +an array with the same shape as `mean(itr, dims=dims)` (additional trailing +singleton dimensions are allowed). + +!!! note + If array contains `NaN` or [`missing`](@ref) values, the result is also + `NaN` or `missing` (`missing` takes precedence if array contains both). + Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the + standard deviation of non-missing values. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. +""" +std(A::AbstractArray; corrected::Bool=true, mean=nothing, dims=:) = _std(A, corrected, mean, dims) + +_std(A::AbstractArray, corrected::Bool, mean, dims) = + sqrt.(var(A; corrected=corrected, mean=mean, dims=dims)) + +_std(A::AbstractArray, corrected::Bool, mean, ::Colon) = + sqrt.(var(A; corrected=corrected, mean=mean)) + +_std(A::AbstractArray{<:AbstractFloat}, corrected::Bool, mean, dims) = + sqrt!(var(A; corrected=corrected, mean=mean, dims=dims)) + +_std(A::AbstractArray{<:AbstractFloat}, corrected::Bool, mean, ::Colon) = + sqrt.(var(A; corrected=corrected, mean=mean)) + +std(iterable; corrected::Bool=true, mean=nothing) = + sqrt(var(iterable, corrected=corrected, mean=mean)) diff --git a/doc/make.jl b/doc/make.jl index 5f5986497c922..8f9660ea77803 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -122,6 +122,7 @@ BaseDocs = [ "base/libc.md", "base/stacktraces.md", "base/simd-types.md", + "base/statistics.md" ] StdlibDocs = [stdlib.targetfile for stdlib in STDLIB_DOCS] diff --git a/doc/src/base/statistics.md b/doc/src/base/statistics.md new file mode 100644 index 0000000000000..f17c80100f807 --- /dev/null +++ b/doc/src/base/statistics.md @@ -0,0 +1,8 @@ +# Statistics + +```@docs +Base.mean +Base.mean! +Base.std +Base.var +``` \ No newline at end of file diff --git a/test/choosetests.jl b/test/choosetests.jl index f5775bbc00911..2b8d9f00e5a45 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -29,6 +29,7 @@ const TESTNAMES = [ "channels", "iostream", "secretbuffer", "specificity", "reinterpretarray", "syntax", "corelogging", "missing", "asyncmap", "smallarrayshrink", "opaque_closure", "filesystem", "download", + "statistics" ] """ diff --git a/test/statistics.jl b/test/statistics.jl new file mode 100644 index 0000000000000..bfd9246c4bc94 --- /dev/null +++ b/test/statistics.jl @@ -0,0 +1,266 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +@testset "mean" begin + @test mean((1,2,3)) === 2. + @test mean([0]) === 0. + @test mean([1.]) === 1. + @test mean([1.,3]) == 2. + @test mean([1,2,3]) == 2. + @test mean([0 1 2; 4 5 6], dims=1) == [2. 3. 4.] + @test mean([1 2 3; 4 5 6], dims=1) == [2.5 3.5 4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=1) == [-2.5 -3.5 -4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=2) == transpose([-2.0 -5.0]) + @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 2)) == -3.5 .* ones(1, 1) + @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 1)) == [-2.5 -3.5 -4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=()) == Float64[-1 -2 -3 ; -4 -5 -6] + @test mean(i->i+1, 0:2) === 2. + @test mean(isodd, [3]) === 1. + @test mean(x->3x, (1,1)) === 3. + + # mean of iterables: + n = 10; a = randn(n); b = randn(n) + @test mean(Tuple(a)) ≈ mean(a) + @test mean(Tuple(a + b*im)) ≈ mean(a + b*im) + @test mean(cos, Tuple(a)) ≈ mean(cos, a) + @test mean(x->x/2, a + b*im) ≈ mean(a + b*im) / 2. + @test ismissing(mean(Tuple((1, 2, missing, 4, 5)))) + + @test isnan(mean([NaN])) + @test isnan(mean([0.0,NaN])) + @test isnan(mean([NaN,0.0])) + + @test isnan(mean([0.,Inf,-Inf])) + @test isnan(mean([1.,-1.,Inf,-Inf])) + @test isnan(mean([-Inf,Inf])) + @test isequal(mean([NaN 0.0; 1.2 4.5], dims=2), reshape([NaN; 2.85], 2, 1)) + + @test ismissing(mean([1, missing])) + @test ismissing(mean([NaN, missing])) + @test ismissing(mean([missing, NaN])) + @test isequal(mean([missing 1.0; 2.0 3.0], dims=1), [missing 2.0]) + @test mean(skipmissing([1, missing, 2])) === 1.5 + @test isequal(mean(Complex{Float64}[]), NaN+NaN*im) + @test mean(Complex{Float64}[]) isa Complex{Float64} + @test isequal(mean(skipmissing(Complex{Float64}[])), NaN+NaN*im) + @test mean(skipmissing(Complex{Float64}[])) isa Complex{Float64} + @test isequal(mean(abs, Complex{Float64}[]), NaN) + @test mean(abs, Complex{Float64}[]) isa Float64 + @test isequal(mean(abs, skipmissing(Complex{Float64}[])), NaN) + @test mean(abs, skipmissing(Complex{Float64}[])) isa Float64 + @test isequal(mean(Int[]), NaN) + @test mean(Int[]) isa Float64 + @test isequal(mean(skipmissing(Int[])), NaN) + @test mean(skipmissing(Int[])) isa Float64 + @test_throws MethodError mean([]) + @test_throws MethodError mean(skipmissing([])) + @test_throws ArgumentError mean((1 for i in 2:1)) + if VERSION >= v"1.6.0-DEV.83" + @test_throws ArgumentError mean(()) + @test_throws ArgumentError mean(Union{}[]) + end + + # Check that small types are accumulated using wider type + for T in (Int8, UInt8) + x = [typemax(T) typemax(T)] + g = (v for v in x) + @test mean(x) == mean(g) == typemax(T) + @test mean(identity, x) == mean(identity, g) == typemax(T) + @test mean(x, dims=2) == [typemax(T)]' + end + # Check that mean avoids integer overflow (#22) + let x = fill(typemax(Int), 10), a = tuple(x...) + @test (mean(x) == mean(x, dims=1)[] == mean(float, x) + == mean(a) == mean(v for v in x) == mean(v for v in a) + ≈ float(typemax(Int))) + end + let x = rand(10000) # mean should use sum's accurate pairwise algorithm + @test mean(x) == sum(x) / length(x) + end + @test mean(Number[1, 1.5, 2+3im]) === 1.5+1im # mixed-type array + @test mean(v for v in Number[1, 1.5, 2+3im]) === 1.5+1im + @test isnan(@inferred mean(Int[])) + @test isnan(@inferred mean(Float32[])) + @test isnan(@inferred mean(Float64[])) + @test isnan(@inferred mean(Iterators.filter(x -> true, Int[]))) + @test isnan(@inferred mean(Iterators.filter(x -> true, Float32[]))) + @test isnan(@inferred mean(Iterators.filter(x -> true, Float64[]))) +end + +@testset "mean for ranges" begin + for n = 2:5 + @test mean(2:n) == mean([2:n;]) + @test mean(2:0.1:n) ≈ mean([2:0.1:n;]) + end + @test mean(2:1) === NaN + @test mean(big(2):1) isa BigFloat +end + +@testset "var & std" begin + # edge case: empty vector + # iterable; this has to throw for type stability + @test_throws MethodError var(()) + @test_throws MethodError var((); corrected=false) + @test_throws MethodError var((); mean=2) + @test_throws MethodError var((); mean=2, corrected=false) + # reduction + @test isnan(var(Int[])) + @test isnan(var(Int[]; corrected=false)) + @test isnan(var(Int[]; mean=2)) + @test isnan(var(Int[]; mean=2, corrected=false)) + # reduction across dimensions + @test isequal(var(Int[], dims=1), [NaN]) + @test isequal(var(Int[], dims=1; corrected=false), [NaN]) + @test isequal(var(Int[], dims=1; mean=[2]), [NaN]) + @test isequal(var(Int[], dims=1; mean=[2], corrected=false), [NaN]) + + # edge case: one-element vector + # iterable + @test isnan(@inferred(var((1,)))) + @test var((1,); corrected=false) === 0.0 + @test var((1,); mean=2) === Inf + @test var((1,); mean=2, corrected=false) === 1.0 + # reduction + @test isnan(@inferred(var([1]))) + @test var([1]; corrected=false) === 0.0 + @test var([1]; mean=2) === Inf + @test var([1]; mean=2, corrected=false) === 1.0 + # reduction across dimensions + @test isequal(@inferred(var([1], dims=1)), [NaN]) + @test var([1], dims=1; corrected=false) ≈ [0.0] + @test var([1], dims=1; mean=[2]) ≈ [Inf] + @test var([1], dims=1; mean=[2], corrected=false) ≈ [1.0] + + @test var(1:8) == 6. + @test var(1:8, mean=1) == var(Vector(1:8), mean=1) + @test isnan(var(1:1, mean=1)) + @test isnan(var(1:1)) + @test isnan(var(1:-1)) + + @test @inferred(var(1.0:8.0)) == 6. + @test var(1.0:8.0, mean=1.0) == var(Vector(1.0:8.0), mean=1) + @test isnan(var(1.0:1.0, mean=1.0)) + @test isnan(var(1.0:1.0)) + @test isnan(var(1.0:-1.0)) + + @test @inferred(var(1.0f0:8.0f0)) === 6.f0 + @test var(1.0f0:8.0f0, mean=1.0f0) == var(Vector(1.0f0:8.0f0), mean=1) + @test isnan(var(1.0f0:1.0f0, mean=1.0f0)) + @test isnan(var(1.0f0:1.0f0)) + @test isnan(var(1.0f0:-1.0f0)) + + @test var([1,2,3], mean=2) ≈ 1. + @test var([1,2,3]) ≈ 1. + @test var([1,2,3]; corrected=false) ≈ 2.0/3 + @test var([1,2,3]; mean=0) ≈ 7. + @test var([1,2,3]; mean=0, corrected=false) ≈ 14.0/3 + + @test var((1,2,3), mean=2) ≈ 1. + @test var((1,2,3)) ≈ 1. + @test var((1,2,3); corrected=false) ≈ 2.0/3 + @test var((1,2,3); mean=0) ≈ 7. + @test var((1,2,3); mean=0, corrected=false) ≈ 14.0/3 + @test_throws ArgumentError var((1,2,3); mean=()) + + @test var([1 2 3 4 5; 6 7 8 9 10], dims=2) ≈ [2.5 2.5]' + @test var([1 2 3 4 5; 6 7 8 9 10], dims=2; corrected=false) ≈ [2.0 2.0]' + + @test var(collect(1:99), dims=1) ≈ [825] + @test var(Matrix(transpose(collect(1:99))), dims=2) ≈ [825] + + @test std([1,2,3], mean=2) ≈ 1. + @test std([1,2,3]) ≈ 1. + @test std([1,2,3]; corrected=false) ≈ sqrt(2.0/3) + @test std([1,2,3]; mean=0) ≈ sqrt(7.0) + @test std([1,2,3]; mean=0, corrected=false) ≈ sqrt(14.0/3) + + @test std([1.0,2,3], mean=2) ≈ 1. + @test std([1.0,2,3]) ≈ 1. + @test std([1.0,2,3]; corrected=false) ≈ sqrt(2.0/3) + @test std([1.0,2,3]; mean=0) ≈ sqrt(7.0) + @test std([1.0,2,3]; mean=0, corrected=false) ≈ sqrt(14.0/3) + + @test std([1.0,2,3], mean=[0]; dims=1, corrected=false)[] ≈ sqrt(14.0/3) + @test std([1.0,2,3]; dims=1)[] ≈ 1. + @test std([1.0,2,3]; dims=1, corrected=false)[] ≈ sqrt(2.0/3) + @test std([1.0,2,3]; dims=1, mean=[0])[] ≈ sqrt(7.0) + @test std([1.0,2,3]; dims=1, mean=[0], corrected=false)[] ≈ sqrt(14.0/3) + + @test std((1,2,3), mean=2) ≈ 1. + @test std((1,2,3)) ≈ 1. + @test std((1,2,3); corrected=false) ≈ sqrt(2.0/3) + @test std((1,2,3); mean=0) ≈ sqrt(7.0) + @test std((1,2,3); mean=0, corrected=false) ≈ sqrt(14.0/3) + + @test std([1 2 3 4 5; 6 7 8 9 10], mean=[3.0,8.0], dims=2) ≈ sqrt.([2.5 2.5]') + @test std([1 2 3 4 5; 6 7 8 9 10], mean=[3.0,8.0], dims=2; corrected=false) ≈ sqrt.([2.0 2.0]') + @test std([1 2 3 4 5; 6 7 8 9 10], dims=2) ≈ sqrt.([2.5 2.5]') + @test std([1 2 3 4 5; 6 7 8 9 10], dims=2; corrected=false) ≈ sqrt.([2.0 2.0]') + + let A = ComplexF64[exp(i*im) for i in 1:10^4] + @test var(A, mean=0.) ≈ sum(map(abs2, A)) / (length(A) - 1) + @test var(A, mean=mean(A)) ≈ var(A) + end + + @test var([1//1, 2//1]) isa Rational{Int} + @test var([1//1, 2//1], dims=1) isa Vector{Rational{Int}} + + @test std([1//1, 2//1]) isa Float64 + @test std([1//1, 2//1], dims=1) isa Vector{Float64} + + @testset "var: empty cases" begin + A = Matrix{Int}(undef, 0,1) + @test var(A) === NaN + + @test isequal(var(A, dims=1), fill(NaN, 1, 1)) + @test isequal(var(A, dims=2), fill(NaN, 0, 1)) + @test isequal(var(A, dims=(1, 2)), fill(NaN, 1, 1)) + @test isequal(var(A, dims=3), fill(NaN, 0, 1)) + end + + # issue #6672 + @test std(AbstractFloat[1,2,3], dims=1) == [1.0] + + for f in (var, std) + @test ismissing(f([1, missing])) + @test ismissing(f([NaN, missing])) + @test ismissing(f([missing, NaN])) + @test isequal(f([missing 1.0; 2.0 3.0], dims=1), [missing f([1.0, 3.0])]) + @test f(skipmissing([1, missing, 2])) === f([1, 2]) + + @test ismissing(f([1, missing], mean=0)) + @test ismissing(f([1, 2], mean=missing)) + @test ismissing(f([1, NaN], mean=missing)) + @test ismissing(f([NaN, missing], mean=0)) + @test ismissing(f([missing, NaN], mean=0)) + @test ismissing(f([NaN, missing], mean=missing)) + @test ismissing(f([missing, NaN], mean=missing)) + @test f(skipmissing([1, missing, 2]), mean=0) === f([1, 2], mean=0) + end + + @test isequal(var(Complex{Float64}[]), NaN) + @test var(Complex{Float64}[]) isa Float64 + @test isequal(var(skipmissing(Complex{Float64}[])), NaN) + @test var(skipmissing(Complex{Float64}[])) isa Float64 + @test_throws MethodError var([]) + @test_throws MethodError var(skipmissing([])) + @test_throws MethodError var((1 for i in 2:1)) + @test isequal(var(Int[]), NaN) + @test var(Int[]) isa Float64 + @test isequal(var(skipmissing(Int[])), NaN) + @test var(skipmissing(Int[])) isa Float64 + + # over dimensions with provided means + x = [1 2 3; 4 5 6] + @test var(x, dims=1, mean=mean(x, dims=1)) == var(x, dims=1) + @test var(x, dims=1, mean=reshape(mean(x, dims=1), 1, :, 1)) == var(x, dims=1) + @test var(x, dims=2, mean=mean(x, dims=2)) == var(x, dims=2) + @test var(x, dims=2, mean=reshape(mean(x, dims=2), :)) == var(x, dims=2) + @test var(x, dims=2, mean=reshape(mean(x, dims=2), :, 1, 1)) == var(x, dims=2) + @test_throws DimensionMismatch var(x, dims=1, mean=ones(size(x, 1))) + @test_throws DimensionMismatch var(x, dims=1, mean=ones(size(x, 1), 1)) + @test_throws DimensionMismatch var(x, dims=2, mean=ones(1, size(x, 2))) + @test_throws DimensionMismatch var(x, dims=1, mean=ones(1, 1, size(x, 2))) + @test_throws DimensionMismatch var(x, dims=2, mean=ones(1, size(x, 2), 1)) + @test_throws DimensionMismatch var(x, dims=2, mean=ones(size(x, 1), 1, 5)) + @test_throws DimensionMismatch var(x, dims=1, mean=ones(1, size(x, 2), 5)) +end \ No newline at end of file From a6418801880d827de67fabacfce73e167a258c61 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Fri, 26 Aug 2022 22:48:35 +0200 Subject: [PATCH 02/15] Remove Statistics stdlib --- NEWS.md | 2 ++ doc/src/manual/modules.md | 2 +- julia.spdx.json | 17 ----------------- stdlib/Makefile | 2 +- stdlib/Statistics.version | 4 ---- 5 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 stdlib/Statistics.version diff --git a/NEWS.md b/NEWS.md index 25efd0eb665ee..360ec031dcf88 100644 --- a/NEWS.md +++ b/NEWS.md @@ -140,6 +140,8 @@ Standard library changes #### Statistics +* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean`, `mean!`, `std` and `var` are now exported directly by Base. + #### Sockets #### Tar diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index c6009594bea2d..468a02551561f 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -143,7 +143,7 @@ As we will see in the next section `import .NiceStuff` is equivalent to `using . You can combine multiple `using` and `import` statements of the same kind in a comma-separated expression, e.g. ```jldoctest module_manual -julia> using LinearAlgebra, Statistics +julia> using LinearAlgebra, Random ``` ### `using` and `import` with specific identifiers, and adding methods diff --git a/julia.spdx.json b/julia.spdx.json index 9c1911958096e..ee93d9944d5a3 100644 --- a/julia.spdx.json +++ b/julia.spdx.json @@ -38,18 +38,6 @@ "copyrightText": "Copyright (c) 2017-2021: Stefan Karpinski, Kristoffer Carlsson, Fredrik Ekre, David Varela, Ian Butterworth, and contributors: https://github.com/JuliaLang/Pkg.jl/graphs/contributors", "summary": "Julia's package manager, shipped with Julia v1.0 and above" }, - { - "name": "Statistics.jl", - "SPDXID": "SPDXRef-JuliaStatistics", - "downloadLocation": "git+https://github.com/JuliaStats/Statistics.jl.git", - "filesAnalyzed": false, - "homepage": "https://juliastats.org", - "sourceInfo": "The git hash of the version in use can be found in the file stdlib/Statistics.version", - "licenseConcluded": "MIT", - "licenseDeclared": "MIT", - "copyrightText": "Copyright (c) 2012-2016: Jeff Bezanson, Stefan Karpinski, Viral B. Shah, Dahua Lin, Simon Byrne, Andreas Noack, Douglas Bates, John Myles White, Simon Kornblith, and other contributors.", - "summary": "Development repository for the Statistics standard library (stdlib) that ships with Julia." - }, { "name": "libCURL.jl", "SPDXID": "SPDXRef-JuliaCurl", @@ -446,11 +434,6 @@ "relationshipType": "BUILD_DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-JuliaMain" }, - { - "spdxElementId": "SPDXRef-JuliaStatistics", - "relationshipType": "BUILD_DEPENDENCY_OF", - "relatedSpdxElement": "SPDXRef-JuliaMain" - }, { "spdxElementId": "SPDXRef-JuliaCurl", "relationshipType": "BUILD_DEPENDENCY_OF", diff --git a/stdlib/Makefile b/stdlib/Makefile index d45be468626cd..1128f5dd9f363 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -47,7 +47,7 @@ STDLIBS = Artifacts Base64 CRC32c Dates Distributed FileWatching \ SharedArrays Sockets SparseArrays SuiteSparse Test TOML Unicode UUIDs \ $(JLL_NAMES) -STDLIBS_EXT = Pkg Statistics LibCURL Downloads ArgTools Tar NetworkOptions SuiteSparse SparseArrays SHA +STDLIBS_EXT = Pkg LibCURL Downloads ArgTools Tar NetworkOptions SuiteSparse SparseArrays SHA $(foreach module, $(STDLIBS_EXT), $(eval $(call stdlib-external,$(module),$(shell echo $(module) | tr a-z A-Z)))) diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version deleted file mode 100644 index a9830fcd8759b..0000000000000 --- a/stdlib/Statistics.version +++ /dev/null @@ -1,4 +0,0 @@ -STATISTICS_BRANCH = master -STATISTICS_SHA1 = 0588f2cf9e43f9f72af5802feaf0af4b652c3257 -STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git -STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 From 4bcde3476d11fa32518e6ecf034f50fd880bf6c7 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Sat, 27 Aug 2022 20:45:36 +0200 Subject: [PATCH 03/15] Fixes --- NEWS.md | 2 +- doc/make.jl | 2 +- doc/src/base/statistics.md | 2 +- stdlib/Random/Project.toml | 3 +-- test/statistics.jl | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 3b63be124f516..778981a331097 100644 --- a/NEWS.md +++ b/NEWS.md @@ -142,7 +142,7 @@ Standard library changes #### Statistics -* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean`, `mean!`, `std` and `var` are now exported directly by Base. +* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean`, `mean!`, `std` and `var` are now exported directly by Base. ([#46501]) #### Sockets diff --git a/doc/make.jl b/doc/make.jl index b2e2cb20bc508..f455d7fc221ff 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -122,7 +122,7 @@ BaseDocs = [ "base/libc.md", "base/stacktraces.md", "base/simd-types.md", - "base/statistics.md" + "base/statistics.md", ] StdlibDocs = [stdlib.targetfile for stdlib in STDLIB_DOCS] diff --git a/doc/src/base/statistics.md b/doc/src/base/statistics.md index f17c80100f807..909d10cfcb445 100644 --- a/doc/src/base/statistics.md +++ b/doc/src/base/statistics.md @@ -5,4 +5,4 @@ Base.mean Base.mean! Base.std Base.var -``` \ No newline at end of file +``` diff --git a/stdlib/Random/Project.toml b/stdlib/Random/Project.toml index 199dcab940c86..51915c2e6e388 100644 --- a/stdlib/Random/Project.toml +++ b/stdlib/Random/Project.toml @@ -10,7 +10,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" -Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [targets] -test = ["Test", "SparseArrays", "LinearAlgebra", "Future", "Statistics"] +test = ["Test", "SparseArrays", "LinearAlgebra", "Future"] diff --git a/test/statistics.jl b/test/statistics.jl index bfd9246c4bc94..22c73ffd782b6 100644 --- a/test/statistics.jl +++ b/test/statistics.jl @@ -263,4 +263,4 @@ end @test_throws DimensionMismatch var(x, dims=2, mean=ones(1, size(x, 2), 1)) @test_throws DimensionMismatch var(x, dims=2, mean=ones(size(x, 1), 1, 5)) @test_throws DimensionMismatch var(x, dims=1, mean=ones(1, size(x, 2), 5)) -end \ No newline at end of file +end From 7f267ba691ee594e4cf71575276281de92dd3a47 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Sat, 24 Sep 2022 18:56:44 +0200 Subject: [PATCH 04/15] Drop `std` and `var`, add tests for `mean!` --- NEWS.md | 2 +- base/Base.jl | 2 - base/exports.jl | 8 +- base/reduce.jl | 71 ++++++ base/reducedim.jl | 107 +++++++++ base/statistics.jl | 438 ------------------------------------ doc/make.jl | 1 - doc/src/base/collections.md | 2 + doc/src/base/statistics.md | 8 - test/choosetests.jl | 1 - test/reduce.jl | 128 +++++++++++ test/statistics.jl | 266 ---------------------- 12 files changed, 311 insertions(+), 723 deletions(-) delete mode 100644 base/statistics.jl delete mode 100644 doc/src/base/statistics.md delete mode 100644 test/statistics.jl diff --git a/NEWS.md b/NEWS.md index 778981a331097..383f04d4db59b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -142,7 +142,7 @@ Standard library changes #### Statistics -* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean`, `mean!`, `std` and `var` are now exported directly by Base. ([#46501]) +* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean` and `mean!` are now exported directly by Base. ([#46501]) #### Sockets diff --git a/base/Base.jl b/base/Base.jl index 97faff372705f..63728fdba3e4e 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -414,8 +414,6 @@ include("util.jl") include("asyncmap.jl") -include("statistics.jl") - # deprecated functions include("deprecated.jl") diff --git a/base/exports.jl b/base/exports.jl index 68a4762ab2d7c..973fb844ad379 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -412,6 +412,8 @@ export max, maximum!, maximum, + mean, + mean!, min, minimum!, minimum, @@ -983,12 +985,6 @@ export rand, randn, -# statistics - mean, - mean!, - std, - var, - # Macros # parser internal @__FILE__, diff --git a/base/reduce.jl b/base/reduce.jl index 64ea4293c9893..1c079cfd4eefa 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -612,6 +612,77 @@ julia> prod(1:5; init = 1.0) """ prod(a; kw...) = mapreduce(identity, mul_prod, a; kw...) +## mean + +_mean_promote(x::T, y::S) where {T,S} = convert(promote_type(T, S), y) + +""" + mean(itr) + +Compute the mean of all elements in a collection. + +!!! note + If `itr` contains `NaN` or [`missing`](@ref) values, the result is also + `NaN` or `missing` (`missing` takes precedence if array contains both). + Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the + mean of non-missing values. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> mean(1:20) +10.5 + +julia> mean([1, missing, 3]) +missing + +julia> mean(skipmissing([1, missing, 3])) +2.0 +``` +""" +mean(itr) = mean(identity, itr) + +""" + mean(f, itr) + +Apply the function `f` to each element of collection `itr` and take the mean. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> mean(√, [1, 2, 3]) +1.3820881233139908 + +julia> mean([√1, √2, √3]) +1.3820881233139908 +``` +""" +function mean(f, itr) + y = iterate(itr) + if y === nothing + return mapreduce_empty_iter(f, +, itr, + IteratorEltype(itr)) / 0 + end + count = 1 + value, state = y + f_value = f(value)/1 + total = reduce_first(+, f_value) + y = iterate(itr, state) + while y !== nothing + value, state = y + total += _mean_promote(total, f(value)) + count += 1 + y = iterate(itr, state) + end + return total/count +end + ## maximum, minimum, & extrema _fast(::typeof(min),x,y) = min(x,y) _fast(::typeof(max),x,y) = max(x,y) diff --git a/base/reducedim.jl b/base/reducedim.jl index dc34b4feb1f6a..3ca52fdb274bf 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -1280,3 +1280,110 @@ julia> argmax(A, dims=2) ``` """ argmax(A::AbstractArray; dims=:) = findmax(A; dims=dims)[2] + +""" + mean(f, A::AbstractArray; dims) + +Apply the function `f` to each element of array `A` and take the mean over dimensions `dims`. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +```jldoctest +julia> mean(√, [1, 2, 3]) +1.3820881233139908 + +julia> mean([√1, √2, √3]) +1.3820881233139908 + +julia> mean(√, [1 2 3; 4 5 6], dims=2) +2×1 Matrix{Float64}: + 1.3820881233139908 + 2.2285192400943226 +``` +""" +mean(f, A::AbstractArray; dims=:) = _mean(f, A, dims) + +""" + mean!(r, v) + +Compute the mean of `v` over the singleton dimensions of `r`, and write results to `r`. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> v = [1 2; 3 4] +2×2 Matrix{Int64}: + 1 2 + 3 4 + +julia> mean!([1., 1.], v) +2-element Vector{Float64}: + 1.5 + 3.5 + +julia> mean!([1. 1.], v) +1×2 Matrix{Float64}: + 2.0 3.0 +``` +""" +function mean!(R::AbstractArray, A::AbstractArray) + sum!(R, A; init=true) + x = max(1, length(R)) // length(A) + R .= R .* x + return R +end + +""" + mean(A::AbstractArray; dims) + +Compute the mean of an array over the given dimensions. + +!!! compat "Julia 1.9" + This method requires at least Julia 1.9. + Support for older releases is provided by the Statistics package. + +# Examples +```jldoctest +julia> A = [1 2; 3 4] +2×2 Matrix{Int64}: + 1 2 + 3 4 + +julia> mean(A, dims=1) +1×2 Matrix{Float64}: + 2.0 3.0 + +julia> mean(A, dims=2) +2×1 Matrix{Float64}: + 1.5 + 3.5 +``` +""" +mean(A::AbstractArray; dims=:) = _mean(identity, A, dims) + +# ::Dims is there to force specializing on Colon (as it is a Function) +function _mean(f, A::AbstractArray, dims::Dims=:) where Dims + isempty(A) && return sum(f, A, dims=dims)/0 + if dims === (:) + n = length(A) + else + n = mapreduce(i -> size(A, i), *, unique(dims); init=1) + end + x1 = f(first(A)) / 1 + result = sum(x -> _mean_promote(x1, f(x)), A, dims=dims) + if dims === (:) + return result / n + else + return result ./= n + end +end + +function mean(r::AbstractRange{<:Real}) + isempty(r) && return oftype((first(r) + last(r)) / 2, NaN) + (first(r) + last(r)) / 2 +end \ No newline at end of file diff --git a/base/statistics.jl b/base/statistics.jl deleted file mode 100644 index 72d7aabf336d9..0000000000000 --- a/base/statistics.jl +++ /dev/null @@ -1,438 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -##### mean ##### - -""" - mean(itr) - -Compute the mean of all elements in a collection. - -!!! note - If `itr` contains `NaN` or [`missing`](@ref) values, the result is also - `NaN` or `missing` (`missing` takes precedence if array contains both). - Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the - mean of non-missing values. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> mean(1:20) -10.5 - -julia> mean([1, missing, 3]) -missing - -julia> mean(skipmissing([1, missing, 3])) -2.0 -``` -""" -mean(itr) = mean(identity, itr) - -""" - mean(f, itr) - -Apply the function `f` to each element of collection `itr` and take the mean. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> mean(√, [1, 2, 3]) -1.3820881233139908 - -julia> mean([√1, √2, √3]) -1.3820881233139908 -``` -""" -function mean(f, itr) - y = iterate(itr) - if y === nothing - return Base.mapreduce_empty_iter(f, +, itr, - Base.IteratorEltype(itr)) / 0 - end - count = 1 - value, state = y - f_value = f(value)/1 - total = Base.reduce_first(+, f_value) - y = iterate(itr, state) - while y !== nothing - value, state = y - total += _mean_promote(total, f(value)) - count += 1 - y = iterate(itr, state) - end - return total/count -end - -""" - mean(f, A::AbstractArray; dims) - -Apply the function `f` to each element of array `A` and take the mean over dimensions `dims`. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -```jldoctest -julia> mean(√, [1, 2, 3]) -1.3820881233139908 - -julia> mean([√1, √2, √3]) -1.3820881233139908 - -julia> mean(√, [1 2 3; 4 5 6], dims=2) -2×1 Matrix{Float64}: - 1.3820881233139908 - 2.2285192400943226 -``` -""" -mean(f, A::AbstractArray; dims=:) = _mean(f, A, dims) - -""" - mean!(r, v) - -Compute the mean of `v` over the singleton dimensions of `r`, and write results to `r`. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> v = [1 2; 3 4] -2×2 Matrix{Int64}: - 1 2 - 3 4 - -julia> mean!([1., 1.], v) -2-element Vector{Float64}: - 1.5 - 3.5 - -julia> mean!([1. 1.], v) -1×2 Matrix{Float64}: - 2.0 3.0 -``` -""" -function mean!(R::AbstractArray, A::AbstractArray) - sum!(R, A; init=true) - x = max(1, length(R)) // length(A) - R .= R .* x - return R -end - -""" - mean(A::AbstractArray; dims) - -Compute the mean of an array over the given dimensions. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> A = [1 2; 3 4] -2×2 Matrix{Int64}: - 1 2 - 3 4 - -julia> mean(A, dims=1) -1×2 Matrix{Float64}: - 2.0 3.0 - -julia> mean(A, dims=2) -2×1 Matrix{Float64}: - 1.5 - 3.5 -``` -""" -mean(A::AbstractArray; dims=:) = _mean(identity, A, dims) - -_mean_promote(x::T, y::S) where {T,S} = convert(promote_type(T, S), y) - -# ::Dims is there to force specializing on Colon (as it is a Function) -function _mean(f, A::AbstractArray, dims::Dims=:) where Dims - isempty(A) && return sum(f, A, dims=dims)/0 - if dims === (:) - n = length(A) - else - n = mapreduce(i -> size(A, i), *, unique(dims); init=1) - end - x1 = f(first(A)) / 1 - result = sum(x -> _mean_promote(x1, f(x)), A, dims=dims) - if dims === (:) - return result / n - else - return result ./= n - end -end - -function mean(r::AbstractRange{<:Real}) - isempty(r) && return oftype((first(r) + last(r)) / 2, NaN) - (first(r) + last(r)) / 2 -end - - -##### variances ##### - -# faster computation of real(conj(x)*y) -realXcY(x::Real, y::Real) = x*y -realXcY(x::Complex, y::Complex) = real(x)*real(y) + imag(x)*imag(y) - -var(iterable; corrected::Bool=true, mean=nothing) = _var(iterable, corrected, mean) - -function _var(iterable, corrected::Bool, mean) - y = iterate(iterable) - if y === nothing - T = eltype(iterable) - return oftype((abs2(zero(T)) + abs2(zero(T)))/2, NaN) - end - count = 1 - value, state = y - y = iterate(iterable, state) - if mean === nothing - # Use Welford algorithm as seen in (among other places) - # Knuth's TAOCP, Vol 2, page 232, 3rd edition. - M = value / 1 - S = real(zero(M)) - while y !== nothing - value, state = y - y = iterate(iterable, state) - count += 1 - new_M = M + (value - M) / count - S = S + realXcY(value - M, value - new_M) - M = new_M - end - return S / (count - Int(corrected)) - elseif isa(mean, Number) # mean provided - # Cannot use a compensated version, e.g. the one from - # "Updating Formulae and a Pairwise Algorithm for Computing Sample Variances." - # by Chan, Golub, and LeVeque, Technical Report STAN-CS-79-773, - # Department of Computer Science, Stanford University, - # because user can provide mean value that is different to mean(iterable) - sum2 = abs2(value - mean::Number) - while y !== nothing - value, state = y - y = iterate(iterable, state) - count += 1 - sum2 += abs2(value - mean) - end - return sum2 / (count - Int(corrected)) - else - throw(ArgumentError("invalid value of mean, $(mean)::$(typeof(mean))")) - end -end - -centralizedabs2fun(m) = x -> abs2.(x - m) -centralize_sumabs2(A::AbstractArray, m) = - mapreduce(centralizedabs2fun(m), +, A) -centralize_sumabs2(A::AbstractArray, m, ifirst::Int, ilast::Int) = - Base.mapreduce_impl(centralizedabs2fun(m), +, A, ifirst, ilast) - -function centralize_sumabs2!(R::AbstractArray{S}, A::AbstractArray, means::AbstractArray) where S - # following the implementation of _mapreducedim! at base/reducedim.jl - lsiz = Base.check_reducedims(R,A) - for i in 1:max(ndims(R), ndims(means)) - if axes(means, i) != axes(R, i) - throw(DimensionMismatch("dimension $i of `mean` should have indices $(axes(R, i)), but got $(axes(means, i))")) - end - end - isempty(R) || fill!(R, zero(S)) - isempty(A) && return R - - if Base.has_fast_linear_indexing(A) && lsiz > 16 && !Base.has_offset_axes(R, means) - nslices = div(length(A), lsiz) - ibase = first(LinearIndices(A))-1 - for i = 1:nslices - @inbounds R[i] = centralize_sumabs2(A, means[i], ibase+1, ibase+lsiz) - ibase += lsiz - end - return R - end - indsAt, indsRt = Base.safe_tail(axes(A)), Base.safe_tail(axes(R)) # handle d=1 manually - keep, Idefault = Broadcast.shapeindexer(indsRt) - if Base.reducedim1(R, A) - i1 = first(Base.axes1(R)) - @inbounds for IA in CartesianIndices(indsAt) - IR = Broadcast.newindex(IA, keep, Idefault) - r = R[i1,IR] - m = means[i1,IR] - @simd for i in axes(A, 1) - r += abs2(A[i,IA] - m) - end - R[i1,IR] = r - end - else - @inbounds for IA in CartesianIndices(indsAt) - IR = Broadcast.newindex(IA, keep, Idefault) - @simd for i in axes(A, 1) - R[i,IR] += abs2(A[i,IA] - means[i,IR]) - end - end - end - return R -end - -function varm!(R::AbstractArray{S}, A::AbstractArray, m::AbstractArray; corrected::Bool=true) where S - if isempty(A) - fill!(R, convert(S, NaN)) - else - rn = div(length(A), length(R)) - Int(corrected) - centralize_sumabs2!(R, A, m) - R .= R .* (1 // rn) - end - return R -end - -varm(A::AbstractArray, m::AbstractArray; corrected::Bool=true, dims=:) = _varm(A, m, corrected, dims) - -_varm(A::AbstractArray{T}, m, corrected::Bool, region) where {T} = - varm!(Base.reducedim_init(t -> abs2(t)/2, +, A, region), A, m; corrected=corrected) - -varm(A::AbstractArray, m; corrected::Bool=true) = _varm(A, m, corrected, :) - -function _varm(A::AbstractArray{T}, m, corrected::Bool, ::Colon) where T - n = length(A) - n == 0 && return oftype((abs2(zero(T)) + abs2(zero(T)))/2, NaN) - return centralize_sumabs2(A, m) / (n - Int(corrected)) -end - - -""" - var(itr; corrected::Bool=true, mean=nothing[, dims]) - -Compute the sample variance of collection `itr`. - -The algorithm returns an estimator of the generative distribution's variance -under the assumption that each entry of `itr` is a sample drawn from the same -unknown distribution, with the samples uncorrelated. -For arrays, this computation is equivalent to calculating -`sum((itr .- mean(itr)).^2) / (length(itr) - 1)`. -If `corrected` is `true`, then the sum is scaled with `n-1`, -whereas the sum is scaled with `n` if `corrected` is -`false` where `n` is the number of elements in `itr`. - -If `itr` is an `AbstractArray`, `dims` can be provided to compute the variance -over dimensions. - -A pre-computed `mean` may be provided. When `dims` is specified, `mean` must be -an array with the same shape as `mean(itr, dims=dims)` (additional trailing -singleton dimensions are allowed). - -!!! note - If array contains `NaN` or [`missing`](@ref) values, the result is also - `NaN` or `missing` (`missing` takes precedence if array contains both). - Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the - variance of non-missing values. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. -""" -var(A::AbstractArray; corrected::Bool=true, mean=nothing, dims=:) = _var(A, corrected, mean, dims) - -function _var(A::AbstractArray, corrected::Bool, m, dims) - if m === nothing - m = mean(A, dims=dims) - end - return varm(A, m; corrected=corrected, dims=dims) -end - -function _var(A::AbstractArray, corrected::Bool, m, ::Colon) - if m === nothing - m = mean(A) - end - return real(varm(A, m; corrected=corrected)) -end - -varm(iterable, m; corrected::Bool=true) = _var(iterable, corrected, m) - -## variances over ranges - -varm(v::AbstractRange, m::AbstractArray) = range_varm(v, m) -varm(v::AbstractRange, m) = range_varm(v, m) - -function range_varm(v::AbstractRange, m) - f = first(v) - m - s = step(v) - l = length(v) - vv = f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 - if l == 0 || l == 1 - return typeof(vv)(NaN) - end - return vv -end - -function var(v::AbstractRange) - s = step(v) - l = length(v) - vv = abs2(s) * (l + 1) * l / 12 - if l == 0 || l == 1 - return typeof(vv)(NaN) - end - return vv -end - - -##### standard deviation ##### - -function sqrt!(A::AbstractArray) - for i in eachindex(A) - @inbounds A[i] = sqrt(A[i]) - end - A -end - -""" - std(itr; corrected::Bool=true, mean=nothing[, dims]) - -Compute the sample standard deviation of collection `itr`. - -The algorithm returns an estimator of the generative distribution's standard -deviation under the assumption that each entry of `itr` is a sample drawn from -the same unknown distribution, with the samples uncorrelated. -For arrays, this computation is equivalent to calculating -`sqrt(sum((itr .- mean(itr)).^2) / (length(itr) - 1))`. -If `corrected` is `true`, then the sum is scaled with `n-1`, -whereas the sum is scaled with `n` if `corrected` is -`false` with `n` the number of elements in `itr`. - -If `itr` is an `AbstractArray`, `dims` can be provided to compute the standard deviation -over dimensions, and `means` may contain means for each dimension of `itr`. - -A pre-computed `mean` may be provided. When `dims` is specified, `mean` must be -an array with the same shape as `mean(itr, dims=dims)` (additional trailing -singleton dimensions are allowed). - -!!! note - If array contains `NaN` or [`missing`](@ref) values, the result is also - `NaN` or `missing` (`missing` takes precedence if array contains both). - Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the - standard deviation of non-missing values. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. -""" -std(A::AbstractArray; corrected::Bool=true, mean=nothing, dims=:) = _std(A, corrected, mean, dims) - -_std(A::AbstractArray, corrected::Bool, mean, dims) = - sqrt.(var(A; corrected=corrected, mean=mean, dims=dims)) - -_std(A::AbstractArray, corrected::Bool, mean, ::Colon) = - sqrt.(var(A; corrected=corrected, mean=mean)) - -_std(A::AbstractArray{<:AbstractFloat}, corrected::Bool, mean, dims) = - sqrt!(var(A; corrected=corrected, mean=mean, dims=dims)) - -_std(A::AbstractArray{<:AbstractFloat}, corrected::Bool, mean, ::Colon) = - sqrt.(var(A; corrected=corrected, mean=mean)) - -std(iterable; corrected::Bool=true, mean=nothing) = - sqrt(var(iterable, corrected=corrected, mean=mean)) diff --git a/doc/make.jl b/doc/make.jl index f455d7fc221ff..5036ef5ee44cb 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -122,7 +122,6 @@ BaseDocs = [ "base/libc.md", "base/stacktraces.md", "base/simd-types.md", - "base/statistics.md", ] StdlibDocs = [stdlib.targetfile for stdlib in STDLIB_DOCS] diff --git a/doc/src/base/collections.md b/doc/src/base/collections.md index 96f540086d021..5c150b549daa6 100644 --- a/doc/src/base/collections.md +++ b/doc/src/base/collections.md @@ -115,6 +115,8 @@ Base.sum Base.sum! Base.prod Base.prod! +Base.mean +Base.mean! Base.any(::Any) Base.any(::AbstractArray, ::Any) Base.any! diff --git a/doc/src/base/statistics.md b/doc/src/base/statistics.md deleted file mode 100644 index 909d10cfcb445..0000000000000 --- a/doc/src/base/statistics.md +++ /dev/null @@ -1,8 +0,0 @@ -# Statistics - -```@docs -Base.mean -Base.mean! -Base.std -Base.var -``` diff --git a/test/choosetests.jl b/test/choosetests.jl index 0b6561fc68a6d..3617b4b31bfb4 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -29,7 +29,6 @@ const TESTNAMES = [ "channels", "iostream", "secretbuffer", "specificity", "reinterpretarray", "syntax", "corelogging", "missing", "asyncmap", "smallarrayshrink", "opaque_closure", "filesystem", "download", - "statistics" ] """ diff --git a/test/reduce.jl b/test/reduce.jl index c03013f880013..f957c4dfef570 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -689,3 +689,131 @@ end @test @inferred(prod(b)) == prod(collect(b)) @test @inferred(minimum(a)) == minimum(collect(a)) end + +@testset "mean" begin + @test mean((1,2,3)) === 2. + @test mean([0]) === 0. + @test mean([1.]) === 1. + @test mean([1.,3]) == 2. + @test mean([1,2,3]) == 2. + @test mean([0 1 2; 4 5 6], dims=1) == [2. 3. 4.] + @test mean([1 2 3; 4 5 6], dims=1) == [2.5 3.5 4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=1) == [-2.5 -3.5 -4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=2) == transpose([-2.0 -5.0]) + @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 2)) == -3.5 .* ones(1, 1) + @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 1)) == [-2.5 -3.5 -4.5] + @test mean(-, [1 2 3 ; 4 5 6], dims=()) == Float64[-1 -2 -3 ; -4 -5 -6] + @test mean(i->i+1, 0:2) === 2. + @test mean(isodd, [3]) === 1. + @test mean(x->3x, (1,1)) === 3. + + # mean of iterables: + n = 10; a = randn(n); b = randn(n) + @test mean(Tuple(a)) ≈ mean(a) + @test mean(Tuple(a + b*im)) ≈ mean(a + b*im) + @test mean(cos, Tuple(a)) ≈ mean(cos, a) + @test mean(x->x/2, a + b*im) ≈ mean(a + b*im) / 2. + @test ismissing(mean(Tuple((1, 2, missing, 4, 5)))) + + @test isnan(mean([NaN])) + @test isnan(mean([0.0,NaN])) + @test isnan(mean([NaN,0.0])) + + @test isnan(mean([0.,Inf,-Inf])) + @test isnan(mean([1.,-1.,Inf,-Inf])) + @test isnan(mean([-Inf,Inf])) + @test isequal(mean([NaN 0.0; 1.2 4.5], dims=2), reshape([NaN; 2.85], 2, 1)) + + @test ismissing(mean([1, missing])) + @test ismissing(mean([NaN, missing])) + @test ismissing(mean([missing, NaN])) + @test isequal(mean([missing 1.0; 2.0 3.0], dims=1), [missing 2.0]) + @test mean(skipmissing([1, missing, 2])) === 1.5 + @test isequal(mean(Complex{Float64}[]), NaN+NaN*im) + @test mean(Complex{Float64}[]) isa Complex{Float64} + @test isequal(mean(skipmissing(Complex{Float64}[])), NaN+NaN*im) + @test mean(skipmissing(Complex{Float64}[])) isa Complex{Float64} + @test isequal(mean(abs, Complex{Float64}[]), NaN) + @test mean(abs, Complex{Float64}[]) isa Float64 + @test isequal(mean(abs, skipmissing(Complex{Float64}[])), NaN) + @test mean(abs, skipmissing(Complex{Float64}[])) isa Float64 + @test isequal(mean(Int[]), NaN) + @test mean(Int[]) isa Float64 + @test isequal(mean(skipmissing(Int[])), NaN) + @test mean(skipmissing(Int[])) isa Float64 + @test_throws MethodError mean([]) + @test_throws MethodError mean(skipmissing([])) + @test_throws ArgumentError mean((1 for i in 2:1)) + @test_throws ArgumentError mean(()) + @test_throws ArgumentError mean(Union{}[]) + + # Check that small types are accumulated using wider type + for T in (Int8, UInt8) + x = [typemax(T) typemax(T)] + g = (v for v in x) + @test mean(x) == mean(g) == typemax(T) + @test mean(identity, x) == mean(identity, g) == typemax(T) + @test mean(x, dims=2) == [typemax(T)]' + end + # Check that mean avoids integer overflow (#22) + let x = fill(typemax(Int), 10), a = tuple(x...) + @test (mean(x) == mean(x, dims=1)[] == mean(float, x) + == mean(a) == mean(v for v in x) == mean(v for v in a) + ≈ float(typemax(Int))) + end + let x = rand(10000) # mean should use sum's accurate pairwise algorithm + @test mean(x) == sum(x) / length(x) + end + @test mean(Number[1, 1.5, 2+3im]) === 1.5+1im # mixed-type array + @test mean(v for v in Number[1, 1.5, 2+3im]) === 1.5+1im + @test isnan(@inferred mean(Int[])) + @test isnan(@inferred mean(Float32[])) + @test isnan(@inferred mean(Float64[])) + @test isnan(@inferred mean(Iterators.filter(x -> true, Int[]))) + @test isnan(@inferred mean(Iterators.filter(x -> true, Float32[]))) + @test isnan(@inferred mean(Iterators.filter(x -> true, Float64[]))) +end + +@testset "mean for ranges" begin + for n = 2:5 + @test mean(2:n) == mean([2:n;]) + @test mean(2:0.1:n) ≈ mean([2:0.1:n;]) + end + @test mean(2:1) === NaN + @test mean(big(2):1) isa BigFloat +end + +@testset "mean!" begin + x = rand(5, 3) + + r = similar(x, 5) + @test mean!(r, x) === r + @test r ≈ mean(x, dims=2) + + r = similar(x, 5, 1) + @test mean!(r, x) === r + @test r ≈ mean(x, dims=2) + + r = similar(x, 1, 3) + @test mean!(r, x) === r + @test r ≈ mean(x, dims=1) + + r = similar(x, 5, 3) + @test mean!(r, x) === r + @test r ≈ x + + r = similar(x, 1) + @test mean!(r, x) === r + @test r[] ≈ mean(x) + + r = similar(x, ()) + @test mean!(r, x) === r + @test r[] ≈ mean(x) + + @test_throws DimensionMismatch mean!(zeros(0, 0), x) + @test_throws DimensionMismatch mean!(zeros(0), x) + @test_throws DimensionMismatch mean!(zeros(2), x) + @test_throws DimensionMismatch mean!(zeros(2, 2), x) + @test_throws DimensionMismatch mean!(zeros(2, 3), x) + @test_throws DimensionMismatch mean!(zeros(5, 2), x) +end \ No newline at end of file diff --git a/test/statistics.jl b/test/statistics.jl deleted file mode 100644 index 22c73ffd782b6..0000000000000 --- a/test/statistics.jl +++ /dev/null @@ -1,266 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -@testset "mean" begin - @test mean((1,2,3)) === 2. - @test mean([0]) === 0. - @test mean([1.]) === 1. - @test mean([1.,3]) == 2. - @test mean([1,2,3]) == 2. - @test mean([0 1 2; 4 5 6], dims=1) == [2. 3. 4.] - @test mean([1 2 3; 4 5 6], dims=1) == [2.5 3.5 4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=1) == [-2.5 -3.5 -4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=2) == transpose([-2.0 -5.0]) - @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 2)) == -3.5 .* ones(1, 1) - @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 1)) == [-2.5 -3.5 -4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=()) == Float64[-1 -2 -3 ; -4 -5 -6] - @test mean(i->i+1, 0:2) === 2. - @test mean(isodd, [3]) === 1. - @test mean(x->3x, (1,1)) === 3. - - # mean of iterables: - n = 10; a = randn(n); b = randn(n) - @test mean(Tuple(a)) ≈ mean(a) - @test mean(Tuple(a + b*im)) ≈ mean(a + b*im) - @test mean(cos, Tuple(a)) ≈ mean(cos, a) - @test mean(x->x/2, a + b*im) ≈ mean(a + b*im) / 2. - @test ismissing(mean(Tuple((1, 2, missing, 4, 5)))) - - @test isnan(mean([NaN])) - @test isnan(mean([0.0,NaN])) - @test isnan(mean([NaN,0.0])) - - @test isnan(mean([0.,Inf,-Inf])) - @test isnan(mean([1.,-1.,Inf,-Inf])) - @test isnan(mean([-Inf,Inf])) - @test isequal(mean([NaN 0.0; 1.2 4.5], dims=2), reshape([NaN; 2.85], 2, 1)) - - @test ismissing(mean([1, missing])) - @test ismissing(mean([NaN, missing])) - @test ismissing(mean([missing, NaN])) - @test isequal(mean([missing 1.0; 2.0 3.0], dims=1), [missing 2.0]) - @test mean(skipmissing([1, missing, 2])) === 1.5 - @test isequal(mean(Complex{Float64}[]), NaN+NaN*im) - @test mean(Complex{Float64}[]) isa Complex{Float64} - @test isequal(mean(skipmissing(Complex{Float64}[])), NaN+NaN*im) - @test mean(skipmissing(Complex{Float64}[])) isa Complex{Float64} - @test isequal(mean(abs, Complex{Float64}[]), NaN) - @test mean(abs, Complex{Float64}[]) isa Float64 - @test isequal(mean(abs, skipmissing(Complex{Float64}[])), NaN) - @test mean(abs, skipmissing(Complex{Float64}[])) isa Float64 - @test isequal(mean(Int[]), NaN) - @test mean(Int[]) isa Float64 - @test isequal(mean(skipmissing(Int[])), NaN) - @test mean(skipmissing(Int[])) isa Float64 - @test_throws MethodError mean([]) - @test_throws MethodError mean(skipmissing([])) - @test_throws ArgumentError mean((1 for i in 2:1)) - if VERSION >= v"1.6.0-DEV.83" - @test_throws ArgumentError mean(()) - @test_throws ArgumentError mean(Union{}[]) - end - - # Check that small types are accumulated using wider type - for T in (Int8, UInt8) - x = [typemax(T) typemax(T)] - g = (v for v in x) - @test mean(x) == mean(g) == typemax(T) - @test mean(identity, x) == mean(identity, g) == typemax(T) - @test mean(x, dims=2) == [typemax(T)]' - end - # Check that mean avoids integer overflow (#22) - let x = fill(typemax(Int), 10), a = tuple(x...) - @test (mean(x) == mean(x, dims=1)[] == mean(float, x) - == mean(a) == mean(v for v in x) == mean(v for v in a) - ≈ float(typemax(Int))) - end - let x = rand(10000) # mean should use sum's accurate pairwise algorithm - @test mean(x) == sum(x) / length(x) - end - @test mean(Number[1, 1.5, 2+3im]) === 1.5+1im # mixed-type array - @test mean(v for v in Number[1, 1.5, 2+3im]) === 1.5+1im - @test isnan(@inferred mean(Int[])) - @test isnan(@inferred mean(Float32[])) - @test isnan(@inferred mean(Float64[])) - @test isnan(@inferred mean(Iterators.filter(x -> true, Int[]))) - @test isnan(@inferred mean(Iterators.filter(x -> true, Float32[]))) - @test isnan(@inferred mean(Iterators.filter(x -> true, Float64[]))) -end - -@testset "mean for ranges" begin - for n = 2:5 - @test mean(2:n) == mean([2:n;]) - @test mean(2:0.1:n) ≈ mean([2:0.1:n;]) - end - @test mean(2:1) === NaN - @test mean(big(2):1) isa BigFloat -end - -@testset "var & std" begin - # edge case: empty vector - # iterable; this has to throw for type stability - @test_throws MethodError var(()) - @test_throws MethodError var((); corrected=false) - @test_throws MethodError var((); mean=2) - @test_throws MethodError var((); mean=2, corrected=false) - # reduction - @test isnan(var(Int[])) - @test isnan(var(Int[]; corrected=false)) - @test isnan(var(Int[]; mean=2)) - @test isnan(var(Int[]; mean=2, corrected=false)) - # reduction across dimensions - @test isequal(var(Int[], dims=1), [NaN]) - @test isequal(var(Int[], dims=1; corrected=false), [NaN]) - @test isequal(var(Int[], dims=1; mean=[2]), [NaN]) - @test isequal(var(Int[], dims=1; mean=[2], corrected=false), [NaN]) - - # edge case: one-element vector - # iterable - @test isnan(@inferred(var((1,)))) - @test var((1,); corrected=false) === 0.0 - @test var((1,); mean=2) === Inf - @test var((1,); mean=2, corrected=false) === 1.0 - # reduction - @test isnan(@inferred(var([1]))) - @test var([1]; corrected=false) === 0.0 - @test var([1]; mean=2) === Inf - @test var([1]; mean=2, corrected=false) === 1.0 - # reduction across dimensions - @test isequal(@inferred(var([1], dims=1)), [NaN]) - @test var([1], dims=1; corrected=false) ≈ [0.0] - @test var([1], dims=1; mean=[2]) ≈ [Inf] - @test var([1], dims=1; mean=[2], corrected=false) ≈ [1.0] - - @test var(1:8) == 6. - @test var(1:8, mean=1) == var(Vector(1:8), mean=1) - @test isnan(var(1:1, mean=1)) - @test isnan(var(1:1)) - @test isnan(var(1:-1)) - - @test @inferred(var(1.0:8.0)) == 6. - @test var(1.0:8.0, mean=1.0) == var(Vector(1.0:8.0), mean=1) - @test isnan(var(1.0:1.0, mean=1.0)) - @test isnan(var(1.0:1.0)) - @test isnan(var(1.0:-1.0)) - - @test @inferred(var(1.0f0:8.0f0)) === 6.f0 - @test var(1.0f0:8.0f0, mean=1.0f0) == var(Vector(1.0f0:8.0f0), mean=1) - @test isnan(var(1.0f0:1.0f0, mean=1.0f0)) - @test isnan(var(1.0f0:1.0f0)) - @test isnan(var(1.0f0:-1.0f0)) - - @test var([1,2,3], mean=2) ≈ 1. - @test var([1,2,3]) ≈ 1. - @test var([1,2,3]; corrected=false) ≈ 2.0/3 - @test var([1,2,3]; mean=0) ≈ 7. - @test var([1,2,3]; mean=0, corrected=false) ≈ 14.0/3 - - @test var((1,2,3), mean=2) ≈ 1. - @test var((1,2,3)) ≈ 1. - @test var((1,2,3); corrected=false) ≈ 2.0/3 - @test var((1,2,3); mean=0) ≈ 7. - @test var((1,2,3); mean=0, corrected=false) ≈ 14.0/3 - @test_throws ArgumentError var((1,2,3); mean=()) - - @test var([1 2 3 4 5; 6 7 8 9 10], dims=2) ≈ [2.5 2.5]' - @test var([1 2 3 4 5; 6 7 8 9 10], dims=2; corrected=false) ≈ [2.0 2.0]' - - @test var(collect(1:99), dims=1) ≈ [825] - @test var(Matrix(transpose(collect(1:99))), dims=2) ≈ [825] - - @test std([1,2,3], mean=2) ≈ 1. - @test std([1,2,3]) ≈ 1. - @test std([1,2,3]; corrected=false) ≈ sqrt(2.0/3) - @test std([1,2,3]; mean=0) ≈ sqrt(7.0) - @test std([1,2,3]; mean=0, corrected=false) ≈ sqrt(14.0/3) - - @test std([1.0,2,3], mean=2) ≈ 1. - @test std([1.0,2,3]) ≈ 1. - @test std([1.0,2,3]; corrected=false) ≈ sqrt(2.0/3) - @test std([1.0,2,3]; mean=0) ≈ sqrt(7.0) - @test std([1.0,2,3]; mean=0, corrected=false) ≈ sqrt(14.0/3) - - @test std([1.0,2,3], mean=[0]; dims=1, corrected=false)[] ≈ sqrt(14.0/3) - @test std([1.0,2,3]; dims=1)[] ≈ 1. - @test std([1.0,2,3]; dims=1, corrected=false)[] ≈ sqrt(2.0/3) - @test std([1.0,2,3]; dims=1, mean=[0])[] ≈ sqrt(7.0) - @test std([1.0,2,3]; dims=1, mean=[0], corrected=false)[] ≈ sqrt(14.0/3) - - @test std((1,2,3), mean=2) ≈ 1. - @test std((1,2,3)) ≈ 1. - @test std((1,2,3); corrected=false) ≈ sqrt(2.0/3) - @test std((1,2,3); mean=0) ≈ sqrt(7.0) - @test std((1,2,3); mean=0, corrected=false) ≈ sqrt(14.0/3) - - @test std([1 2 3 4 5; 6 7 8 9 10], mean=[3.0,8.0], dims=2) ≈ sqrt.([2.5 2.5]') - @test std([1 2 3 4 5; 6 7 8 9 10], mean=[3.0,8.0], dims=2; corrected=false) ≈ sqrt.([2.0 2.0]') - @test std([1 2 3 4 5; 6 7 8 9 10], dims=2) ≈ sqrt.([2.5 2.5]') - @test std([1 2 3 4 5; 6 7 8 9 10], dims=2; corrected=false) ≈ sqrt.([2.0 2.0]') - - let A = ComplexF64[exp(i*im) for i in 1:10^4] - @test var(A, mean=0.) ≈ sum(map(abs2, A)) / (length(A) - 1) - @test var(A, mean=mean(A)) ≈ var(A) - end - - @test var([1//1, 2//1]) isa Rational{Int} - @test var([1//1, 2//1], dims=1) isa Vector{Rational{Int}} - - @test std([1//1, 2//1]) isa Float64 - @test std([1//1, 2//1], dims=1) isa Vector{Float64} - - @testset "var: empty cases" begin - A = Matrix{Int}(undef, 0,1) - @test var(A) === NaN - - @test isequal(var(A, dims=1), fill(NaN, 1, 1)) - @test isequal(var(A, dims=2), fill(NaN, 0, 1)) - @test isequal(var(A, dims=(1, 2)), fill(NaN, 1, 1)) - @test isequal(var(A, dims=3), fill(NaN, 0, 1)) - end - - # issue #6672 - @test std(AbstractFloat[1,2,3], dims=1) == [1.0] - - for f in (var, std) - @test ismissing(f([1, missing])) - @test ismissing(f([NaN, missing])) - @test ismissing(f([missing, NaN])) - @test isequal(f([missing 1.0; 2.0 3.0], dims=1), [missing f([1.0, 3.0])]) - @test f(skipmissing([1, missing, 2])) === f([1, 2]) - - @test ismissing(f([1, missing], mean=0)) - @test ismissing(f([1, 2], mean=missing)) - @test ismissing(f([1, NaN], mean=missing)) - @test ismissing(f([NaN, missing], mean=0)) - @test ismissing(f([missing, NaN], mean=0)) - @test ismissing(f([NaN, missing], mean=missing)) - @test ismissing(f([missing, NaN], mean=missing)) - @test f(skipmissing([1, missing, 2]), mean=0) === f([1, 2], mean=0) - end - - @test isequal(var(Complex{Float64}[]), NaN) - @test var(Complex{Float64}[]) isa Float64 - @test isequal(var(skipmissing(Complex{Float64}[])), NaN) - @test var(skipmissing(Complex{Float64}[])) isa Float64 - @test_throws MethodError var([]) - @test_throws MethodError var(skipmissing([])) - @test_throws MethodError var((1 for i in 2:1)) - @test isequal(var(Int[]), NaN) - @test var(Int[]) isa Float64 - @test isequal(var(skipmissing(Int[])), NaN) - @test var(skipmissing(Int[])) isa Float64 - - # over dimensions with provided means - x = [1 2 3; 4 5 6] - @test var(x, dims=1, mean=mean(x, dims=1)) == var(x, dims=1) - @test var(x, dims=1, mean=reshape(mean(x, dims=1), 1, :, 1)) == var(x, dims=1) - @test var(x, dims=2, mean=mean(x, dims=2)) == var(x, dims=2) - @test var(x, dims=2, mean=reshape(mean(x, dims=2), :)) == var(x, dims=2) - @test var(x, dims=2, mean=reshape(mean(x, dims=2), :, 1, 1)) == var(x, dims=2) - @test_throws DimensionMismatch var(x, dims=1, mean=ones(size(x, 1))) - @test_throws DimensionMismatch var(x, dims=1, mean=ones(size(x, 1), 1)) - @test_throws DimensionMismatch var(x, dims=2, mean=ones(1, size(x, 2))) - @test_throws DimensionMismatch var(x, dims=1, mean=ones(1, 1, size(x, 2))) - @test_throws DimensionMismatch var(x, dims=2, mean=ones(1, size(x, 2), 1)) - @test_throws DimensionMismatch var(x, dims=2, mean=ones(size(x, 1), 1, 5)) - @test_throws DimensionMismatch var(x, dims=1, mean=ones(1, size(x, 2), 5)) -end From 987bc13da2e07ababb747fed504fbbafd26d3c6e Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Mon, 10 Oct 2022 12:23:53 +0200 Subject: [PATCH 05/15] Add final newlines --- base/reducedim.jl | 2 +- test/reduce.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/base/reducedim.jl b/base/reducedim.jl index 3ca52fdb274bf..8e0496a86fd33 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -1386,4 +1386,4 @@ end function mean(r::AbstractRange{<:Real}) isempty(r) && return oftype((first(r) + last(r)) / 2, NaN) (first(r) + last(r)) / 2 -end \ No newline at end of file +end diff --git a/test/reduce.jl b/test/reduce.jl index f957c4dfef570..64a4fbc2d8ff0 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -816,4 +816,4 @@ end @test_throws DimensionMismatch mean!(zeros(2, 2), x) @test_throws DimensionMismatch mean!(zeros(2, 3), x) @test_throws DimensionMismatch mean!(zeros(5, 2), x) -end \ No newline at end of file +end From 2062d8cd864474a46e8b50ad9d2add93f123fa89 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Thu, 13 Jul 2023 23:28:11 +0200 Subject: [PATCH 06/15] Make Statistics an stdlib again --- stdlib/Makefile | 2 +- stdlib/Statistics.version | 4 ++++ test/loading.jl | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 stdlib/Statistics.version diff --git a/stdlib/Makefile b/stdlib/Makefile index 9ca3e431e2ca9..e42061d593905 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -46,7 +46,7 @@ STDLIBS = Artifacts Base64 CRC32c Dates Distributed FileWatching \ SharedArrays Sockets Test TOML Unicode UUIDs \ $(JLL_NAMES) -STDLIBS_EXT = Pkg LibCURL DelimitedFiles Downloads ArgTools Tar NetworkOptions SuiteSparse SparseArrays SHA +STDLIBS_EXT = Pkg Statistics LibCURL DelimitedFiles Downloads ArgTools Tar NetworkOptions SuiteSparse SparseArrays SHA $(foreach module, $(STDLIBS_EXT), $(eval $(call stdlib-external,$(module),$(shell echo $(module) | tr a-z A-Z)))) diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version new file mode 100644 index 0000000000000..27197b12be54c --- /dev/null +++ b/stdlib/Statistics.version @@ -0,0 +1,4 @@ +STATISTICS_BRANCH = master +STATISTICS_SHA1 = a3feba2bb63f06b7f40024185e9fa5f6385e2510 +STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git +STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 diff --git a/test/loading.jl b/test/loading.jl index 394c13c5f2962..d002d10d0dab3 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1182,4 +1182,5 @@ end @testset "Upgradable stdlibs" begin @test success(`$(Base.julia_cmd()) --startup-file=no -e 'using DelimitedFiles'`) + @test success(`$(Base.julia_cmd()) --startup-file=no -e 'using Statistics'`) end From f48f31b0cb653b0b0ef747a928cec0a3b7d06a8b Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Thu, 13 Jul 2023 23:39:44 +0200 Subject: [PATCH 07/15] Backport JuliaStats/Statistics.jl##131 --- base/reducedim.jl | 10 ++++++++++ test/reduce.jl | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/base/reducedim.jl b/base/reducedim.jl index d2fd2d36c64ba..060077652f502 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -1368,6 +1368,16 @@ julia> mean(A, dims=2) """ mean(A::AbstractArray; dims=:) = _mean(identity, A, dims) +function mean(f::Number, itr::Number) + f_value = try + f(itr) + catch MethodError + rethrow(ArgumentError("""mean(f, itr) requires a function and an iterable. + Perhaps you meant mean((x, y))?""")) + end + Base.reduce_first(+, f_value)/1 +end + # ::Dims is there to force specializing on Colon (as it is a Function) function _mean(f, A::AbstractArray, dims::Dims=:) where Dims isempty(A) && return sum(f, A, dims=dims)/0 diff --git a/test/reduce.jl b/test/reduce.jl index a7cc732fbc5e9..2ed879567aaf6 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -788,6 +788,14 @@ end @test isnan(@inferred mean(Iterators.filter(x -> true, Int[]))) @test isnan(@inferred mean(Iterators.filter(x -> true, Float32[]))) @test isnan(@inferred mean(Iterators.filter(x -> true, Float64[]))) + + # using a number as a "function" + @test_throws "ArgumentError: mean(f, itr) requires a function and an iterable.\nPerhaps you meant mean((x, y))?" mean(1, 2) + struct T <: Number + x::Int + end + (t::T)(y) = t.x * y + @test @inferred mean(T(2), 3) === 6.0 end @testset "mean for ranges" begin From 21a49d772bcfb0e4697f3f984135f2249d4f54b4 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Sun, 30 Jul 2023 16:30:37 +0200 Subject: [PATCH 08/15] Adapt pkgimage.mk --- pkgimage.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgimage.mk b/pkgimage.mk index 0803a188851bb..5bbf1e6ba9bfa 100644 --- a/pkgimage.mk +++ b/pkgimage.mk @@ -27,7 +27,7 @@ STDLIBS := ArgTools Artifacts Base64 CRC32c FileWatching Libdl NetworkOptions SH Zlib_jll dSFMT_jll libLLVM_jll libblastrampoline_jll OpenBLAS_jll Printf Random Tar \ LibSSH2_jll MPFR_jll LinearAlgebra Dates Distributed Future LibGit2 Profile SparseArrays UUIDs \ SharedArrays TOML Test LibCURL Downloads Pkg Dates LazyArtifacts Sockets Unicode Markdown \ - InteractiveUtils REPL DelimitedFiles + InteractiveUtils REPL DelimitedFiles Statistics all-release: $(addprefix cache-release-, $(STDLIBS)) all-debug: $(addprefix cache-debug-, $(STDLIBS)) @@ -129,5 +129,5 @@ $(eval $(call sysimg_builder,Pkg,Dates LibGit2 Libdl Logging Printf Random SHA U $(eval $(call pkgimg_builder,LazyArtifacts,Artifacts Pkg)) $(eval $(call pkgimg_builder,SparseArrays,Libdl LinearAlgebra Random Serialization)) +$(eval $(call pkgimg_builder,Statistics,LinearAlgebra SparseArrays)) # SuiteSparse_jll -# Statistics From b64715499d548ca7e4f6a5f749a9902ac4590d43 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Tue, 15 Aug 2023 10:48:44 +0200 Subject: [PATCH 09/15] Use latest Statistics.jl to fix building manual --- stdlib/Statistics.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index 27197b12be54c..b41bde83ef0da 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = a3feba2bb63f06b7f40024185e9fa5f6385e2510 +STATISTICS_SHA1 = 14438ab59ec5ea76d6eea844f03040c692d3b1f3 STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 From dea1d570e35b7bb84382237a52908564cc2a418e Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Tue, 15 Aug 2023 10:49:47 +0200 Subject: [PATCH 10/15] Also update checksums --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 create mode 100644 deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 delete mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 delete mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 diff --git a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 new file mode 100644 index 0000000000000..0a0008313ae76 --- /dev/null +++ b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 @@ -0,0 +1 @@ +0fa18e602c971748ba3398b8dc89588d diff --git a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 new file mode 100644 index 0000000000000..8d5c5af20cd63 --- /dev/null +++ b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 @@ -0,0 +1 @@ +0ea0d3fc88191ccea71d0b8fd4dec8cc3bd72947cc6a8d3193b2c4348efe38f41d99d00a5c79c7af812f9585231961f6c0cd5b8b5c4b443260a2c68c10fb374e diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 deleted file mode 100644 index 7e7a889eecd29..0000000000000 --- a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -6564297a5f5971231809bf9940f68b98 diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 deleted file mode 100644 index bbe9b8bed6371..0000000000000 --- a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -22d14c82a30f3ec7af09028423cc823808abf86918d5707fd1fcf6ca20dea7871589da9b22e462d194e86fcee380f549aeb65f585048f00bf23281786b17e040 From fcac4b945e1d81671c055328a6ae9f0066b2fe5f Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Tue, 15 Aug 2023 11:20:43 +0200 Subject: [PATCH 11/15] Fix missing ending newline --- test/reduce.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/reduce.jl b/test/reduce.jl index 2ed879567aaf6..0b7efb9da7462 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -840,4 +840,4 @@ end @test_throws DimensionMismatch mean!(zeros(2, 2), x) @test_throws DimensionMismatch mean!(zeros(2, 3), x) @test_throws DimensionMismatch mean!(zeros(5, 2), x) -end \ No newline at end of file +end From 73bcc1ae86e1744a3e3031d2ed2404d04dc50f76 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Tue, 15 Aug 2023 19:49:37 +0200 Subject: [PATCH 12/15] Revert moving `mean` to Base --- base/exports.jl | 2 - base/reduce.jl | 71 --------- base/reducedim.jl | 117 --------------- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + doc/src/base/collections.md | 2 - julia.spdx.json | 17 +++ stdlib/Statistics.version | 2 +- test/reduce.jl | 136 ------------------ 11 files changed, 20 insertions(+), 331 deletions(-) delete mode 100644 deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 delete mode 100644 deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 create mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 create mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 diff --git a/base/exports.jl b/base/exports.jl index fd7c542709c29..0959fa1c391e2 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -415,8 +415,6 @@ export max, maximum!, maximum, - mean, - mean!, min, minimum!, minimum, diff --git a/base/reduce.jl b/base/reduce.jl index 9fff597026e95..61a0f466b2902 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -619,77 +619,6 @@ julia> prod(1:5; init = 1.0) """ prod(a; kw...) = mapreduce(identity, mul_prod, a; kw...) -## mean - -_mean_promote(x::T, y::S) where {T,S} = convert(promote_type(T, S), y) - -""" - mean(itr) - -Compute the mean of all elements in a collection. - -!!! note - If `itr` contains `NaN` or [`missing`](@ref) values, the result is also - `NaN` or `missing` (`missing` takes precedence if array contains both). - Use the [`skipmissing`](@ref) function to omit `missing` entries and compute the - mean of non-missing values. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> mean(1:20) -10.5 - -julia> mean([1, missing, 3]) -missing - -julia> mean(skipmissing([1, missing, 3])) -2.0 -``` -""" -mean(itr) = mean(identity, itr) - -""" - mean(f, itr) - -Apply the function `f` to each element of collection `itr` and take the mean. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> mean(√, [1, 2, 3]) -1.3820881233139908 - -julia> mean([√1, √2, √3]) -1.3820881233139908 -``` -""" -function mean(f, itr) - y = iterate(itr) - if y === nothing - return mapreduce_empty_iter(f, +, itr, - IteratorEltype(itr)) / 0 - end - count = 1 - value, state = y - f_value = f(value)/1 - total = reduce_first(+, f_value) - y = iterate(itr, state) - while y !== nothing - value, state = y - total += _mean_promote(total, f(value)) - count += 1 - y = iterate(itr, state) - end - return total/count -end - ## maximum, minimum, & extrema _fast(::typeof(min),x,y) = min(x,y) _fast(::typeof(max),x,y) = max(x,y) diff --git a/base/reducedim.jl b/base/reducedim.jl index 060077652f502..c1c58ccdfefed 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -1282,120 +1282,3 @@ julia> argmax(A, dims=2) ``` """ argmax(A::AbstractArray; dims=:) = findmax(A; dims=dims)[2] - -""" - mean(f, A::AbstractArray; dims) - -Apply the function `f` to each element of array `A` and take the mean over dimensions `dims`. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -```jldoctest -julia> mean(√, [1, 2, 3]) -1.3820881233139908 - -julia> mean([√1, √2, √3]) -1.3820881233139908 - -julia> mean(√, [1 2 3; 4 5 6], dims=2) -2×1 Matrix{Float64}: - 1.3820881233139908 - 2.2285192400943226 -``` -""" -mean(f, A::AbstractArray; dims=:) = _mean(f, A, dims) - -""" - mean!(r, v) - -Compute the mean of `v` over the singleton dimensions of `r`, and write results to `r`. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> v = [1 2; 3 4] -2×2 Matrix{Int64}: - 1 2 - 3 4 - -julia> mean!([1., 1.], v) -2-element Vector{Float64}: - 1.5 - 3.5 - -julia> mean!([1. 1.], v) -1×2 Matrix{Float64}: - 2.0 3.0 -``` -""" -function mean!(R::AbstractArray, A::AbstractArray) - sum!(R, A; init=true) - x = max(1, length(R)) // length(A) - R .= R .* x - return R -end - -""" - mean(A::AbstractArray; dims) - -Compute the mean of an array over the given dimensions. - -!!! compat "Julia 1.9" - This method requires at least Julia 1.9. - Support for older releases is provided by the Statistics package. - -# Examples -```jldoctest -julia> A = [1 2; 3 4] -2×2 Matrix{Int64}: - 1 2 - 3 4 - -julia> mean(A, dims=1) -1×2 Matrix{Float64}: - 2.0 3.0 - -julia> mean(A, dims=2) -2×1 Matrix{Float64}: - 1.5 - 3.5 -``` -""" -mean(A::AbstractArray; dims=:) = _mean(identity, A, dims) - -function mean(f::Number, itr::Number) - f_value = try - f(itr) - catch MethodError - rethrow(ArgumentError("""mean(f, itr) requires a function and an iterable. - Perhaps you meant mean((x, y))?""")) - end - Base.reduce_first(+, f_value)/1 -end - -# ::Dims is there to force specializing on Colon (as it is a Function) -function _mean(f, A::AbstractArray, dims::Dims=:) where Dims - isempty(A) && return sum(f, A, dims=dims)/0 - if dims === (:) - n = length(A) - else - n = mapreduce(i -> size(A, i), *, unique(dims); init=1) - end - x1 = f(first(A)) / 1 - result = sum(x -> _mean_promote(x1, f(x)), A, dims=dims) - if dims === (:) - return result / n - else - return result ./= n - end -end - -function mean(r::AbstractRange{<:Real}) - isempty(r) && return oftype((first(r) + last(r)) / 2, NaN) - (first(r) + last(r)) / 2 -end diff --git a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 deleted file mode 100644 index 0a0008313ae76..0000000000000 --- a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -0fa18e602c971748ba3398b8dc89588d diff --git a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 b/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 deleted file mode 100644 index 8d5c5af20cd63..0000000000000 --- a/deps/checksums/Statistics-14438ab59ec5ea76d6eea844f03040c692d3b1f3.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -0ea0d3fc88191ccea71d0b8fd4dec8cc3bd72947cc6a8d3193b2c4348efe38f41d99d00a5c79c7af812f9585231961f6c0cd5b8b5c4b443260a2c68c10fb374e diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 new file mode 100644 index 0000000000000..7e7a889eecd29 --- /dev/null +++ b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 @@ -0,0 +1 @@ +6564297a5f5971231809bf9940f68b98 diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 new file mode 100644 index 0000000000000..bbe9b8bed6371 --- /dev/null +++ b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 @@ -0,0 +1 @@ +22d14c82a30f3ec7af09028423cc823808abf86918d5707fd1fcf6ca20dea7871589da9b22e462d194e86fcee380f549aeb65f585048f00bf23281786b17e040 diff --git a/doc/src/base/collections.md b/doc/src/base/collections.md index c417e4d01ca65..8c943d447e2dd 100644 --- a/doc/src/base/collections.md +++ b/doc/src/base/collections.md @@ -116,8 +116,6 @@ Base.sum Base.sum! Base.prod Base.prod! -Base.mean -Base.mean! Base.any(::Any) Base.any(::AbstractArray, ::Any) Base.any! diff --git a/julia.spdx.json b/julia.spdx.json index 3a87873f8b159..bea7bdc6c3a5d 100644 --- a/julia.spdx.json +++ b/julia.spdx.json @@ -38,6 +38,18 @@ "copyrightText": "Copyright (c) 2017-2021: Stefan Karpinski, Kristoffer Carlsson, Fredrik Ekre, David Varela, Ian Butterworth, and contributors: https://github.com/JuliaLang/Pkg.jl/graphs/contributors", "summary": "Julia's package manager, shipped with Julia v1.0 and above" }, + { + "name": "Statistics.jl", + "SPDXID": "SPDXRef-JuliaStatistics", + "downloadLocation": "git+https://github.com/JuliaStats/Statistics.jl.git", + "filesAnalyzed": false, + "homepage": "https://juliastats.org", + "sourceInfo": "The git hash of the version in use can be found in the file stdlib/Statistics.version", + "licenseConcluded": "MIT", + "licenseDeclared": "MIT", + "copyrightText": "Copyright (c) 2012-2016: Jeff Bezanson, Stefan Karpinski, Viral B. Shah, Dahua Lin, Simon Byrne, Andreas Noack, Douglas Bates, John Myles White, Simon Kornblith, and other contributors.", + "summary": "Development repository for the Statistics standard library (stdlib) that ships with Julia." + }, { "name": "libCURL.jl", "SPDXID": "SPDXRef-JuliaCurl", @@ -434,6 +446,11 @@ "relationshipType": "BUILD_DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-JuliaMain" }, + { + "spdxElementId": "SPDXRef-JuliaStatistics", + "relationshipType": "BUILD_DEPENDENCY_OF", + "relatedSpdxElement": "SPDXRef-JuliaMain" + }, { "spdxElementId": "SPDXRef-JuliaCurl", "relationshipType": "BUILD_DEPENDENCY_OF", diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index b41bde83ef0da..27197b12be54c 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = 14438ab59ec5ea76d6eea844f03040c692d3b1f3 +STATISTICS_SHA1 = a3feba2bb63f06b7f40024185e9fa5f6385e2510 STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 diff --git a/test/reduce.jl b/test/reduce.jl index 0b7efb9da7462..aea1f1e60f6cd 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -705,139 +705,3 @@ let a = NamedTuple(Symbol(:x,i) => i for i in 1:33), b = (a...,) @test fold_alloc(a) == fold_alloc(b) == 0 end - -@testset "mean" begin - @test mean((1,2,3)) === 2. - @test mean([0]) === 0. - @test mean([1.]) === 1. - @test mean([1.,3]) == 2. - @test mean([1,2,3]) == 2. - @test mean([0 1 2; 4 5 6], dims=1) == [2. 3. 4.] - @test mean([1 2 3; 4 5 6], dims=1) == [2.5 3.5 4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=1) == [-2.5 -3.5 -4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=2) == transpose([-2.0 -5.0]) - @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 2)) == -3.5 .* ones(1, 1) - @test mean(-, [1 2 3 ; 4 5 6], dims=(1, 1)) == [-2.5 -3.5 -4.5] - @test mean(-, [1 2 3 ; 4 5 6], dims=()) == Float64[-1 -2 -3 ; -4 -5 -6] - @test mean(i->i+1, 0:2) === 2. - @test mean(isodd, [3]) === 1. - @test mean(x->3x, (1,1)) === 3. - - # mean of iterables: - n = 10; a = randn(n); b = randn(n) - @test mean(Tuple(a)) ≈ mean(a) - @test mean(Tuple(a + b*im)) ≈ mean(a + b*im) - @test mean(cos, Tuple(a)) ≈ mean(cos, a) - @test mean(x->x/2, a + b*im) ≈ mean(a + b*im) / 2. - @test ismissing(mean(Tuple((1, 2, missing, 4, 5)))) - - @test isnan(mean([NaN])) - @test isnan(mean([0.0,NaN])) - @test isnan(mean([NaN,0.0])) - - @test isnan(mean([0.,Inf,-Inf])) - @test isnan(mean([1.,-1.,Inf,-Inf])) - @test isnan(mean([-Inf,Inf])) - @test isequal(mean([NaN 0.0; 1.2 4.5], dims=2), reshape([NaN; 2.85], 2, 1)) - - @test ismissing(mean([1, missing])) - @test ismissing(mean([NaN, missing])) - @test ismissing(mean([missing, NaN])) - @test isequal(mean([missing 1.0; 2.0 3.0], dims=1), [missing 2.0]) - @test mean(skipmissing([1, missing, 2])) === 1.5 - @test isequal(mean(Complex{Float64}[]), NaN+NaN*im) - @test mean(Complex{Float64}[]) isa Complex{Float64} - @test isequal(mean(skipmissing(Complex{Float64}[])), NaN+NaN*im) - @test mean(skipmissing(Complex{Float64}[])) isa Complex{Float64} - @test isequal(mean(abs, Complex{Float64}[]), NaN) - @test mean(abs, Complex{Float64}[]) isa Float64 - @test isequal(mean(abs, skipmissing(Complex{Float64}[])), NaN) - @test mean(abs, skipmissing(Complex{Float64}[])) isa Float64 - @test isequal(mean(Int[]), NaN) - @test mean(Int[]) isa Float64 - @test isequal(mean(skipmissing(Int[])), NaN) - @test mean(skipmissing(Int[])) isa Float64 - @test_throws MethodError mean([]) - @test_throws MethodError mean(skipmissing([])) - @test_throws ArgumentError mean((1 for i in 2:1)) - @test_throws ArgumentError mean(()) - @test_throws ArgumentError mean(Union{}[]) - - # Check that small types are accumulated using wider type - for T in (Int8, UInt8) - x = [typemax(T) typemax(T)] - g = (v for v in x) - @test mean(x) == mean(g) == typemax(T) - @test mean(identity, x) == mean(identity, g) == typemax(T) - @test mean(x, dims=2) == [typemax(T)]' - end - # Check that mean avoids integer overflow (#22) - let x = fill(typemax(Int), 10), a = tuple(x...) - @test (mean(x) == mean(x, dims=1)[] == mean(float, x) - == mean(a) == mean(v for v in x) == mean(v for v in a) - ≈ float(typemax(Int))) - end - let x = rand(10000) # mean should use sum's accurate pairwise algorithm - @test mean(x) == sum(x) / length(x) - end - @test mean(Number[1, 1.5, 2+3im]) === 1.5+1im # mixed-type array - @test mean(v for v in Number[1, 1.5, 2+3im]) === 1.5+1im - @test isnan(@inferred mean(Int[])) - @test isnan(@inferred mean(Float32[])) - @test isnan(@inferred mean(Float64[])) - @test isnan(@inferred mean(Iterators.filter(x -> true, Int[]))) - @test isnan(@inferred mean(Iterators.filter(x -> true, Float32[]))) - @test isnan(@inferred mean(Iterators.filter(x -> true, Float64[]))) - - # using a number as a "function" - @test_throws "ArgumentError: mean(f, itr) requires a function and an iterable.\nPerhaps you meant mean((x, y))?" mean(1, 2) - struct T <: Number - x::Int - end - (t::T)(y) = t.x * y - @test @inferred mean(T(2), 3) === 6.0 -end - -@testset "mean for ranges" begin - for n = 2:5 - @test mean(2:n) == mean([2:n;]) - @test mean(2:0.1:n) ≈ mean([2:0.1:n;]) - end - @test mean(2:1) === NaN - @test mean(big(2):1) isa BigFloat -end - -@testset "mean!" begin - x = rand(5, 3) - - r = similar(x, 5) - @test mean!(r, x) === r - @test r ≈ mean(x, dims=2) - - r = similar(x, 5, 1) - @test mean!(r, x) === r - @test r ≈ mean(x, dims=2) - - r = similar(x, 1, 3) - @test mean!(r, x) === r - @test r ≈ mean(x, dims=1) - - r = similar(x, 5, 3) - @test mean!(r, x) === r - @test r ≈ x - - r = similar(x, 1) - @test mean!(r, x) === r - @test r[] ≈ mean(x) - - r = similar(x, ()) - @test mean!(r, x) === r - @test r[] ≈ mean(x) - - @test_throws DimensionMismatch mean!(zeros(0, 0), x) - @test_throws DimensionMismatch mean!(zeros(0), x) - @test_throws DimensionMismatch mean!(zeros(2), x) - @test_throws DimensionMismatch mean!(zeros(2, 2), x) - @test_throws DimensionMismatch mean!(zeros(2, 3), x) - @test_throws DimensionMismatch mean!(zeros(5, 2), x) -end From 4d0dbb1fe6b9c6c80915be4a2c1db79b960bfb55 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Tue, 15 Aug 2023 19:53:15 +0200 Subject: [PATCH 13/15] Update NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 8581c1a08dd3d..20e6af89f2ec5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -59,7 +59,7 @@ Standard library changes #### Statistics -* Statistics has been promoted from being a standard library to a separate package. It now has to be explicitly installed to be used. However, functions `mean` and `mean!` are now exported directly by Base. ([#46501]) +* Statistics is now an upgradeable standard library.([#46501]) #### Distributed From c7b41e4342ef30d307666cf63fddb2cdfc1c508d Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Thu, 14 Sep 2023 18:21:46 +0200 Subject: [PATCH 14/15] Bump Pkg --- .../Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/md5 | 1 - .../Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/sha512 | 1 - .../Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/md5 | 1 + .../Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/md5 create mode 100644 deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/sha512 diff --git a/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/md5 b/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/md5 deleted file mode 100644 index cdb6872ead5bc..0000000000000 --- a/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -260d6910ccf7e9f11547146cbe433cba diff --git a/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/sha512 b/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/sha512 deleted file mode 100644 index d1fe7570b7cbf..0000000000000 --- a/deps/checksums/Pkg-b044bf6a239c5341164968a6a0d1a610b2ea431a.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -3d482fae1c474d9b209b7049cf8cd25b3f6a630ac9e823d38a2272f4063bd08e63cab619bac51ff1082c717c29bb36ff0585f38bec43be04d4a0585975b4cf91 diff --git a/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/md5 b/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/md5 new file mode 100644 index 0000000000000..69d4194df4385 --- /dev/null +++ b/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/md5 @@ -0,0 +1 @@ +2c076e4095bb473af0a0c4d2225bf85a diff --git a/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/sha512 b/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/sha512 new file mode 100644 index 0000000000000..b4ffb5f6acf2d --- /dev/null +++ b/deps/checksums/Pkg-ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5.tar.gz/sha512 @@ -0,0 +1 @@ +feffd9850f4fd46b431c411162a997b3da6425aba4b59adb54526e5d241e8a688263facea3896c04aa3c24211bd3f416f7eba366dd094bbb6bdba6b479448aad diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 849386f26df9b..671779d2b05b7 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = b044bf6a239c5341164968a6a0d1a610b2ea431a +PKG_SHA1 = ff6d645cd8bd18f4d22f6b5a24ff0234cf193fa5 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From e31fd3baa1fc46397b22a13e4ca76455fef77fe1 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Fri, 15 Sep 2023 10:50:20 +0200 Subject: [PATCH 15/15] Bump Statistics --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Statistics.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/md5 create mode 100644 deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/sha512 delete mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 delete mode 100644 deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 diff --git a/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/md5 b/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/md5 new file mode 100644 index 0000000000000..546b021cc2afb --- /dev/null +++ b/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/md5 @@ -0,0 +1 @@ +1ed739f3d108cfe880fd97fe8b4359e7 diff --git a/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/sha512 b/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/sha512 new file mode 100644 index 0000000000000..c4501f163b216 --- /dev/null +++ b/deps/checksums/Statistics-04e5d8916fae616f5ad328cf6a0b94cf883b8ba6.tar.gz/sha512 @@ -0,0 +1 @@ +f83e44af718c5dbe8346762f869796cf80ca6bb10d97c7855e5ea2863198ae650ba8462b46a92a7f6d0941f52d2739c3e10b0a7cbbc6f28e0ad3adb13a89a874 diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 deleted file mode 100644 index 7e7a889eecd29..0000000000000 --- a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -6564297a5f5971231809bf9940f68b98 diff --git a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 b/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 deleted file mode 100644 index bbe9b8bed6371..0000000000000 --- a/deps/checksums/Statistics-a3feba2bb63f06b7f40024185e9fa5f6385e2510.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -22d14c82a30f3ec7af09028423cc823808abf86918d5707fd1fcf6ca20dea7871589da9b22e462d194e86fcee380f549aeb65f585048f00bf23281786b17e040 diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index 27197b12be54c..6028e12fe19f4 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = a3feba2bb63f06b7f40024185e9fa5f6385e2510 +STATISTICS_SHA1 = 04e5d8916fae616f5ad328cf6a0b94cf883b8ba6 STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1