From 750d93bab1cfe80c86cfde8c5bfb376bc6a791c2 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 23 Oct 2016 14:50:54 -0500 Subject: [PATCH] Fix statistics functions for non-1 indices --- base/sort.jl | 15 ++++++++------- base/statistics.jl | 26 ++++++++++++++------------ test/offsetarray.jl | 7 +++++++ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/base/sort.jl b/base/sort.jl index 5f1ef98158562..08a6e829bb36a 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -2,7 +2,7 @@ module Sort -using Base: Order, Checked, copymutable, linearindices, linearindexing, viewindexing, LinearFast +using Base: Order, Checked, copymutable, linearindices, linearindexing, viewindexing, LinearFast, _length import Base.sort, @@ -66,7 +66,8 @@ issorted(itr; issorted(itr, ord(lt,by,rev,order)) function select!(v::AbstractVector, k::Union{Int,OrdinalRange}, o::Ordering) - sort!(v, 1, length(v), PartialQuickSort(k), o) + inds = indices(v, 1) + sort!(v, first(inds), last(inds), PartialQuickSort(k), o) v[k] end select!(v::AbstractVector, k::Union{Int,OrdinalRange}; @@ -187,7 +188,7 @@ searchsorted{T<:Real}(a::Range{T}, x::Real, o::DirectOrdering) = for s in [:searchsortedfirst, :searchsortedlast, :searchsorted] @eval begin - $s(v::AbstractVector, x, o::Ordering) = $s(v,x,1,length(v),o) + $s(v::AbstractVector, x, o::Ordering) = (inds = indices(v, 1); $s(v,x,first(inds),last(inds),o)) $s(v::AbstractVector, x; lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) = $s(v,x,ord(lt,by,rev,order)) @@ -432,7 +433,7 @@ function sort!(v::AbstractVector; order::Ordering=Forward) ordr = ord(lt,by,rev,order) if ordr === Forward && isa(v,Vector) && eltype(v)<:Integer - n = length(v) + n = _length(v) if n > 1 min, max = extrema(v) (diff, o1) = sub_with_overflow(max, min) @@ -478,7 +479,7 @@ sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...) ## selectperm: the permutation to sort the first k elements of an array ## selectperm(v::AbstractVector, k::Union{Integer,OrdinalRange}; kwargs...) = - selectperm!(Vector{eltype(k)}(length(v)), v, k; kwargs..., initialized=false) + selectperm!(similar(Vector{eltype(k)}, indices(v,1)), v, k; kwargs..., initialized=false) function selectperm!{I<:Integer}(ix::AbstractVector{I}, v::AbstractVector, k::Union{Int, OrdinalRange}; @@ -521,7 +522,7 @@ function sortperm(v::AbstractVector; order::Ordering=Forward) ordr = ord(lt,by,rev,order) if ordr === Forward && isa(v,Vector) && eltype(v)<:Integer - n = length(v) + n = _length(v) if n > 1 min, max = extrema(v) (diff, o1) = sub_with_overflow(max, min) @@ -553,7 +554,7 @@ function sortperm!{I<:Integer}(x::AbstractVector{I}, v::AbstractVector; order::Ordering=Forward, initialized::Bool=false) if indices(x,1) != indices(v,1) - throw(ArgumentError("index vector must be the same length as the source vector, $(indices(x,1)) != $(indices(v,1))")) + throw(ArgumentError("index vector must have the same indices as the source vector, $(indices(x,1)) != $(indices(v,1))")) end if !initialized @inbounds for i = indices(v,1) diff --git a/base/statistics.jl b/base/statistics.jl index 05805f2a2db50..e3766ef5cecaa 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -24,12 +24,12 @@ function mean(f::Callable, iterable) return total/count end mean(iterable) = mean(identity, iterable) -mean(f::Callable, A::AbstractArray) = sum(f, A) / length(A) -mean(A::AbstractArray) = sum(A) / length(A) +mean(f::Callable, A::AbstractArray) = sum(f, A) / _length(A) +mean(A::AbstractArray) = sum(A) / _length(A) function mean!{T}(R::AbstractArray{T}, A::AbstractArray) sum!(R, A; init=true) - scale!(R, length(R) / length(A)) + scale!(R, _length(R) / _length(A)) return R end @@ -140,7 +140,7 @@ function centralize_sumabs2!{S,T,N}(R::AbstractArray{S}, A::AbstractArray{T,N}, end function varm{T}(A::AbstractArray{T}, m::Number; corrected::Bool=true) - n = length(A) + n = _length(A) n == 0 && return convert(real(momenttype(T)), NaN) n == 1 && return convert(real(momenttype(T)), abs2(A[1] - m)/(1 - Int(corrected))) return centralize_sumabs2(A, m) / (n - Int(corrected)) @@ -150,7 +150,7 @@ function varm!{S}(R::AbstractArray{S}, A::AbstractArray, m::AbstractArray; corre if isempty(A) fill!(R, convert(S, NaN)) else - rn = div(length(A), length(R)) - Int(corrected) + rn = div(_length(A), _length(R)) - Int(corrected) scale!(centralize_sumabs2!(R, A, m), convert(S, 1/rn)) end return R @@ -282,7 +282,7 @@ stdm(iterable, m::Number; corrected::Bool=true) = _conj{T<:Real}(x::AbstractArray{T}) = x _conj(x::AbstractArray) = conj(x) -_getnobs(x::AbstractVector, vardim::Int) = length(x) +_getnobs(x::AbstractVector, vardim::Int) = _length(x) _getnobs(x::AbstractMatrix, vardim::Int) = size(x, vardim) function _getnobs(x::AbstractVecOrMat, y::AbstractVecOrMat, vardim::Int) @@ -309,11 +309,11 @@ unscaled_covzm(x::AbstractMatrix, y::AbstractMatrix, vardim::Int) = # covzm (with centered data) -covzm(x::AbstractVector, corrected::Bool=true) = unscaled_covzm(x) / (length(x) - Int(corrected)) +covzm(x::AbstractVector, corrected::Bool=true) = unscaled_covzm(x) / (_length(x) - Int(corrected)) covzm(x::AbstractMatrix, vardim::Int=1, corrected::Bool=true) = scale!(unscaled_covzm(x, vardim), inv(size(x,vardim) - Int(corrected))) covzm(x::AbstractVector, y::AbstractVector, corrected::Bool=true) = - unscaled_covzm(x, y) / (length(x) - Int(corrected)) + unscaled_covzm(x, y) / (_length(x) - Int(corrected)) covzm(x::AbstractVecOrMat, y::AbstractVecOrMat, vardim::Int=1, corrected::Bool=true) = scale!(unscaled_covzm(x, y, vardim), inv(_getnobs(x, y, vardim) - Int(corrected))) @@ -568,16 +568,18 @@ function median!{T}(v::AbstractVector{T}) isnan(x) && return x end end - n = length(v) + inds = indices(v, 1) + n = length(inds) + mid = div(first(inds)+last(inds),2) if isodd(n) - return middle(select!(v,div(n+1,2))) + return middle(select!(v,mid)) else - m = select!(v, div(n,2):div(n,2)+1) + m = select!(v, mid:mid+1) return middle(m[1], m[2]) end end median!{T}(v::AbstractArray{T}) = median!(vec(v)) -median{T}(v::AbstractArray{T}) = median!(copy!(Array{T,1}(length(v)), v)) +median{T}(v::AbstractArray{T}) = median!(copy!(Array{T,1}(_length(v)), v)) """ median(v[, region]) diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 2980185182e88..88b4a9097d0cd 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -310,6 +310,13 @@ I,J,N = findnz(z) @test find(x->x>0, h) == [-1,1] @test find(x->x<0, h) == [-2,0] @test find(x->x==0, h) == [2] +@test mean(A_3_3) == median(A_3_3) == 5 +@test mean(x->2x, A_3_3) == 10 +@test mean(A_3_3, 1) == median(A_3_3, 1) == OffsetArray([2 5 8], (0,A_3_3.offsets[2])) +@test mean(A_3_3, 2) == median(A_3_3, 2) == OffsetArray([4,5,6]'', (A_3_3.offsets[1],0)) +@test var(A_3_3) == 7.5 +@test std(A_3_3, 1) == OffsetArray([1 1 1], (0,A_3_3.offsets[2])) +@test std(A_3_3, 2) == OffsetArray([3,3,3]'', (A_3_3.offsets[1],0)) @test_approx_eq vecnorm(v) vecnorm(parent(v)) @test_approx_eq vecnorm(A) vecnorm(parent(A))