#![allow(ambiguous_glob_reexports)]
#[cfg(feature = "dtype-categorical")]
pub mod cat;
#[cfg(feature = "dtype-categorical")]
pub use cat::*;
#[cfg(feature = "rolling_window_by")]
pub(crate) use polars_time::prelude::*;
mod arithmetic;
mod arity;
#[cfg(feature = "dtype-array")]
mod array;
pub mod binary;
#[cfg(feature = "bitwise")]
mod bitwise;
mod builder_dsl;
pub use builder_dsl::*;
mod datatype_expr;
#[cfg(feature = "temporal")]
pub mod dt;
mod expr;
mod format;
mod from;
pub mod function_expr;
pub mod functions;
mod list;
mod match_to_schema;
#[cfg(feature = "meta")]
mod meta;
mod name;
mod options;
#[cfg(feature = "python")]
pub mod python_dsl;
#[cfg(feature = "random")]
mod random;
mod scan_sources;
mod selector;
mod statistics;
#[cfg(feature = "strings")]
pub mod string;
#[cfg(feature = "dtype-struct")]
mod struct_;
pub mod udf;
use std::fmt::Debug;
use std::sync::Arc;
mod plan;
pub use arity::*;
#[cfg(feature = "dtype-array")]
pub use array::*;
pub use datatype_expr::DataTypeExpr;
pub use expr::*;
pub use function_expr::*;
pub use functions::*;
pub use list::*;
pub use match_to_schema::*;
#[cfg(feature = "meta")]
pub use meta::*;
pub use name::*;
pub use options::*;
pub use plan::*;
use polars_compute::rolling::QuantileMethod;
use polars_core::chunked_array::cast::CastOptions;
use polars_core::error::feature_gated;
use polars_core::prelude::*;
use polars_core::series::IsSorted;
#[cfg(feature = "diff")]
use polars_core::series::ops::NullBehavior;
#[cfg(feature = "is_close")]
use polars_utils::total_ord::TotalOrdWrap;
pub use selector::{DataTypeSelector, Selector, TimeUnitSet, TimeZoneSet};
#[cfg(feature = "dtype-struct")]
pub use struct_::*;
pub use udf::UserDefinedFunction;
mod file_scan;
pub use file_scan::*;
pub use scan_sources::{ScanSource, ScanSourceIter, ScanSourceRef, ScanSources};
pub use crate::plans::lit;
use crate::prelude::*;
impl Expr {
pub fn eq<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::Eq, other.into())
}
pub fn eq_missing<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::EqValidity, other.into())
}
pub fn neq<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::NotEq, other.into())
}
pub fn neq_missing<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::NotEqValidity, other.into())
}
pub fn lt<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::Lt, other.into())
}
pub fn gt<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::Gt, other.into())
}
pub fn gt_eq<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::GtEq, other.into())
}
pub fn lt_eq<E: Into<Expr>>(self, other: E) -> Expr {
binary_expr(self, Operator::LtEq, other.into())
}
#[allow(clippy::should_implement_trait)]
pub fn not(self) -> Expr {
self.map_unary(BooleanFunction::Not)
}
pub fn alias<S>(self, name: S) -> Expr
where
S: Into<PlSmallStr>,
{
Expr::Alias(Arc::new(self), name.into())
}
#[allow(clippy::wrong_self_convention)]
pub fn is_null(self) -> Self {
self.map_unary(BooleanFunction::IsNull)
}
#[allow(clippy::wrong_self_convention)]
pub fn is_not_null(self) -> Self {
self.map_unary(BooleanFunction::IsNotNull)
}
pub fn drop_nulls(self) -> Self {
self.map_unary(FunctionExpr::DropNulls)
}
pub fn drop_nans(self) -> Self {
self.map_unary(FunctionExpr::DropNans)
}
pub fn n_unique(self) -> Self {
AggExpr::NUnique(Arc::new(self)).into()
}
pub fn first(self) -> Self {
AggExpr::First(Arc::new(self)).into()
}
pub fn last(self) -> Self {
AggExpr::Last(Arc::new(self)).into()
}
pub fn implode(self) -> Self {
AggExpr::Implode(Arc::new(self)).into()
}
pub fn quantile(self, quantile: Expr, method: QuantileMethod) -> Self {
AggExpr::Quantile {
expr: Arc::new(self),
quantile: Arc::new(quantile),
method,
}
.into()
}
pub fn agg_groups(self) -> Self {
AggExpr::AggGroups(Arc::new(self)).into()
}
pub fn flatten(self) -> Self {
self.explode()
}
pub fn explode(self) -> Self {
Expr::Explode {
input: Arc::new(self),
skip_empty: false,
}
}
pub fn slice<E: Into<Expr>, F: Into<Expr>>(self, offset: E, length: F) -> Self {
Expr::Slice {
input: Arc::new(self),
offset: Arc::new(offset.into()),
length: Arc::new(length.into()),
}
}
pub fn append<E: Into<Expr>>(self, other: E, upcast: bool) -> Self {
self.map_binary(FunctionExpr::Append { upcast }, other.into())
}
pub fn rechunk(self) -> Self {
self.map_unary(FunctionExpr::Rechunk)
}
pub fn head(self, length: Option<usize>) -> Self {
self.slice(lit(0), lit(length.unwrap_or(10) as u64))
}
pub fn tail(self, length: Option<usize>) -> Self {
let len = length.unwrap_or(10);
self.slice(lit(-(len as i64)), lit(len as u64))
}
pub fn unique(self) -> Self {
self.map_unary(FunctionExpr::Unique(false))
}
pub fn unique_stable(self) -> Self {
self.map_unary(FunctionExpr::Unique(true))
}
pub fn arg_unique(self) -> Self {
self.map_unary(FunctionExpr::ArgUnique)
}
pub fn arg_min(self) -> Self {
self.map_unary(FunctionExpr::ArgMin)
}
pub fn arg_max(self) -> Self {
self.map_unary(FunctionExpr::ArgMax)
}
pub fn arg_sort(self, descending: bool, nulls_last: bool) -> Self {
self.map_unary(FunctionExpr::ArgSort {
descending,
nulls_last,
})
}
#[cfg(feature = "index_of")]
pub fn index_of<E: Into<Expr>>(self, element: E) -> Expr {
self.map_binary(FunctionExpr::IndexOf, element.into())
}
#[cfg(feature = "search_sorted")]
pub fn search_sorted<E: Into<Expr>>(
self,
element: E,
side: SearchSortedSide,
descending: bool,
) -> Expr {
self.map_binary(
FunctionExpr::SearchSorted { side, descending },
element.into(),
)
}
pub fn strict_cast(self, dtype: impl Into<DataTypeExpr>) -> Self {
Expr::Cast {
expr: Arc::new(self),
dtype: dtype.into(),
options: CastOptions::Strict,
}
}
pub fn cast(self, dtype: impl Into<DataTypeExpr>) -> Self {
Expr::Cast {
expr: Arc::new(self),
dtype: dtype.into(),
options: CastOptions::NonStrict,
}
}
pub fn cast_with_options(
self,
dtype: impl Into<DataTypeExpr>,
cast_options: CastOptions,
) -> Self {
Expr::Cast {
expr: Arc::new(self),
dtype: dtype.into(),
options: cast_options,
}
}
pub fn gather<E: Into<Expr>>(self, idx: E) -> Self {
Expr::Gather {
expr: Arc::new(self),
idx: Arc::new(idx.into()),
returns_scalar: false,
}
}
pub fn get<E: Into<Expr>>(self, idx: E) -> Self {
Expr::Gather {
expr: Arc::new(self),
idx: Arc::new(idx.into()),
returns_scalar: true,
}
}
pub fn sort(self, options: SortOptions) -> Self {
Expr::Sort {
expr: Arc::new(self),
options,
}
}
#[cfg(feature = "top_k")]
pub fn top_k(self, k: Expr) -> Self {
self.map_binary(FunctionExpr::TopK { descending: false }, k)
}
#[cfg(feature = "top_k")]
pub fn top_k_by<K: Into<Expr>, E: AsRef<[IE]>, IE: Into<Expr> + Clone>(
self,
k: K,
by: E,
descending: Vec<bool>,
) -> Self {
self.map_n_ary(
FunctionExpr::TopKBy { descending },
[k.into()]
.into_iter()
.chain(by.as_ref().iter().map(|e| -> Expr { e.clone().into() })),
)
}
#[cfg(feature = "top_k")]
pub fn bottom_k(self, k: Expr) -> Self {
self.map_binary(FunctionExpr::TopK { descending: true }, k)
}
#[cfg(feature = "top_k")]
pub fn bottom_k_by<K: Into<Expr>, E: AsRef<[IE]>, IE: Into<Expr> + Clone>(
self,
k: K,
by: E,
descending: Vec<bool>,
) -> Self {
let descending = descending.into_iter().map(|x| !x).collect();
self.map_n_ary(
FunctionExpr::TopKBy { descending },
[k.into()]
.into_iter()
.chain(by.as_ref().iter().map(|e| -> Expr { e.clone().into() })),
)
}
pub fn reverse(self) -> Self {
self.map_unary(FunctionExpr::Reverse)
}
pub fn map<F, DT>(self, function: F, output_type: DT) -> Self
where
F: Fn(Column) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &Field) -> PolarsResult<Field> + 'static + Send + Sync,
{
self.map_with_fmt_str(function, output_type, "map")
}
pub fn map_with_fmt_str<F, DT>(
self,
function: F,
output_type: DT,
fmt_str: impl Into<PlSmallStr>,
) -> Self
where
F: Fn(Column) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &Field) -> PolarsResult<Field> + 'static + Send + Sync,
{
let f = BaseColumnUdf::new(
move |c: &mut [Column]| function(std::mem::take(&mut c[0])),
move |schema: &Schema, fields: &[Field]| output_type(schema, &fields[0]),
);
let options =
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::OPTIONAL_RE_ENTRANT);
let fmt_str = Box::new(fmt_str.into());
Expr::AnonymousFunction {
input: vec![self],
function: new_column_udf(f),
options,
fmt_str,
}
}
pub fn agg_with_fmt_str<F, DT>(
self,
function: F,
output_type: DT,
fmt_str: impl Into<PlSmallStr>,
) -> Self
where
F: Fn(Column) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &Field) -> PolarsResult<Field> + 'static + Send + Sync,
{
let f = BaseColumnUdf::new(
move |c: &mut [Column]| function(std::mem::take(&mut c[0])),
move |schema: &Schema, fields: &[Field]| output_type(schema, &fields[0]),
);
let options = FunctionOptions::aggregation();
let fmt_str = Box::new(fmt_str.into());
Expr::AnonymousFunction {
input: vec![self],
function: new_column_udf(f),
options,
fmt_str,
}
}
pub fn apply_with_fmt_str<F, DT>(
self,
function: F,
output_type: DT,
fmt_str: impl Into<PlSmallStr>,
) -> Self
where
F: Fn(Column) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &Field) -> PolarsResult<Field> + 'static + Send + Sync,
{
let f = BaseColumnUdf::new(
move |c: &mut [Column]| function(std::mem::take(&mut c[0])),
move |schema: &Schema, fields: &[Field]| output_type(schema, &fields[0]),
);
let options = FunctionOptions::groupwise();
let fmt_str = Box::new(fmt_str.into());
Expr::AnonymousFunction {
input: vec![self],
function: new_column_udf(f),
options,
fmt_str,
}
}
pub fn map_many<F, DT>(self, function: F, arguments: &[Expr], output_type: DT) -> Self
where
F: Fn(&mut [Column]) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &[Field]) -> PolarsResult<Field> + 'static + Send + Sync,
{
let mut input = vec![self];
input.extend_from_slice(arguments);
let function = BaseColumnUdf::new(function, output_type);
let options = FunctionOptions::elementwise();
Expr::AnonymousFunction {
input,
function: new_column_udf(function),
options,
fmt_str: Box::new(PlSmallStr::EMPTY),
}
}
pub fn apply<F, DT>(self, function: F, output_type: DT) -> Self
where
F: Fn(Column) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &Field) -> PolarsResult<Field> + 'static + Send + Sync,
{
self.apply_with_fmt_str(function, output_type, PlSmallStr::EMPTY)
}
pub fn apply_many<F, DT>(self, function: F, arguments: &[Expr], output_type: DT) -> Self
where
F: Fn(&mut [Column]) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &[Field]) -> PolarsResult<Field> + 'static + Send + Sync,
{
let mut input = vec![self];
input.extend_from_slice(arguments);
let function = BaseColumnUdf::new(function, output_type);
let options = FunctionOptions::groupwise();
Expr::AnonymousFunction {
input,
function: new_column_udf(function),
options,
fmt_str: Box::new(PlSmallStr::EMPTY),
}
}
#[allow(clippy::wrong_self_convention)]
pub fn is_finite(self) -> Self {
self.map_unary(BooleanFunction::IsFinite)
}
#[allow(clippy::wrong_self_convention)]
pub fn is_infinite(self) -> Self {
self.map_unary(BooleanFunction::IsInfinite)
}
pub fn is_nan(self) -> Self {
self.map_unary(BooleanFunction::IsNan)
}
pub fn is_not_nan(self) -> Self {
self.map_unary(BooleanFunction::IsNotNan)
}
pub fn shift(self, n: Expr) -> Self {
self.map_binary(FunctionExpr::Shift, n)
}
pub fn shift_and_fill<E: Into<Expr>, IE: Into<Expr>>(self, n: E, fill_value: IE) -> Self {
self.map_ternary(FunctionExpr::ShiftAndFill, n.into(), fill_value.into())
}
#[cfg(feature = "cum_agg")]
pub fn cumulative_eval(self, evaluation: Expr, min_samples: usize) -> Self {
Expr::Eval {
expr: Arc::new(self),
evaluation: Arc::new(evaluation),
variant: EvalVariant::Cumulative { min_samples },
}
}
#[cfg(feature = "cum_agg")]
pub fn cum_count(self, reverse: bool) -> Self {
self.map_unary(FunctionExpr::CumCount { reverse })
}
#[cfg(feature = "cum_agg")]
pub fn cum_sum(self, reverse: bool) -> Self {
self.map_unary(FunctionExpr::CumSum { reverse })
}
#[cfg(feature = "cum_agg")]
pub fn cum_prod(self, reverse: bool) -> Self {
self.map_unary(FunctionExpr::CumProd { reverse })
}
#[cfg(feature = "cum_agg")]
pub fn cum_min(self, reverse: bool) -> Self {
self.map_unary(FunctionExpr::CumMin { reverse })
}
#[cfg(feature = "cum_agg")]
pub fn cum_max(self, reverse: bool) -> Self {
self.map_unary(FunctionExpr::CumMax { reverse })
}
pub fn product(self) -> Self {
self.map_unary(FunctionExpr::Product)
}
#[cfg(feature = "round_series")]
pub fn round(self, decimals: u32, mode: RoundMode) -> Self {
self.map_unary(FunctionExpr::Round { decimals, mode })
}
#[cfg(feature = "round_series")]
pub fn round_sig_figs(self, digits: i32) -> Self {
self.map_unary(FunctionExpr::RoundSF { digits })
}
#[cfg(feature = "round_series")]
pub fn floor(self) -> Self {
self.map_unary(FunctionExpr::Floor)
}
#[cfg(feature = "round_series")]
pub fn pi() -> Self {
lit(std::f64::consts::PI)
}
#[cfg(feature = "round_series")]
pub fn ceil(self) -> Self {
self.map_unary(FunctionExpr::Ceil)
}
#[cfg(feature = "round_series")]
pub fn clip(self, min: Expr, max: Expr) -> Self {
self.map_ternary(
FunctionExpr::Clip {
has_min: true,
has_max: true,
},
min,
max,
)
}
#[cfg(feature = "round_series")]
pub fn clip_max(self, max: Expr) -> Self {
self.map_binary(
FunctionExpr::Clip {
has_min: false,
has_max: true,
},
max,
)
}
#[cfg(feature = "round_series")]
pub fn clip_min(self, min: Expr) -> Self {
self.map_binary(
FunctionExpr::Clip {
has_min: true,
has_max: false,
},
min,
)
}
#[cfg(feature = "abs")]
pub fn abs(self) -> Self {
self.map_unary(FunctionExpr::Abs)
}
pub fn over<E: AsRef<[IE]>, IE: Into<Expr> + Clone>(self, partition_by: E) -> Self {
self.over_with_options(Some(partition_by), None, Default::default())
.expect("We explicitly passed `partition_by`")
}
pub fn over_with_options<E: AsRef<[IE]>, IE: Into<Expr> + Clone>(
self,
partition_by: Option<E>,
order_by: Option<(E, SortOptions)>,
options: WindowMapping,
) -> PolarsResult<Self> {
polars_ensure!(partition_by.is_some() || order_by.is_some(), InvalidOperation: "At least one of `partition_by` and `order_by` must be specified in `over`");
let partition_by = if let Some(partition_by) = partition_by {
partition_by
.as_ref()
.iter()
.map(|e| e.clone().into())
.collect()
} else {
vec![lit(1)]
};
let order_by = order_by.map(|(e, options)| {
let e = e.as_ref();
let e = if e.len() == 1 {
Arc::new(e[0].clone().into())
} else {
feature_gated!["dtype-struct", {
let e = e.iter().map(|e| e.clone().into()).collect::<Vec<_>>();
Arc::new(as_struct(e))
}]
};
(e, options)
});
Ok(Expr::Window {
function: Arc::new(self),
partition_by,
order_by,
options: options.into(),
})
}
#[cfg(feature = "dynamic_group_by")]
pub fn rolling(self, options: RollingGroupOptions) -> Self {
let index_col = col(options.index_column.clone());
Expr::Window {
function: Arc::new(self),
partition_by: vec![index_col],
order_by: None,
options: WindowType::Rolling(options),
}
}
fn fill_null_impl(self, fill_value: Expr) -> Self {
self.map_binary(FunctionExpr::FillNull, fill_value)
}
pub fn fill_null<E: Into<Expr>>(self, fill_value: E) -> Self {
self.fill_null_impl(fill_value.into())
}
pub fn fill_null_with_strategy(self, strategy: FillNullStrategy) -> Self {
self.map_unary(FunctionExpr::FillNullWithStrategy(strategy))
}
pub fn fill_nan<E: Into<Expr>>(self, fill_value: E) -> Self {
when(self.clone().is_not_nan().or(self.clone().is_null()))
.then(self)
.otherwise(fill_value.into())
}
pub fn count(self) -> Self {
AggExpr::Count {
input: Arc::new(self),
include_nulls: false,
}
.into()
}
pub fn len(self) -> Self {
AggExpr::Count {
input: Arc::new(self),
include_nulls: true,
}
.into()
}
#[allow(clippy::wrong_self_convention)]
#[cfg(feature = "is_unique")]
pub fn is_duplicated(self) -> Self {
self.map_unary(BooleanFunction::IsDuplicated)
}
#[allow(clippy::wrong_self_convention)]
#[cfg(feature = "is_between")]
pub fn is_between<E: Into<Expr>>(self, lower: E, upper: E, closed: ClosedInterval) -> Self {
self.map_ternary(
BooleanFunction::IsBetween { closed },
lower.into(),
upper.into(),
)
}
#[allow(clippy::wrong_self_convention)]
#[cfg(feature = "is_unique")]
pub fn is_unique(self) -> Self {
self.map_unary(BooleanFunction::IsUnique)
}
#[allow(clippy::wrong_self_convention)]
#[cfg(feature = "is_close")]
pub fn is_close<E: Into<Expr>>(
self,
expr: E,
abs_tol: f64,
rel_tol: f64,
nans_equal: bool,
) -> Self {
self.map_binary(
BooleanFunction::IsClose {
abs_tol: TotalOrdWrap(abs_tol),
rel_tol: TotalOrdWrap(rel_tol),
nans_equal,
},
expr.into(),
)
}
#[cfg(feature = "approx_unique")]
pub fn approx_n_unique(self) -> Self {
self.map_unary(FunctionExpr::ApproxNUnique)
}
pub fn and<E: Into<Expr>>(self, expr: E) -> Self {
binary_expr(self, Operator::And, expr.into())
}
pub fn xor<E: Into<Expr>>(self, expr: E) -> Self {
binary_expr(self, Operator::Xor, expr.into())
}
pub fn or<E: Into<Expr>>(self, expr: E) -> Self {
binary_expr(self, Operator::Or, expr.into())
}
pub fn logical_or<E: Into<Expr>>(self, expr: E) -> Self {
binary_expr(self, Operator::LogicalOr, expr.into())
}
pub fn logical_and<E: Into<Expr>>(self, expr: E) -> Self {
binary_expr(self, Operator::LogicalAnd, expr.into())
}
pub fn filter<E: Into<Expr>>(self, predicate: E) -> Self {
Expr::Filter {
input: Arc::new(self),
by: Arc::new(predicate.into()),
}
}
#[allow(clippy::wrong_self_convention)]
#[cfg(feature = "is_in")]
pub fn is_in<E: Into<Expr>>(self, other: E, nulls_equal: bool) -> Self {
let other = other.into();
let function = BooleanFunction::IsIn { nulls_equal };
let function = function.into();
Expr::Function {
input: vec![self, other],
function,
}
}
pub fn sort_by<E: AsRef<[IE]>, IE: Into<Expr> + Clone>(
self,
by: E,
sort_options: SortMultipleOptions,
) -> Expr {
let by = by.as_ref().iter().map(|e| e.clone().into()).collect();
Expr::SortBy {
expr: Arc::new(self),
by,
sort_options,
}
}
#[cfg(feature = "repeat_by")]
pub fn repeat_by<E: Into<Expr>>(self, by: E) -> Expr {
self.map_binary(FunctionExpr::RepeatBy, by.into())
}
#[cfg(feature = "is_first_distinct")]
#[allow(clippy::wrong_self_convention)]
pub fn is_first_distinct(self) -> Expr {
self.map_unary(BooleanFunction::IsFirstDistinct)
}
#[cfg(feature = "is_last_distinct")]
#[allow(clippy::wrong_self_convention)]
pub fn is_last_distinct(self) -> Expr {
self.map_unary(BooleanFunction::IsLastDistinct)
}
fn dot_impl(self, other: Expr) -> Expr {
(self * other).sum()
}
pub fn dot<E: Into<Expr>>(self, other: E) -> Expr {
self.dot_impl(other.into())
}
#[cfg(feature = "mode")]
pub fn mode(self) -> Expr {
self.map_unary(FunctionExpr::Mode)
}
#[cfg(feature = "interpolate")]
pub fn interpolate(self, method: InterpolationMethod) -> Expr {
self.map_unary(FunctionExpr::Interpolate(method))
}
#[cfg(feature = "rolling_window_by")]
#[allow(clippy::type_complexity)]
fn finish_rolling_by(
self,
by: Expr,
options: RollingOptionsDynamicWindow,
rolling_function_by: RollingFunctionBy,
) -> Expr {
self.map_binary(
FunctionExpr::RollingExprBy {
function_by: rolling_function_by,
options,
},
by,
)
}
#[cfg(feature = "interpolate_by")]
pub fn interpolate_by(self, by: Expr) -> Expr {
self.map_binary(FunctionExpr::InterpolateBy, by)
}
#[cfg(feature = "rolling_window")]
#[allow(clippy::type_complexity)]
fn finish_rolling(
self,
options: RollingOptionsFixedWindow,
rolling_function: RollingFunction,
) -> Expr {
self.map_unary(FunctionExpr::RollingExpr {
function: rolling_function,
options,
})
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_min_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::MinBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_max_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::MaxBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_mean_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::MeanBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_sum_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::SumBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_quantile_by(
self,
by: Expr,
method: QuantileMethod,
quantile: f64,
mut options: RollingOptionsDynamicWindow,
) -> Expr {
use polars_compute::rolling::{RollingFnParams, RollingQuantileParams};
options.fn_params = Some(RollingFnParams::Quantile(RollingQuantileParams {
prob: quantile,
method,
}));
self.finish_rolling_by(by, options, RollingFunctionBy::QuantileBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_var_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::VarBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_std_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.finish_rolling_by(by, options, RollingFunctionBy::StdBy)
}
#[cfg(feature = "rolling_window_by")]
pub fn rolling_median_by(self, by: Expr, options: RollingOptionsDynamicWindow) -> Expr {
self.rolling_quantile_by(by, QuantileMethod::Linear, 0.5, options)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_min(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Min)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_max(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Max)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_mean(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Mean)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_sum(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Sum)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_median(self, options: RollingOptionsFixedWindow) -> Expr {
self.rolling_quantile(QuantileMethod::Linear, 0.5, options)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_quantile(
self,
method: QuantileMethod,
quantile: f64,
mut options: RollingOptionsFixedWindow,
) -> Expr {
use polars_compute::rolling::{RollingFnParams, RollingQuantileParams};
options.fn_params = Some(RollingFnParams::Quantile(RollingQuantileParams {
prob: quantile,
method,
}));
self.finish_rolling(options, RollingFunction::Quantile)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_var(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Var)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_std(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Std)
}
#[cfg(feature = "rolling_window")]
#[cfg(feature = "moment")]
pub fn rolling_skew(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Skew)
}
#[cfg(feature = "rolling_window")]
#[cfg(feature = "moment")]
pub fn rolling_kurtosis(self, options: RollingOptionsFixedWindow) -> Expr {
self.finish_rolling(options, RollingFunction::Kurtosis)
}
#[cfg(feature = "rolling_window")]
pub fn rolling_map(
self,
f: PlanCallback<Series, Series>,
options: RollingOptionsFixedWindow,
) -> Expr {
self.finish_rolling(options, RollingFunction::Map(f))
}
#[cfg(feature = "peaks")]
pub fn peak_min(self) -> Expr {
self.map_unary(FunctionExpr::PeakMin)
}
#[cfg(feature = "peaks")]
pub fn peak_max(self) -> Expr {
self.map_unary(FunctionExpr::PeakMax)
}
#[cfg(feature = "rank")]
pub fn rank(self, options: RankOptions, seed: Option<u64>) -> Expr {
self.map_unary(FunctionExpr::Rank { options, seed })
}
#[cfg(feature = "replace")]
pub fn replace<E: Into<Expr>>(self, old: E, new: E) -> Expr {
let old = old.into();
let new = new.into();
self.map_n_ary(FunctionExpr::Replace, [old, new])
}
#[cfg(feature = "replace")]
pub fn replace_strict<E: Into<Expr>>(
self,
old: E,
new: E,
default: Option<E>,
return_dtype: Option<impl Into<DataTypeExpr>>,
) -> Expr {
let old = old.into();
let new = new.into();
let mut args = vec![old, new];
args.extend(default.map(Into::into));
self.map_n_ary(
FunctionExpr::ReplaceStrict {
return_dtype: return_dtype.map(Into::into),
},
args,
)
}
#[cfg(feature = "cutqcut")]
pub fn cut(
self,
breaks: Vec<f64>,
labels: Option<impl IntoVec<PlSmallStr>>,
left_closed: bool,
include_breaks: bool,
) -> Expr {
self.map_unary(FunctionExpr::Cut {
breaks,
labels: labels.map(|x| x.into_vec()),
left_closed,
include_breaks,
})
}
#[cfg(feature = "cutqcut")]
pub fn qcut(
self,
probs: Vec<f64>,
labels: Option<impl IntoVec<PlSmallStr>>,
left_closed: bool,
allow_duplicates: bool,
include_breaks: bool,
) -> Expr {
self.map_unary(FunctionExpr::QCut {
probs,
labels: labels.map(|x| x.into_vec()),
left_closed,
allow_duplicates,
include_breaks,
})
}
#[cfg(feature = "cutqcut")]
pub fn qcut_uniform(
self,
n_bins: usize,
labels: Option<impl IntoVec<PlSmallStr>>,
left_closed: bool,
allow_duplicates: bool,
include_breaks: bool,
) -> Expr {
let probs = (1..n_bins).map(|b| b as f64 / n_bins as f64).collect();
self.map_unary(FunctionExpr::QCut {
probs,
labels: labels.map(|x| x.into_vec()),
left_closed,
allow_duplicates,
include_breaks,
})
}
#[cfg(feature = "rle")]
pub fn rle(self) -> Expr {
self.map_unary(FunctionExpr::RLE)
}
#[cfg(feature = "rle")]
pub fn rle_id(self) -> Expr {
self.map_unary(FunctionExpr::RLEID)
}
#[cfg(feature = "diff")]
pub fn diff(self, n: Expr, null_behavior: NullBehavior) -> Expr {
self.map_binary(FunctionExpr::Diff(null_behavior), n)
}
#[cfg(feature = "pct_change")]
pub fn pct_change(self, n: Expr) -> Expr {
self.map_binary(FunctionExpr::PctChange, n)
}
#[cfg(feature = "moment")]
pub fn skew(self, bias: bool) -> Expr {
self.map_unary(FunctionExpr::Skew(bias))
}
#[cfg(feature = "moment")]
pub fn kurtosis(self, fisher: bool, bias: bool) -> Expr {
self.map_unary(FunctionExpr::Kurtosis(fisher, bias))
}
pub fn upper_bound(self) -> Expr {
self.map_unary(FunctionExpr::UpperBound)
}
pub fn lower_bound(self) -> Expr {
self.map_unary(FunctionExpr::LowerBound)
}
#[cfg(feature = "dtype-array")]
pub fn reshape(self, dimensions: &[i64]) -> Self {
let dimensions = dimensions
.iter()
.map(|&v| ReshapeDimension::new(v))
.collect();
self.map_unary(FunctionExpr::Reshape(dimensions))
}
#[cfg(feature = "ewma")]
pub fn ewm_mean(self, options: EWMOptions) -> Self {
self.map_unary(FunctionExpr::EwmMean { options })
}
#[cfg(feature = "ewma_by")]
pub fn ewm_mean_by(self, times: Expr, half_life: Duration) -> Self {
self.map_binary(FunctionExpr::EwmMeanBy { half_life }, times)
}
#[cfg(feature = "ewma")]
pub fn ewm_std(self, options: EWMOptions) -> Self {
self.map_unary(FunctionExpr::EwmStd { options })
}
#[cfg(feature = "ewma")]
pub fn ewm_var(self, options: EWMOptions) -> Self {
self.map_unary(FunctionExpr::EwmVar { options })
}
pub fn any(self, ignore_nulls: bool) -> Self {
self.map_unary(BooleanFunction::Any { ignore_nulls })
}
pub fn all(self, ignore_nulls: bool) -> Self {
self.map_unary(BooleanFunction::All { ignore_nulls })
}
#[cfg(feature = "dtype-struct")]
pub fn value_counts(self, sort: bool, parallel: bool, name: &str, normalize: bool) -> Self {
self.map_unary(FunctionExpr::ValueCounts {
sort,
parallel,
name: name.into(),
normalize,
})
}
#[cfg(feature = "unique_counts")]
pub fn unique_counts(self) -> Self {
self.map_unary(FunctionExpr::UniqueCounts)
}
#[cfg(feature = "log")]
pub fn log(self, base: Expr) -> Self {
self.map_binary(FunctionExpr::Log, base)
}
#[cfg(feature = "log")]
pub fn log1p(self) -> Self {
self.map_unary(FunctionExpr::Log1p)
}
#[cfg(feature = "log")]
pub fn exp(self) -> Self {
self.map_unary(FunctionExpr::Exp)
}
#[cfg(feature = "log")]
pub fn entropy(self, base: f64, normalize: bool) -> Self {
self.map_unary(FunctionExpr::Entropy { base, normalize })
}
pub fn null_count(self) -> Expr {
self.map_unary(FunctionExpr::NullCount)
}
pub fn set_sorted_flag(self, sorted: IsSorted) -> Expr {
self.map_unary(FunctionExpr::SetSortedFlag(sorted))
}
#[cfg(feature = "row_hash")]
pub fn hash(self, k0: u64, k1: u64, k2: u64, k3: u64) -> Expr {
self.map_unary(FunctionExpr::Hash(k0, k1, k2, k3))
}
pub fn to_physical(self) -> Expr {
self.map_unary(FunctionExpr::ToPhysical)
}
pub fn gather_every(self, n: usize, offset: usize) -> Expr {
self.map_unary(FunctionExpr::GatherEvery { n, offset })
}
#[cfg(feature = "reinterpret")]
pub fn reinterpret(self, signed: bool) -> Expr {
self.map_unary(FunctionExpr::Reinterpret(signed))
}
pub fn extend_constant(self, value: Expr, n: Expr) -> Expr {
self.map_ternary(FunctionExpr::ExtendConstant, value, n)
}
#[cfg(feature = "strings")]
pub fn str(self) -> string::StringNameSpace {
string::StringNameSpace(self)
}
pub fn binary(self) -> binary::BinaryNameSpace {
binary::BinaryNameSpace(self)
}
#[cfg(feature = "temporal")]
pub fn dt(self) -> dt::DateLikeNameSpace {
dt::DateLikeNameSpace(self)
}
pub fn list(self) -> list::ListNameSpace {
list::ListNameSpace(self)
}
pub fn name(self) -> name::ExprNameNameSpace {
name::ExprNameNameSpace(self)
}
#[cfg(feature = "dtype-array")]
pub fn arr(self) -> array::ArrayNameSpace {
array::ArrayNameSpace(self)
}
#[cfg(feature = "dtype-categorical")]
pub fn cat(self) -> cat::CategoricalNameSpace {
cat::CategoricalNameSpace(self)
}
#[cfg(feature = "dtype-struct")]
pub fn struct_(self) -> struct_::StructNameSpace {
struct_::StructNameSpace(self)
}
#[cfg(feature = "meta")]
pub fn meta(self) -> meta::MetaNameSpace {
meta::MetaNameSpace(self)
}
}
pub fn map_multiple<F, DT, E>(function: F, expr: E, output_type: DT) -> Expr
where
F: Fn(&mut [Column]) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &[Field]) -> PolarsResult<Field> + 'static + Send + Sync,
E: AsRef<[Expr]>,
{
let input = expr.as_ref().to_vec();
let function = BaseColumnUdf::new(function, output_type);
let options = FunctionOptions::elementwise();
Expr::AnonymousFunction {
input,
function: new_column_udf(function),
options,
fmt_str: Box::new(PlSmallStr::EMPTY),
}
}
pub fn apply_multiple<F, DT, E>(function: F, expr: E, output_type: DT, returns_scalar: bool) -> Expr
where
F: Fn(&mut [Column]) -> PolarsResult<Column> + 'static + Send + Sync,
DT: Fn(&Schema, &[Field]) -> PolarsResult<Field> + 'static + Send + Sync,
E: AsRef<[Expr]>,
{
let input = expr.as_ref().to_vec();
let options = FunctionOptions::groupwise().with_flags(|mut f| {
f.set(FunctionFlags::RETURNS_SCALAR, returns_scalar);
f
});
let function = BaseColumnUdf::new(function, output_type);
Expr::AnonymousFunction {
input,
function: new_column_udf(function),
options,
fmt_str: Box::new(PlSmallStr::EMPTY),
}
}
pub fn len() -> Expr {
Expr::Len
}
pub fn first() -> Selector {
nth(0)
}
pub fn last() -> Selector {
nth(-1)
}
pub fn nth(n: i64) -> Selector {
Selector::ByIndex {
indices: [n].into(),
strict: true,
}
}