Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-compute/src/rolling/no_nulls/moment.rs
8503 views
1
#![allow(unsafe_op_in_unsafe_fn)]
2
use num_traits::{FromPrimitive, ToPrimitive};
3
use polars_error::polars_ensure;
4
5
pub use super::super::moment::*;
6
use super::*;
7
8
pub fn rolling_var<T>(
9
values: &[T],
10
window_size: usize,
11
min_periods: usize,
12
center: bool,
13
weights: Option<&[f64]>,
14
params: Option<RollingFnParams>,
15
) -> PolarsResult<ArrayRef>
16
where
17
T: NativeType + Float + IsFloat + ToPrimitive + FromPrimitive + AddAssign,
18
{
19
let offset_fn = match center {
20
true => det_offsets_center,
21
false => det_offsets,
22
};
23
match weights {
24
None => rolling_apply_agg_window::<MomentWindow<_, VarianceMoment>, _, _, _>(
25
values,
26
window_size,
27
min_periods,
28
offset_fn,
29
params,
30
),
31
Some(weights) => {
32
// Validate and standardize the weights like we do for the mean. This definition is fine
33
// because frequency weights and unbiasing don't make sense for rolling operations.
34
let mut wts = no_nulls::coerce_weights(weights);
35
let wsum = wts.iter().fold(T::zero(), |acc, x| acc + *x);
36
polars_ensure!(
37
wsum != T::zero(),
38
ComputeError: "Weighted variance is undefined if weights sum to 0"
39
);
40
wts.iter_mut().for_each(|w| *w = *w / wsum);
41
super::rolling_apply_weights(
42
values,
43
window_size,
44
min_periods,
45
offset_fn,
46
compute_var_weights,
47
&wts,
48
center,
49
)
50
},
51
}
52
}
53
54
pub fn rolling_skew<T>(
55
values: &[T],
56
window_size: usize,
57
min_periods: usize,
58
center: bool,
59
params: Option<RollingFnParams>,
60
) -> PolarsResult<ArrayRef>
61
where
62
T: NativeType + Float + IsFloat + ToPrimitive + FromPrimitive + AddAssign,
63
{
64
let offset_fn = match center {
65
true => det_offsets_center,
66
false => det_offsets,
67
};
68
rolling_apply_agg_window::<MomentWindow<_, SkewMoment>, _, _, _>(
69
values,
70
window_size,
71
min_periods,
72
offset_fn,
73
params,
74
)
75
}
76
77
pub fn rolling_kurtosis<T>(
78
values: &[T],
79
window_size: usize,
80
min_periods: usize,
81
center: bool,
82
params: Option<RollingFnParams>,
83
) -> PolarsResult<ArrayRef>
84
where
85
T: NativeType + Float + IsFloat + ToPrimitive + FromPrimitive + AddAssign,
86
{
87
let offset_fn = match center {
88
true => det_offsets_center,
89
false => det_offsets,
90
};
91
rolling_apply_agg_window::<MomentWindow<_, KurtosisMoment>, _, _, _>(
92
values,
93
window_size,
94
min_periods,
95
offset_fn,
96
params,
97
)
98
}
99
100
#[cfg(test)]
101
mod test {
102
use super::*;
103
104
#[test]
105
fn test_rolling_var() {
106
let values = &[1.0f64, 5.0, 3.0, 4.0];
107
108
let out = rolling_var(values, 2, 2, false, None, None).unwrap();
109
let out = out.as_any().downcast_ref::<PrimitiveArray<f64>>().unwrap();
110
let out = out.into_iter().map(|v| v.copied()).collect::<Vec<_>>();
111
assert_eq!(out, &[None, Some(8.0), Some(2.0), Some(0.5)]);
112
113
let testpars = Some(RollingFnParams::Var(RollingVarParams { ddof: 0 }));
114
let out = rolling_var(values, 2, 2, false, None, testpars).unwrap();
115
let out = out.as_any().downcast_ref::<PrimitiveArray<f64>>().unwrap();
116
let out = out.into_iter().map(|v| v.copied()).collect::<Vec<_>>();
117
assert_eq!(out, &[None, Some(4.0), Some(1.0), Some(0.25)]);
118
119
let out = rolling_var(values, 2, 1, false, None, None).unwrap();
120
let out = out.as_any().downcast_ref::<PrimitiveArray<f64>>().unwrap();
121
let out = out.into_iter().map(|v| v.copied()).collect::<Vec<_>>();
122
// we cannot compare nans, so we compare the string values
123
assert_eq!(
124
format!("{:?}", out.as_slice()),
125
format!("{:?}", &[None, Some(8.0), Some(2.0), Some(0.5)])
126
);
127
// test nan handling.
128
let values = &[-10.0, 2.0, 3.0, f64::nan(), 5.0, 6.0, 7.0];
129
let out = rolling_var(values, 3, 3, false, None, None).unwrap();
130
let out = out.as_any().downcast_ref::<PrimitiveArray<f64>>().unwrap();
131
let out = out.into_iter().map(|v| v.copied()).collect::<Vec<_>>();
132
// we cannot compare nans, so we compare the string values
133
assert_eq!(
134
format!("{:?}", out.as_slice()),
135
format!(
136
"{:?}",
137
&[
138
None,
139
None,
140
Some(52.33333333333333),
141
Some(f64::nan()),
142
Some(f64::nan()),
143
Some(f64::nan()),
144
Some(0.9999999999999911)
145
]
146
)
147
);
148
}
149
}
150
151