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