From 55d93f74b0378b361cd8757a2a1e20268242fb20 Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Wed, 24 Mar 2021 14:51:26 +0100 Subject: [PATCH] Fix NaN and missing detection in quantile() (#72) When `sort=false`, we only partially sort the input, so `NaN`/`missing` is not guaranteed to be in the last position. Also avoid throwing errors for non-`Number` types, for which `isnan` may not be defined. --- src/Statistics.jl | 6 ++++-- test/runtests.jl | 11 +++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Statistics.jl b/src/Statistics.jl index 0d247608..ac2d2426 100644 --- a/src/Statistics.jl +++ b/src/Statistics.jl @@ -971,8 +971,10 @@ function _quantilesort!(v::AbstractArray, sorted::Bool, minp::Real, maxp::Real) # only need to perform partial sort sort!(v, 1, lv, Base.Sort.PartialQuickSort(lo:hi), Base.Sort.Forward) end - ismissing(v[end]) && throw(ArgumentError("quantiles are undefined in presence of missing values")) - isnan(v[end]) && throw(ArgumentError("quantiles are undefined in presence of NaNs")) + if (sorted && (ismissing(v[end]) || (v[end] isa Number && isnan(v[end])))) || + any(x -> ismissing(x) || (x isa Number && isnan(x)), v) + throw(ArgumentError("quantiles are undefined in presence of NaNs or missing values")) + end return v end diff --git a/test/runtests.jl b/test/runtests.jl index 4ac7c52d..e0377b46 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -571,8 +571,15 @@ end @test quantile(Any[1, Float16(2), 3], Float16(0.5)) isa Float16 @test quantile(Any[1, big(2), 3], Float16(0.5)) isa BigFloat - @test_throws ArgumentError quantile([1, missing], 0.5) - @test_throws ArgumentError quantile([1, NaN], 0.5) + # Need a large vector to actually check consequences of partial sorting + x = rand(50) + for sorted in (false, true) + x[10] = NaN + @test_throws ArgumentError quantile(x, 0.5, sorted=sorted) + x = Vector{Union{Float64, Missing}}(x) + x[10] = missing + @test_throws ArgumentError quantile(x, 0.5, sorted=sorted) + end @test quantile(skipmissing([1, missing, 2]), 0.5) === 1.5 @test quantile([1], 0.5) === 1.0