-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
324 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
use crate::trusted_len::{PushUnchecked, TrustedLen}; | ||
use num::Float; | ||
use std::fmt::Debug; | ||
use std::ops::AddAssign; | ||
// See: | ||
// https://github.com/pola-rs/polars/issues/2148 | ||
// https://stackoverflow.com/a/51392341/6717054 | ||
|
||
pub fn ewma_no_nulls<T, I>(vals: I, alpha: T) -> Vec<T> | ||
where | ||
T: Float + AddAssign, | ||
I: IntoIterator<Item = T>, | ||
I::IntoIter: TrustedLen, | ||
{ | ||
let mut iter = vals.into_iter(); | ||
let len = iter.size_hint().1.unwrap(); | ||
if len == 0 { | ||
return vec![]; | ||
} | ||
let mut weight = T::one(); | ||
let mut out = Vec::with_capacity(len); | ||
|
||
let first = iter.next().unwrap(); | ||
out.push(first); | ||
let mut ewma_old = first; | ||
let one_sub_alpha = T::one() - alpha; | ||
|
||
for (i, val) in iter.enumerate() { | ||
let i = i + 1; | ||
weight += one_sub_alpha.powf(T::from(i).unwrap()); | ||
ewma_old = ewma_old * (one_sub_alpha) + val; | ||
// Safety: | ||
// we allocated vals.len() | ||
unsafe { out.push_unchecked(ewma_old / weight) } | ||
} | ||
|
||
out | ||
} | ||
|
||
pub fn ewma_inf_hist_no_nulls<T, I>(vals: I, alpha: T) -> Vec<T> | ||
where | ||
T: Float + AddAssign + Debug, | ||
I: IntoIterator<Item = T>, | ||
I::IntoIter: TrustedLen, | ||
{ | ||
let mut iter = vals.into_iter(); | ||
let len = iter.size_hint().1.unwrap(); | ||
if len == 0 { | ||
return vec![]; | ||
} | ||
|
||
let mut out = Vec::with_capacity(len); | ||
let first = iter.next().unwrap(); | ||
out.push(first); | ||
let one_sub_alpha = T::one() - alpha; | ||
|
||
for (i, val) in iter.enumerate() { | ||
let i = i + 1; | ||
|
||
// Safety: | ||
// we add first, so i - 1 always exits | ||
let output_val = val * alpha + unsafe { *out.get_unchecked(i - 1) } * one_sub_alpha; | ||
|
||
// Safety: | ||
// we allocated vals.len() | ||
unsafe { out.push_unchecked(output_val) } | ||
} | ||
|
||
out | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_ewma() { | ||
let vals = [2.0, 5.0, 3.0]; | ||
let out = ewma_no_nulls(vals.iter().copied(), 0.5); | ||
let expected = [2.0, 4.0, 3.4285714285714284]; | ||
assert_eq!(out, expected); | ||
|
||
let vals = [2.0, 5.0, 3.0]; | ||
let out = ewma_inf_hist_no_nulls(vals.iter().copied(), 0.5); | ||
let expected = [2.0, 3.5, 3.25]; | ||
assert_eq!(out, expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
mod average; | ||
|
||
pub use average::*; | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
pub struct ExponentialWindowOptions { | ||
pub alpha: f64, | ||
pub adjust: bool, | ||
} | ||
|
||
impl Default for ExponentialWindowOptions { | ||
fn default() -> Self { | ||
Self { | ||
alpha: 0.5, | ||
adjust: true, | ||
} | ||
} | ||
} | ||
|
||
impl ExponentialWindowOptions { | ||
pub fn and_adjust(mut self, adjust: bool) -> Self { | ||
self.adjust = adjust; | ||
self | ||
} | ||
pub fn and_span(mut self, span: usize) -> Self { | ||
assert!(span >= 1); | ||
self.alpha = 2.0 / (span as f64 + 1.0); | ||
self | ||
} | ||
|
||
pub fn and_halflife(mut self, halflife: f64) -> Self { | ||
assert!(halflife > 0.0); | ||
self.alpha = 1.0 - ((-2.0f64).ln() / halflife).exp(); | ||
self | ||
} | ||
|
||
pub fn and_com(mut self, com: f64) -> Self { | ||
assert!(com > 0.0); | ||
self.alpha = 1.0 / (1.0 + com); | ||
self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use crate::prelude::*; | ||
pub use polars_arrow::kernels::ew::ExponentialWindowOptions; | ||
use polars_arrow::kernels::ew::{ewma_inf_hist_no_nulls, ewma_no_nulls}; | ||
|
||
impl Series { | ||
pub fn ewm_mean(&self, options: ExponentialWindowOptions) -> Result<Self> { | ||
if self.null_count() > 0 { | ||
return self | ||
.fill_null(FillNullStrategy::Zero) | ||
.unwrap() | ||
.ewm_mean(options); | ||
} | ||
|
||
match self.dtype() { | ||
DataType::Float32 => { | ||
let ca = self.f32().unwrap(); | ||
match self.n_chunks() { | ||
1 => { | ||
let vals = ca.downcast_iter().next().unwrap(); | ||
let vals = vals.values().as_slice(); | ||
let out = if options.adjust { | ||
ewma_no_nulls(vals.iter().copied(), options.alpha as f32) | ||
} else { | ||
ewma_inf_hist_no_nulls(vals.iter().copied(), options.alpha as f32) | ||
}; | ||
Ok(Float32Chunked::new_vec(self.name(), out).into_series()) | ||
} | ||
_ => { | ||
let iter = ca.into_no_null_iter(); | ||
let out = if options.adjust { | ||
ewma_no_nulls(iter, options.alpha as f32) | ||
} else { | ||
ewma_inf_hist_no_nulls(iter, options.alpha as f32) | ||
}; | ||
Ok(Float32Chunked::new_vec(self.name(), out).into_series()) | ||
} | ||
} | ||
} | ||
DataType::Float64 => { | ||
let ca = self.f64().unwrap(); | ||
match self.n_chunks() { | ||
1 => { | ||
let vals = ca.downcast_iter().next().unwrap(); | ||
let vals = vals.values().as_slice(); | ||
let out = if options.adjust { | ||
ewma_no_nulls(vals.iter().copied(), options.alpha) | ||
} else { | ||
ewma_inf_hist_no_nulls(vals.iter().copied(), options.alpha) | ||
}; | ||
Ok(Float64Chunked::new_vec(self.name(), out).into_series()) | ||
} | ||
_ => { | ||
let iter = ca.into_no_null_iter(); | ||
let out = if options.adjust { | ||
ewma_no_nulls(iter, options.alpha) | ||
} else { | ||
ewma_inf_hist_no_nulls(iter, options.alpha) | ||
}; | ||
Ok(Float64Chunked::new_vec(self.name(), out).into_series()) | ||
} | ||
} | ||
} | ||
_ => self.cast(&DataType::Float64)?.ewm_mean(options), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,6 +82,7 @@ features = [ | |
"dtype-categorical", | ||
"diagonal_concat", | ||
"abs", | ||
"ewma", | ||
] | ||
|
||
# [patch.crates-io] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.