Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-python/src/series/scatter.rs
7889 views
1
use arrow::array::Array;
2
use polars::prelude::*;
3
use pyo3::prelude::*;
4
5
use super::PySeries;
6
use crate::utils::EnterPolarsExt;
7
8
#[pymethods]
9
impl PySeries {
10
fn scatter(&self, py: Python<'_>, idx: PySeries, values: PySeries) -> PyResult<()> {
11
py.enter_polars(|| {
12
// we take the value because we want a ref count of 1 so that we can
13
// have mutable access cheaply via _get_inner_mut().
14
let mut lock = self.series.write();
15
let s = std::mem::take(&mut *lock);
16
let result = scatter(s, &idx.series.into_inner(), &values.series.into_inner());
17
match result {
18
Ok(out) => {
19
*lock = out;
20
Ok(())
21
},
22
Err((s, e)) => {
23
// Restore original series:
24
*lock = s;
25
Err(e)
26
},
27
}
28
})
29
}
30
}
31
32
fn scatter(mut s: Series, idx: &Series, values: &Series) -> Result<Series, (Series, PolarsError)> {
33
let logical_dtype = s.dtype().clone();
34
35
let values = if logical_dtype.is_categorical() || logical_dtype.is_enum() {
36
if matches!(
37
values.dtype(),
38
DataType::Categorical(_, _) | DataType::Enum(_, _) | DataType::String | DataType::Null
39
) {
40
match values.strict_cast(&logical_dtype) {
41
Ok(values) => values,
42
Err(err) => return Err((s, err)),
43
}
44
} else {
45
return Err((
46
s,
47
polars_err!(InvalidOperation: "invalid values dtype '{}' for scattering into dtype '{}'", values.dtype(), logical_dtype),
48
));
49
}
50
} else {
51
values.clone()
52
};
53
54
let idx = match polars_ops::prelude::convert_to_unsigned_index(idx, s.len()) {
55
Ok(idx) => idx,
56
Err(err) => return Err((s, err)),
57
};
58
let idx = idx.rechunk();
59
let idx = idx.downcast_as_array();
60
61
if idx.null_count() > 0 {
62
return Err((
63
s,
64
PolarsError::ComputeError("index values should not be null".into()),
65
));
66
}
67
68
let idx = idx.values().as_slice();
69
70
let mut values = match values.to_physical_repr().cast(&s.dtype().to_physical()) {
71
Ok(values) => values,
72
Err(err) => return Err((s, err)),
73
};
74
75
// Broadcast values input
76
if values.len() == 1 && idx.len() > 1 {
77
values = values.new_from_index(0, idx.len());
78
}
79
80
// do not shadow, otherwise s is not dropped immediately
81
// and we want to have mutable access
82
s = s.to_physical_repr().into_owned();
83
let s_mut_ref = &mut s;
84
scatter_impl(s_mut_ref, logical_dtype, idx, &values).map_err(|err| (s, err))
85
}
86
87
fn scatter_impl(
88
s: &mut Series,
89
logical_dtype: DataType,
90
idx: &[IdxSize],
91
values: &Series,
92
) -> PolarsResult<Series> {
93
let mutable_s = s._get_inner_mut();
94
95
let s = match logical_dtype.to_physical() {
96
DataType::Int8 => {
97
let ca: &mut ChunkedArray<Int8Type> = mutable_s.as_mut();
98
let values = values.i8()?;
99
ca.scatter(idx, values)
100
},
101
DataType::Int16 => {
102
let ca: &mut ChunkedArray<Int16Type> = mutable_s.as_mut();
103
let values = values.i16()?;
104
ca.scatter(idx, values)
105
},
106
DataType::Int32 => {
107
let ca: &mut ChunkedArray<Int32Type> = mutable_s.as_mut();
108
let values = values.i32()?;
109
ca.scatter(idx, values)
110
},
111
DataType::Int64 => {
112
let ca: &mut ChunkedArray<Int64Type> = mutable_s.as_mut();
113
let values = values.i64()?;
114
ca.scatter(idx, values)
115
},
116
DataType::UInt8 => {
117
let ca: &mut ChunkedArray<UInt8Type> = mutable_s.as_mut();
118
let values = values.u8()?;
119
ca.scatter(idx, values)
120
},
121
DataType::UInt16 => {
122
let ca: &mut ChunkedArray<UInt16Type> = mutable_s.as_mut();
123
let values = values.u16()?;
124
ca.scatter(idx, values)
125
},
126
DataType::UInt32 => {
127
let ca: &mut ChunkedArray<UInt32Type> = mutable_s.as_mut();
128
let values = values.u32()?;
129
ca.scatter(idx, values)
130
},
131
DataType::UInt64 => {
132
let ca: &mut ChunkedArray<UInt64Type> = mutable_s.as_mut();
133
let values = values.u64()?;
134
ca.scatter(idx, values)
135
},
136
DataType::Float32 => {
137
let ca: &mut ChunkedArray<Float32Type> = mutable_s.as_mut();
138
let values = values.f32()?;
139
ca.scatter(idx, values)
140
},
141
DataType::Float64 => {
142
let ca: &mut ChunkedArray<Float64Type> = mutable_s.as_mut();
143
let values = values.f64()?;
144
ca.scatter(idx, values)
145
},
146
DataType::Boolean => {
147
let ca = s.bool()?;
148
let values = values.bool()?;
149
ca.scatter(idx, values)
150
},
151
DataType::String => {
152
let ca = s.str()?;
153
let values = values.str()?;
154
ca.scatter(idx, values)
155
},
156
_ => {
157
return Err(PolarsError::ComputeError(
158
format!("not yet implemented for dtype: {logical_dtype}").into(),
159
));
160
},
161
};
162
163
s.and_then(|s| s.cast(&logical_dtype))
164
}
165
166