From 977a6d90546e9a0842645bc35f4b8f36f110f887 Mon Sep 17 00:00:00 2001 From: feiyang Date: Sat, 18 Jan 2025 13:14:00 +0000 Subject: [PATCH 01/10] impl expr.list().quantile for duration floats, decimals, and ints --- .../legacy/kernels/rolling/no_nulls/mod.rs | 18 +++++++++++++ crates/polars-arrow/src/legacy/prelude.rs | 2 +- .../src/series/implementations/decimal.rs | 7 +++++ .../src/series/implementations/duration.rs | 7 +++++ .../src/series/implementations/floats.rs | 7 +++++ .../src/series/implementations/mod.rs | 7 +++++ crates/polars-core/src/series/series_trait.rs | 6 +++++ .../src/chunked_array/list/dispersion.rs | 27 +++++++++++++++++++ .../src/chunked_array/list/namespace.rs | 5 ++++ .../polars-plan/src/dsl/function_expr/list.rs | 8 ++++++ crates/polars-plan/src/dsl/list.rs | 5 ++++ 11 files changed, 98 insertions(+), 1 deletion(-) diff --git a/crates/polars-arrow/src/legacy/kernels/rolling/no_nulls/mod.rs b/crates/polars-arrow/src/legacy/kernels/rolling/no_nulls/mod.rs index 7abe2455e61f..6ac9e462c9f4 100644 --- a/crates/polars-arrow/src/legacy/kernels/rolling/no_nulls/mod.rs +++ b/crates/polars-arrow/src/legacy/kernels/rolling/no_nulls/mod.rs @@ -4,6 +4,7 @@ mod quantile; mod sum; mod variance; use std::fmt::Debug; +use std::hash::{Hash, Hasher}; pub use mean::*; pub use min_max::*; @@ -83,6 +84,23 @@ pub enum QuantileMethod { Equiprobable, } + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct QuantileOptions { + pub prob: f64, + pub method: QuantileMethod +} + +impl Eq for QuantileOptions {} + +impl Hash for QuantileOptions { + fn hash(&self, state: &mut H) { + self.prob.to_bits().hash(state); + self.method.hash(state); + } +} + #[deprecated(note = "use QuantileMethod instead")] pub type QuantileInterpolOptions = QuantileMethod; diff --git a/crates/polars-arrow/src/legacy/prelude.rs b/crates/polars-arrow/src/legacy/prelude.rs index 6afeb0c6c9be..4786be70581b 100644 --- a/crates/polars-arrow/src/legacy/prelude.rs +++ b/crates/polars-arrow/src/legacy/prelude.rs @@ -2,7 +2,7 @@ use crate::array::{BinaryArray, ListArray, Utf8Array}; pub use crate::legacy::array::default_arrays::*; pub use crate::legacy::array::*; pub use crate::legacy::index::*; -pub use crate::legacy::kernels::rolling::no_nulls::QuantileMethod; +pub use crate::legacy::kernels::rolling::no_nulls::{QuantileMethod, QuantileOptions}; pub use crate::legacy::kernels::rolling::{ RollingFnParams, RollingQuantileParams, RollingVarParams, }; diff --git a/crates/polars-core/src/series/implementations/decimal.rs b/crates/polars-core/src/series/implementations/decimal.rs index 6e477ccf6c3f..4426e82eef50 100644 --- a/crates/polars-core/src/series/implementations/decimal.rs +++ b/crates/polars-core/src/series/implementations/decimal.rs @@ -396,6 +396,13 @@ impl SeriesTrait for SeriesWrap { self.0.mean().map(|v| v / self.scale_factor() as f64) } + fn quantile(&self, quantile: f64, method: QuantileMethod) -> PolarsResult> { + polars_ensure!((0.0..=1.0).contains(&quantile), + ComputeError: "quantile should be between 0.0 and 1.0", + ); + Ok(self.0.quantile(quantile, method).unwrap().map(|v| v as f64)) + } + fn median(&self) -> Option { self.0.median().map(|v| v / self.scale_factor() as f64) } diff --git a/crates/polars-core/src/series/implementations/duration.rs b/crates/polars-core/src/series/implementations/duration.rs index 51426f1b94e6..3f3912b4ba60 100644 --- a/crates/polars-core/src/series/implementations/duration.rs +++ b/crates/polars-core/src/series/implementations/duration.rs @@ -307,6 +307,13 @@ impl SeriesTrait for SeriesWrap { self.0.median() } + fn quantile(&self, quantile: f64, method: QuantileMethod) -> PolarsResult> { + polars_ensure!((0.0..=1.0).contains(&quantile), + ComputeError: "quantile should be between 0.0 and 1.0", + ); + Ok(self.0.quantile(quantile, method).unwrap().map(|v| v as f64)) + } + fn std(&self, ddof: u8) -> Option { self.0.std(ddof) } diff --git a/crates/polars-core/src/series/implementations/floats.rs b/crates/polars-core/src/series/implementations/floats.rs index 9ccbb1d8d958..645723785113 100644 --- a/crates/polars-core/src/series/implementations/floats.rs +++ b/crates/polars-core/src/series/implementations/floats.rs @@ -206,6 +206,13 @@ macro_rules! impl_dyn_series { self.0.median().map(|v| v as f64) } + fn quantile(&self, quantile: f64, method: QuantileMethod) -> PolarsResult> { + polars_ensure!((0.0..=1.0).contains(&quantile), + ComputeError: "quantile should be between 0.0 and 1.0", + ); + Ok(self.0.quantile(quantile, method).unwrap().map(|v| v as f64)) + } + fn std(&self, ddof: u8) -> Option { self.0.std(ddof) } diff --git a/crates/polars-core/src/series/implementations/mod.rs b/crates/polars-core/src/series/implementations/mod.rs index 9df0e7695127..48c488d0b7f7 100644 --- a/crates/polars-core/src/series/implementations/mod.rs +++ b/crates/polars-core/src/series/implementations/mod.rs @@ -276,6 +276,13 @@ macro_rules! impl_dyn_series { self.0.median() } + fn quantile(&self, quantile: f64, method: QuantileMethod) -> PolarsResult> { + polars_ensure!((0.0..=1.0).contains(&quantile), + ComputeError: "quantile should be between 0.0 and 1.0", + ); + Ok(self.0.quantile(quantile, method).unwrap().map(|v| v as f64)) + } + fn std(&self, ddof: u8) -> Option { self.0.std(ddof) } diff --git a/crates/polars-core/src/series/series_trait.rs b/crates/polars-core/src/series/series_trait.rs index c1b8d3f97764..9c2a319be2a5 100644 --- a/crates/polars-core/src/series/series_trait.rs +++ b/crates/polars-core/src/series/series_trait.rs @@ -359,6 +359,12 @@ pub trait SeriesTrait: None } + /// Returns the quantile value in the array + /// Returns a result