Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-ops/src/series/ops/log.rs
8449 views
1
#[cfg(feature = "dtype-f16")]
2
use num_traits::real::Real;
3
use polars_core::prelude::arity::broadcast_binary_elementwise_values;
4
use polars_core::prelude::*;
5
use polars_core::{with_match_physical_float_polars_type, with_match_physical_integer_polars_type};
6
7
use crate::series::ops::SeriesSealed;
8
9
fn log1p<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
10
ca.cast_and_apply_in_place(|v: f64| v.ln_1p())
11
}
12
13
fn exp<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
14
ca.cast_and_apply_in_place(|v: f64| v.exp())
15
}
16
17
pub trait LogSeries: SeriesSealed {
18
/// Compute the logarithm to a given base
19
fn log(&self, base: &Series) -> Series {
20
let s = self.as_series();
21
22
match (s.dtype(), base.dtype()) {
23
(dt1, dt2) if dt1 == dt2 && dt1.is_float() => {
24
let s = s.to_physical_repr();
25
let base = base.to_physical_repr();
26
with_match_physical_float_polars_type!(s.dtype(), |$T| {
27
let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();
28
let base_ca: &ChunkedArray<$T> = base.as_ref().as_ref().as_ref();
29
let out: ChunkedArray<$T> = broadcast_binary_elementwise_values(ca, base_ca,
30
|x, base| x.log(base)
31
);
32
out.into_series()
33
})
34
},
35
(dt1, _) if dt1.is_float() => s.log(&base.cast(dt1).unwrap()),
36
(_, dt2) if dt2.is_float() => s.cast(base.dtype()).unwrap().log(base),
37
(_, _) => s.cast(&DataType::Float64).unwrap().log(base),
38
}
39
}
40
41
/// Compute the natural logarithm of all elements plus one in the input array
42
fn log1p(&self) -> Series {
43
let s = self.as_series();
44
if s.dtype().is_decimal() {
45
return s.cast(&DataType::Float64).unwrap().log1p();
46
}
47
48
let s = s.to_physical_repr();
49
let s = s.as_ref();
50
51
use DataType::*;
52
match s.dtype() {
53
dt if dt.is_integer() => {
54
with_match_physical_integer_polars_type!(s.dtype(), |$T| {
55
let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();
56
log1p(ca).into_series()
57
})
58
},
59
#[cfg(feature = "dtype-f16")]
60
Float16 => s.f16().unwrap().apply_values(|v| v.ln_1p()).into_series(),
61
Float32 => s.f32().unwrap().apply_values(|v| v.ln_1p()).into_series(),
62
Float64 => s.f64().unwrap().apply_values(|v| v.ln_1p()).into_series(),
63
_ => s.cast(&DataType::Float64).unwrap().log1p(),
64
}
65
}
66
67
/// Calculate the exponential of all elements in the input array.
68
fn exp(&self) -> Series {
69
let s = self.as_series();
70
if s.dtype().is_decimal() {
71
return s.cast(&DataType::Float64).unwrap().exp();
72
}
73
74
let s = s.to_physical_repr();
75
let s = s.as_ref();
76
77
use DataType::*;
78
match s.dtype() {
79
dt if dt.is_integer() => {
80
with_match_physical_integer_polars_type!(s.dtype(), |$T| {
81
let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();
82
exp(ca).into_series()
83
})
84
},
85
#[cfg(feature = "dtype-f16")]
86
Float16 => s.f16().unwrap().apply_values(|v| v.exp()).into_series(),
87
Float32 => s.f32().unwrap().apply_values(|v| v.exp()).into_series(),
88
Float64 => s.f64().unwrap().apply_values(|v| v.exp()).into_series(),
89
_ => s.cast(&DataType::Float64).unwrap().exp(),
90
}
91
}
92
93
/// Compute the entropy as `-sum(pk * log(pk))`.
94
/// where `pk` are discrete probabilities.
95
fn entropy(&self, base: f64, normalize: bool) -> PolarsResult<f64> {
96
let s = self.as_series().to_physical_repr();
97
polars_ensure!(s.dtype().is_primitive_numeric(), InvalidOperation: "expected numerical input for 'entropy'");
98
// if there is only one value in the series, return 0.0 to prevent the
99
// function from returning -0.0
100
if s.len() == 1 {
101
return Ok(0.0);
102
}
103
match s.dtype() {
104
DataType::Float16 | DataType::Float32 | DataType::Float64 => {
105
let pk = s.as_ref();
106
107
let pk = if normalize {
108
let sum = pk.sum_reduce().unwrap().into_series(PlSmallStr::EMPTY);
109
110
if sum.get(0).unwrap().extract::<f64>().unwrap() != 1.0 {
111
(pk / &sum)?
112
} else {
113
pk.clone()
114
}
115
} else {
116
pk.clone()
117
};
118
119
let base = &Series::new(PlSmallStr::EMPTY, [base]);
120
(&pk * &pk.log(base))?.sum::<f64>().map(|v| -v)
121
},
122
_ => s
123
.cast(&DataType::Float64)
124
.map(|s| s.entropy(base, normalize))?,
125
}
126
}
127
}
128
129
impl LogSeries for Series {}
130
131