Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-core/src/series/implementations/duration.rs
8424 views
1
use polars_compute::rolling::QuantileMethod;
2
3
use super::*;
4
use crate::chunked_array::comparison::*;
5
#[cfg(feature = "algorithm_group_by")]
6
use crate::frame::group_by::*;
7
use crate::prelude::*;
8
9
unsafe impl IntoSeries for DurationChunked {
10
fn into_series(self) -> Series {
11
Series(Arc::new(SeriesWrap(self)))
12
}
13
}
14
15
impl private::PrivateSeriesNumeric for SeriesWrap<DurationChunked> {
16
fn bit_repr(&self) -> Option<BitRepr> {
17
Some(self.0.physical().to_bit_repr())
18
}
19
}
20
21
impl private::PrivateSeries for SeriesWrap<DurationChunked> {
22
fn compute_len(&mut self) {
23
self.0.physical_mut().compute_len()
24
}
25
fn _field(&self) -> Cow<'_, Field> {
26
Cow::Owned(self.0.field())
27
}
28
fn _dtype(&self) -> &DataType {
29
self.0.dtype()
30
}
31
32
fn _set_flags(&mut self, flags: StatisticsFlags) {
33
self.0.physical_mut().set_flags(flags)
34
}
35
36
fn _get_flags(&self) -> StatisticsFlags {
37
self.0.physical().get_flags()
38
}
39
40
unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
41
self.0.physical().equal_element(idx_self, idx_other, other)
42
}
43
44
#[cfg(feature = "zip_with")]
45
fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {
46
let other = other.to_physical_repr().into_owned();
47
self.0
48
.physical()
49
.zip_with(mask, other.as_ref().as_ref())
50
.map(|ca| ca.into_duration(self.0.time_unit()).into_series())
51
}
52
53
fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a> {
54
self.0.physical().into_total_eq_inner()
55
}
56
fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {
57
self.0.physical().into_total_ord_inner()
58
}
59
60
fn vec_hash(
61
&self,
62
random_state: PlSeedableRandomStateQuality,
63
buf: &mut Vec<u64>,
64
) -> PolarsResult<()> {
65
self.0.physical().vec_hash(random_state, buf)?;
66
Ok(())
67
}
68
69
fn vec_hash_combine(
70
&self,
71
build_hasher: PlSeedableRandomStateQuality,
72
hashes: &mut [u64],
73
) -> PolarsResult<()> {
74
self.0.physical().vec_hash_combine(build_hasher, hashes)?;
75
Ok(())
76
}
77
78
#[cfg(feature = "algorithm_group_by")]
79
unsafe fn agg_min(&self, groups: &GroupsType) -> Series {
80
self.0
81
.physical()
82
.agg_min(groups)
83
.into_duration(self.0.time_unit())
84
.into_series()
85
}
86
87
#[cfg(feature = "algorithm_group_by")]
88
unsafe fn agg_max(&self, groups: &GroupsType) -> Series {
89
self.0
90
.physical()
91
.agg_max(groups)
92
.into_duration(self.0.time_unit())
93
.into_series()
94
}
95
96
#[cfg(feature = "algorithm_group_by")]
97
unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {
98
self.0.physical().agg_arg_min(groups)
99
}
100
101
#[cfg(feature = "algorithm_group_by")]
102
unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {
103
self.0.physical().agg_arg_max(groups)
104
}
105
106
#[cfg(feature = "algorithm_group_by")]
107
unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {
108
self.0
109
.physical()
110
.agg_sum(groups)
111
.into_duration(self.0.time_unit())
112
.into_series()
113
}
114
115
#[cfg(feature = "algorithm_group_by")]
116
unsafe fn agg_std(&self, groups: &GroupsType, ddof: u8) -> Series {
117
self.0
118
.physical()
119
.agg_std(groups, ddof)
120
// cast f64 back to physical type
121
.cast(&DataType::Int64)
122
.unwrap()
123
.into_duration(self.0.time_unit())
124
.into_series()
125
}
126
127
#[cfg(feature = "algorithm_group_by")]
128
unsafe fn agg_var(&self, groups: &GroupsType, ddof: u8) -> Series {
129
self.0
130
.physical()
131
.agg_var(groups, ddof)
132
// cast f64 back to physical type
133
.cast(&DataType::Int64)
134
.unwrap()
135
.into_duration(self.0.time_unit())
136
.into_series()
137
}
138
139
#[cfg(feature = "algorithm_group_by")]
140
unsafe fn agg_list(&self, groups: &GroupsType) -> Series {
141
// we cannot cast and dispatch as the inner type of the list would be incorrect
142
self.0
143
.physical()
144
.agg_list(groups)
145
.cast(&DataType::List(Box::new(self.dtype().clone())))
146
.unwrap()
147
}
148
149
fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {
150
match (self.dtype(), rhs.dtype()) {
151
(DataType::Duration(tu), DataType::Duration(tur)) => {
152
polars_ensure!(tu == tur, InvalidOperation: "units are different");
153
let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
154
let rhs = rhs.cast(&DataType::Int64).unwrap();
155
Ok(lhs.subtract(&rhs)?.into_duration(*tu).into_series())
156
},
157
(dtl, dtr) => polars_bail!(opq = sub, dtl, dtr),
158
}
159
}
160
fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {
161
match (self.dtype(), rhs.dtype()) {
162
(DataType::Duration(tu), DataType::Duration(tur)) => {
163
polars_ensure!(tu == tur, InvalidOperation: "units are different");
164
let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
165
let rhs = rhs.cast(&DataType::Int64).unwrap();
166
Ok(lhs.add_to(&rhs)?.into_duration(*tu).into_series())
167
},
168
(DataType::Duration(tu), DataType::Date) => {
169
let one_day_in_tu: i64 = match tu {
170
TimeUnit::Milliseconds => 86_400_000,
171
TimeUnit::Microseconds => 86_400_000_000,
172
TimeUnit::Nanoseconds => 86_400_000_000_000,
173
};
174
let lhs =
175
self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap() / one_day_in_tu;
176
let rhs = rhs
177
.cast(&DataType::Int32)
178
.unwrap()
179
.cast(&DataType::Int64)
180
.unwrap();
181
Ok(lhs
182
.add_to(&rhs)?
183
.cast(&DataType::Int32)?
184
.into_date()
185
.into_series())
186
},
187
(DataType::Duration(tu), DataType::Datetime(tur, tz)) => {
188
polars_ensure!(tu == tur, InvalidOperation: "units are different");
189
let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
190
let rhs = rhs.cast(&DataType::Int64).unwrap();
191
Ok(lhs
192
.add_to(&rhs)?
193
.into_datetime(*tu, tz.clone())
194
.into_series())
195
},
196
(dtl, dtr) => polars_bail!(opq = add, dtl, dtr),
197
}
198
}
199
fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {
200
let tul = self.0.time_unit();
201
match rhs.dtype() {
202
DataType::Int64 => Ok((&self.0.phys * rhs.i64().unwrap())
203
.into_duration(tul)
204
.into_series()),
205
dt if dt.is_integer() => {
206
let rhs = rhs.cast(&DataType::Int64)?;
207
self.multiply(&rhs)
208
},
209
dt if dt.is_float() => {
210
let phys = &self.0.phys;
211
let phys_float = phys.cast(dt).unwrap();
212
let out = std::ops::Mul::mul(&phys_float, rhs)?
213
.cast(&DataType::Int64)
214
.unwrap();
215
let phys = out.i64().unwrap().clone();
216
Ok(phys.into_duration(tul).into_series())
217
},
218
_ => {
219
polars_bail!(opq = mul, self.dtype(), rhs.dtype());
220
},
221
}
222
}
223
fn divide(&self, rhs: &Series) -> PolarsResult<Series> {
224
let tul = self.0.time_unit();
225
match rhs.dtype() {
226
DataType::Duration(tur) => {
227
if tul == *tur {
228
// Returns a constant as f64.
229
Ok(std::ops::Div::div(
230
&self.0.phys.cast(&DataType::Float64).unwrap(),
231
&rhs.duration()
232
.unwrap()
233
.phys
234
.cast(&DataType::Float64)
235
.unwrap(),
236
)?
237
.into_series())
238
} else {
239
let rhs = rhs.cast(self.dtype())?;
240
self.divide(&rhs)
241
}
242
},
243
DataType::Int64 => Ok((&self.0.phys / rhs.i64().unwrap())
244
.into_duration(tul)
245
.into_series()),
246
dt if dt.is_integer() => {
247
let rhs = rhs.cast(&DataType::Int64)?;
248
self.divide(&rhs)
249
},
250
dt if dt.is_float() => {
251
let phys = &self.0.phys;
252
let phys_float = phys.cast(dt).unwrap();
253
let out = std::ops::Div::div(&phys_float, rhs)?
254
.cast(&DataType::Int64)
255
.unwrap();
256
let phys = out.i64().unwrap().clone();
257
Ok(phys.into_duration(tul).into_series())
258
},
259
_ => {
260
polars_bail!(opq = div, self.dtype(), rhs.dtype());
261
},
262
}
263
}
264
fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {
265
polars_ensure!(self.dtype() == rhs.dtype(), InvalidOperation: "dtypes and units must be equal in duration arithmetic");
266
let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();
267
let rhs = rhs.cast(&DataType::Int64).unwrap();
268
Ok(lhs
269
.remainder(&rhs)?
270
.into_duration(self.0.time_unit())
271
.into_series())
272
}
273
#[cfg(feature = "algorithm_group_by")]
274
fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {
275
self.0.physical().group_tuples(multithreaded, sorted)
276
}
277
278
fn arg_sort_multiple(
279
&self,
280
by: &[Column],
281
options: &SortMultipleOptions,
282
) -> PolarsResult<IdxCa> {
283
self.0.physical().arg_sort_multiple(by, options)
284
}
285
}
286
287
impl SeriesTrait for SeriesWrap<DurationChunked> {
288
fn rename(&mut self, name: PlSmallStr) {
289
self.0.rename(name);
290
}
291
292
fn chunk_lengths(&self) -> ChunkLenIter<'_> {
293
self.0.physical().chunk_lengths()
294
}
295
fn name(&self) -> &PlSmallStr {
296
self.0.name()
297
}
298
299
fn chunks(&self) -> &Vec<ArrayRef> {
300
self.0.physical().chunks()
301
}
302
unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {
303
self.0.physical_mut().chunks_mut()
304
}
305
306
fn shrink_to_fit(&mut self) {
307
self.0.physical_mut().shrink_to_fit()
308
}
309
310
fn slice(&self, offset: i64, length: usize) -> Series {
311
self.0.slice(offset, length).into_series()
312
}
313
314
fn split_at(&self, offset: i64) -> (Series, Series) {
315
let (a, b) = self.0.split_at(offset);
316
(a.into_series(), b.into_series())
317
}
318
319
fn _sum_as_f64(&self) -> f64 {
320
self.0.physical()._sum_as_f64()
321
}
322
323
fn mean(&self) -> Option<f64> {
324
self.0.physical().mean()
325
}
326
327
fn median(&self) -> Option<f64> {
328
self.0.physical().median()
329
}
330
331
fn std(&self, ddof: u8) -> Option<f64> {
332
self.0.physical().std(ddof)
333
}
334
335
fn var(&self, ddof: u8) -> Option<f64> {
336
self.0.physical().var(ddof)
337
}
338
339
fn append(&mut self, other: &Series) -> PolarsResult<()> {
340
polars_ensure!(self.0.dtype() == other.dtype(), append);
341
let mut other = other.to_physical_repr().into_owned();
342
self.0
343
.physical_mut()
344
.append_owned(std::mem::take(other._get_inner_mut().as_mut()))
345
}
346
fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {
347
polars_ensure!(self.0.dtype() == other.dtype(), append);
348
self.0.physical_mut().append_owned(std::mem::take(
349
&mut other
350
._get_inner_mut()
351
.as_any_mut()
352
.downcast_mut::<DurationChunked>()
353
.unwrap()
354
.phys,
355
))
356
}
357
358
fn extend(&mut self, other: &Series) -> PolarsResult<()> {
359
polars_ensure!(self.0.dtype() == other.dtype(), extend);
360
let other = other.to_physical_repr();
361
self.0
362
.physical_mut()
363
.extend(other.as_ref().as_ref().as_ref())?;
364
Ok(())
365
}
366
367
fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {
368
self.0
369
.physical()
370
.filter(filter)
371
.map(|ca| ca.into_duration(self.0.time_unit()).into_series())
372
}
373
374
fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {
375
Ok(self
376
.0
377
.physical()
378
.take(indices)?
379
.into_duration(self.0.time_unit())
380
.into_series())
381
}
382
383
unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {
384
self.0
385
.physical()
386
.take_unchecked(indices)
387
.into_duration(self.0.time_unit())
388
.into_series()
389
}
390
391
fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {
392
Ok(self
393
.0
394
.physical()
395
.take(indices)?
396
.into_duration(self.0.time_unit())
397
.into_series())
398
}
399
400
unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {
401
self.0
402
.physical()
403
.take_unchecked(indices)
404
.into_duration(self.0.time_unit())
405
.into_series()
406
}
407
408
fn deposit(&self, validity: &Bitmap) -> Series {
409
self.0
410
.physical()
411
.deposit(validity)
412
.into_duration(self.0.time_unit())
413
.into_series()
414
}
415
416
fn len(&self) -> usize {
417
self.0.len()
418
}
419
420
fn rechunk(&self) -> Series {
421
self.0
422
.physical()
423
.rechunk()
424
.into_owned()
425
.into_duration(self.0.time_unit())
426
.into_series()
427
}
428
429
fn new_from_index(&self, index: usize, length: usize) -> Series {
430
self.0
431
.physical()
432
.new_from_index(index, length)
433
.into_duration(self.0.time_unit())
434
.into_series()
435
}
436
437
fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {
438
self.0.cast_with_options(dtype, cast_options)
439
}
440
441
#[inline]
442
unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {
443
self.0.get_any_value_unchecked(index)
444
}
445
446
fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {
447
Ok(self
448
.0
449
.physical()
450
.sort_with(options)
451
.into_duration(self.0.time_unit())
452
.into_series())
453
}
454
455
fn arg_sort(&self, options: SortOptions) -> IdxCa {
456
self.0.physical().arg_sort(options)
457
}
458
459
fn null_count(&self) -> usize {
460
self.0.null_count()
461
}
462
463
fn has_nulls(&self) -> bool {
464
self.0.has_nulls()
465
}
466
467
#[cfg(feature = "algorithm_group_by")]
468
fn unique(&self) -> PolarsResult<Series> {
469
self.0
470
.physical()
471
.unique()
472
.map(|ca| ca.into_duration(self.0.time_unit()).into_series())
473
}
474
475
#[cfg(feature = "algorithm_group_by")]
476
fn n_unique(&self) -> PolarsResult<usize> {
477
self.0.physical().n_unique()
478
}
479
480
fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {
481
ChunkUnique::unique_id(self.0.physical())
482
}
483
484
#[cfg(feature = "algorithm_group_by")]
485
fn arg_unique(&self) -> PolarsResult<IdxCa> {
486
self.0.physical().arg_unique()
487
}
488
489
fn is_null(&self) -> BooleanChunked {
490
self.0.is_null()
491
}
492
493
fn is_not_null(&self) -> BooleanChunked {
494
self.0.is_not_null()
495
}
496
497
fn reverse(&self) -> Series {
498
self.0
499
.physical()
500
.reverse()
501
.into_duration(self.0.time_unit())
502
.into_series()
503
}
504
505
fn as_single_ptr(&mut self) -> PolarsResult<usize> {
506
self.0.physical_mut().as_single_ptr()
507
}
508
509
fn shift(&self, periods: i64) -> Series {
510
self.0
511
.physical()
512
.shift(periods)
513
.into_duration(self.0.time_unit())
514
.into_series()
515
}
516
517
fn sum_reduce(&self) -> PolarsResult<Scalar> {
518
let sc = self.0.physical().sum_reduce();
519
let v = sc.value().as_duration(self.0.time_unit());
520
Ok(Scalar::new(self.dtype().clone(), v))
521
}
522
523
fn max_reduce(&self) -> PolarsResult<Scalar> {
524
let sc = self.0.physical().max_reduce();
525
let v = sc.value().as_duration(self.0.time_unit());
526
Ok(Scalar::new(self.dtype().clone(), v))
527
}
528
fn min_reduce(&self) -> PolarsResult<Scalar> {
529
let sc = self.0.physical().min_reduce();
530
let v = sc.value().as_duration(self.0.time_unit());
531
Ok(Scalar::new(self.dtype().clone(), v))
532
}
533
fn std_reduce(&self, ddof: u8) -> PolarsResult<Scalar> {
534
let sc = self.0.physical().std_reduce(ddof);
535
let to = self.dtype().to_physical();
536
let v = sc.value().cast(&to);
537
Ok(Scalar::new(
538
self.dtype().clone(),
539
v.as_duration(self.0.time_unit()),
540
))
541
}
542
543
fn mean_reduce(&self) -> PolarsResult<Scalar> {
544
let mean = self.mean().map(|v| v as i64);
545
let av = AnyValue::from(mean).as_duration(self.0.time_unit());
546
Ok(Scalar::new(self.dtype().clone(), av))
547
}
548
549
fn median_reduce(&self) -> PolarsResult<Scalar> {
550
let mean = self.median().map(|v| v as i64);
551
let av = AnyValue::from(mean).as_duration(self.0.time_unit());
552
Ok(Scalar::new(self.dtype().clone(), av))
553
}
554
555
fn quantile_reduce(&self, quantile: f64, method: QuantileMethod) -> PolarsResult<Scalar> {
556
let v = self.0.physical().quantile_reduce(quantile, method)?;
557
let v = v.value().cast(&DataType::Int64);
558
Ok(Scalar::new(
559
self.dtype().clone(),
560
v.as_duration(self.0.time_unit()),
561
))
562
}
563
564
fn quantiles_reduce(&self, quantiles: &[f64], method: QuantileMethod) -> PolarsResult<Scalar> {
565
let result = self.0.physical().quantiles_reduce(quantiles, method)?;
566
if let AnyValue::List(float_s) = result.value() {
567
let float_ca = float_s.f64().unwrap();
568
let int_s = float_ca
569
.iter()
570
.map(|v: Option<f64>| v.map(|f| f as i64))
571
.collect::<Int64Chunked>()
572
.into_duration(self.0.time_unit())
573
.into_series();
574
Ok(Scalar::new(
575
DataType::List(Box::new(self.dtype().clone())),
576
AnyValue::List(int_s),
577
))
578
} else {
579
polars_bail!(ComputeError: "expected list scalar from quantiles_reduce")
580
}
581
}
582
583
#[cfg(feature = "approx_unique")]
584
fn approx_n_unique(&self) -> PolarsResult<IdxSize> {
585
Ok(ChunkApproxNUnique::approx_n_unique(self.0.physical()))
586
}
587
588
fn clone_inner(&self) -> Arc<dyn SeriesTrait> {
589
Arc::new(SeriesWrap(Clone::clone(&self.0)))
590
}
591
592
fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {
593
self.0.physical().find_validity_mismatch(other, idxs)
594
}
595
596
fn as_any(&self) -> &dyn Any {
597
&self.0
598
}
599
600
fn as_any_mut(&mut self) -> &mut dyn Any {
601
&mut self.0
602
}
603
604
fn as_phys_any(&self) -> &dyn Any {
605
self.0.physical()
606
}
607
608
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
609
self as _
610
}
611
}
612
613