fix(gaps): G1 — re-enable Python bindings (PyO3 0.25, Python 3.14)
- Upgrade workspace pyo3 0.24 → 0.25 and numpy 0.24 → 0.25 for Python 3.14 support - rtx-sklearn-py: replace pinned pyo3 0.20 / pyo3-asyncio 0.20 / numpy 0.20 with workspace versions; remove broken pyo3-asyncio async feature; update pyo3-build-config to 0.24 - rtx-bindings: uncomment pyo3/numpy/ndarray optional deps; enable python feature in Cargo.toml - Migrate rtx-bindings python/ to PyO3 0.25 Bound API: &PyAny → Bound<'py, PyAny>, downcast/extract on Bound types, remove rtx_runtime import, remove InferenceError arm (variant not in enum), fix py_shape_to_shape signature - Migrate rtx-sklearn-py src/ to PyO3 0.25 Bound API: #[pymodule] fn now takes &Bound<'_, PyModule>, &PyDict → &Bound<'py, PyDict>, from_array returns Bound (unbind instead of to_owned), PyTuple::new now fallible, use numpy::ndarray (0.16) over workspace ndarray (0.15) to resolve trait mismatches Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
228137555f
commit
448c0a0be5
@@ -2,7 +2,7 @@
|
||||
Simplified sklearn-compatible classifier wrappers that compile with current API
|
||||
*/
|
||||
|
||||
use ndarray::{Array1, Array2};
|
||||
use numpy::ndarray::{Array1, Array2};
|
||||
use numpy::{PyArray1, PyArray2, PyReadonlyArrayDyn};
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
@@ -196,7 +196,7 @@ impl DecisionTreeClassifier {
|
||||
let predictions: Array1<i64> =
|
||||
Array1::from_iter(predictions_data.iter().map(|&x| x.round() as i64));
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, predictions)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, predictions)?.unbind()))
|
||||
}
|
||||
|
||||
/// Predict class probabilities
|
||||
@@ -251,7 +251,7 @@ impl DecisionTreeClassifier {
|
||||
))
|
||||
})?;
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, probabilities)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, probabilities)?.unbind()))
|
||||
}
|
||||
|
||||
/// Score the model on test data
|
||||
@@ -259,8 +259,11 @@ impl DecisionTreeClassifier {
|
||||
let predictions = self.predict(x)?;
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let pred_array = predictions.as_ref(py).readonly();
|
||||
let pred_view = ArrayConverter::to_dyn_view(&pred_array);
|
||||
use numpy::PyArrayMethods;
|
||||
let pred_bound = predictions.bind(py);
|
||||
let pred_array = pred_bound.readonly();
|
||||
// Convert Ix1 readonly array view to dynamic view directly
|
||||
let pred_view = pred_array.as_array();
|
||||
let y_view = ArrayConverter::to_array_view1(&y).map_err(|e| PyErr::from(e))?;
|
||||
|
||||
if pred_view.len() != y_view.len() {
|
||||
@@ -281,26 +284,21 @@ impl DecisionTreeClassifier {
|
||||
|
||||
/// Get model parameters
|
||||
fn get_params(&self) -> PyResult<HashMap<String, PyObject>> {
|
||||
use pyo3::IntoPyObjectExt;
|
||||
Python::with_gil(|py| {
|
||||
let mut params = HashMap::new();
|
||||
params.insert("criterion".to_string(), self.criterion.to_object(py));
|
||||
params.insert("max_depth".to_string(), self.max_depth.to_object(py));
|
||||
params.insert(
|
||||
"min_samples_split".to_string(),
|
||||
self.min_samples_split.to_object(py),
|
||||
);
|
||||
params.insert(
|
||||
"min_samples_leaf".to_string(),
|
||||
self.min_samples_leaf.to_object(py),
|
||||
);
|
||||
params.insert("random_state".to_string(), self.random_state.to_object(py));
|
||||
params.insert("device".to_string(), self.device.to_string().to_object(py));
|
||||
params.insert("criterion".to_string(), self.criterion.clone().into_py_any(py)?);
|
||||
params.insert("max_depth".to_string(), self.max_depth.into_py_any(py)?);
|
||||
params.insert("min_samples_split".to_string(), self.min_samples_split.into_py_any(py)?);
|
||||
params.insert("min_samples_leaf".to_string(), self.min_samples_leaf.into_py_any(py)?);
|
||||
params.insert("random_state".to_string(), self.random_state.into_py_any(py)?);
|
||||
params.insert("device".to_string(), self.device.to_string().into_py_any(py)?);
|
||||
Ok(params)
|
||||
})
|
||||
}
|
||||
|
||||
/// Set model parameters
|
||||
fn set_params(&mut self, params: &PyDict) -> PyResult<()> {
|
||||
fn set_params<'py>(&mut self, params: &Bound<'py, PyDict>) -> PyResult<()> {
|
||||
let valid_params = vec![
|
||||
"criterion",
|
||||
"max_depth",
|
||||
@@ -343,7 +341,7 @@ impl DecisionTreeClassifier {
|
||||
match &self.classes {
|
||||
Some(classes) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, classes.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, classes.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -375,7 +373,7 @@ impl DecisionTreeClassifier {
|
||||
|
||||
Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, importances)?.to_owned(),
|
||||
ArrayConverter::from_array1(py, importances)?.unbind(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Simplified sklearn-compatible clustering wrappers
|
||||
*/
|
||||
|
||||
use ndarray::{Array1, Array2, Axis};
|
||||
use numpy::ndarray::{Array1, Array2, Axis};
|
||||
use numpy::{PyArray1, PyArray2, PyReadonlyArrayDyn};
|
||||
use pyo3::prelude::*;
|
||||
use rand::{Rng, SeedableRng};
|
||||
@@ -190,7 +190,7 @@ impl KMeans {
|
||||
labels[sample_idx] = best_cluster as i64;
|
||||
}
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, labels)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, labels)?.unbind()))
|
||||
}
|
||||
|
||||
fn fit_predict(&mut self, x: PyReadonlyArrayDyn<f64>) -> PyResult<Py<PyArray1<i64>>> {
|
||||
@@ -198,7 +198,7 @@ impl KMeans {
|
||||
|
||||
match &self.labels_ {
|
||||
Some(labels) => Python::with_gil(|py| {
|
||||
Ok(ArrayConverter::from_array1(py, labels.clone())?.to_owned())
|
||||
Ok(ArrayConverter::from_array1(py, labels.clone())?.unbind())
|
||||
}),
|
||||
None => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(
|
||||
"fit_predict failed: no labels available",
|
||||
@@ -227,16 +227,17 @@ impl KMeans {
|
||||
}
|
||||
}
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, distances)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, distances)?.unbind()))
|
||||
}
|
||||
|
||||
fn get_params(&self) -> PyResult<HashMap<String, PyObject>> {
|
||||
use pyo3::IntoPyObjectExt;
|
||||
Python::with_gil(|py| {
|
||||
let mut params = HashMap::new();
|
||||
params.insert("n_clusters".to_string(), self.n_clusters.to_object(py));
|
||||
params.insert("random_state".to_string(), self.random_state.to_object(py));
|
||||
params.insert("max_iter".to_string(), self.max_iter.to_object(py));
|
||||
params.insert("device".to_string(), self.device.to_string().to_object(py));
|
||||
params.insert("n_clusters".to_string(), self.n_clusters.into_py_any(py)?);
|
||||
params.insert("random_state".to_string(), self.random_state.into_py_any(py)?);
|
||||
params.insert("max_iter".to_string(), self.max_iter.into_py_any(py)?);
|
||||
params.insert("device".to_string(), self.device.to_string().into_py_any(py)?);
|
||||
Ok(params)
|
||||
})
|
||||
}
|
||||
@@ -246,7 +247,7 @@ impl KMeans {
|
||||
match &self.cluster_centers_ {
|
||||
Some(centers) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array2(py, centers.clone())?.to_owned(),
|
||||
ArrayConverter::from_array2(py, centers.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -258,7 +259,7 @@ impl KMeans {
|
||||
match &self.labels_ {
|
||||
Some(labels) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, labels.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, labels.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -299,12 +300,12 @@ impl DBSCAN {
|
||||
|
||||
fn fit_predict(&mut self, x: PyReadonlyArrayDyn<f64>) -> PyResult<Py<PyArray1<i64>>> {
|
||||
let x_view = ArrayConverter::to_array_view2(&x).map_err(|e| PyErr::from(e))?;
|
||||
// Simplified: assign random labels for demonstration
|
||||
// Simplified: assign zero labels for demonstration
|
||||
let labels = Array1::zeros(x_view.shape()[0]);
|
||||
self.labels_ = Some(labels.clone());
|
||||
self.is_fitted = true;
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, labels)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, labels)?.unbind()))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -312,7 +313,7 @@ impl DBSCAN {
|
||||
match &self.labels_ {
|
||||
Some(labels) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, labels.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, labels.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Simplified sklearn-compatible model selection wrappers
|
||||
*/
|
||||
|
||||
use ndarray::{Array1, Array2, Axis};
|
||||
use numpy::ndarray::{Array1, Array2, Axis};
|
||||
use numpy::{PyArray1, PyReadonlyArrayDyn};
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyTuple};
|
||||
@@ -27,7 +27,7 @@ pub struct GridSearchCV {
|
||||
impl GridSearchCV {
|
||||
#[new]
|
||||
#[pyo3(signature = (estimator, param_grid, cv=5))]
|
||||
fn new(estimator: PyObject, param_grid: &PyDict, cv: Option<usize>) -> PyResult<Self> {
|
||||
fn new<'py>(estimator: PyObject, param_grid: &Bound<'py, PyDict>, cv: Option<usize>) -> PyResult<Self> {
|
||||
// Convert param_grid from PyDict to HashMap (simplified)
|
||||
let param_grid_map = HashMap::new(); // Placeholder
|
||||
|
||||
@@ -56,7 +56,7 @@ impl GridSearchCV {
|
||||
Python::with_gil(|py| {
|
||||
let x_view = ArrayConverter::to_array_view2(&x).map_err(|e| PyErr::from(e))?;
|
||||
let dummy_preds = Array1::<f64>::zeros(x_view.shape()[0]);
|
||||
Ok(ArrayConverter::from_array1(py, dummy_preds)?.to_object(py))
|
||||
Ok(ArrayConverter::from_array1(py, dummy_preds)?.into_any().unbind())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,8 +66,15 @@ impl GridSearchCV {
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn best_params_(&self) -> Option<HashMap<String, PyObject>> {
|
||||
self.best_params_.clone()
|
||||
fn best_params_(&self) -> PyResult<Option<PyObject>> {
|
||||
match &self.best_params_ {
|
||||
Some(_params) => Python::with_gil(|py| {
|
||||
let dict = PyDict::new(py);
|
||||
// Return empty dict for the placeholder
|
||||
Ok(Some(dict.into_any().unbind()))
|
||||
}),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +95,7 @@ pub fn cross_val_score(
|
||||
// Simplified - return dummy cross-validation scores
|
||||
let scores = Array1::from_vec(vec![0.9, 0.92, 0.88, 0.91, 0.89][..cv_folds].to_vec());
|
||||
|
||||
Ok(ArrayConverter::from_array1(py, scores)?.to_owned())
|
||||
Ok(ArrayConverter::from_array1(py, scores)?.unbind())
|
||||
}
|
||||
|
||||
/// Simplified sklearn-compatible train_test_split function
|
||||
@@ -154,21 +161,16 @@ pub fn train_test_split(
|
||||
let y_train_1d = Array1::from_vec(y_train.iter().copied().collect());
|
||||
let y_test_1d = Array1::from_vec(y_test.iter().copied().collect());
|
||||
|
||||
let x_train_py = ArrayConverter::from_array2(py, x_train_2d)?;
|
||||
let x_test_py = ArrayConverter::from_array2(py, x_test_2d)?;
|
||||
let y_train_py = ArrayConverter::from_array1(py, y_train_1d)?;
|
||||
let y_test_py = ArrayConverter::from_array1(py, y_test_1d)?;
|
||||
let x_train_py = ArrayConverter::from_array2(py, x_train_2d)?.into_any().unbind();
|
||||
let x_test_py = ArrayConverter::from_array2(py, x_test_2d)?.into_any().unbind();
|
||||
let y_train_py = ArrayConverter::from_array1(py, y_train_1d)?.into_any().unbind();
|
||||
let y_test_py = ArrayConverter::from_array1(py, y_test_1d)?.into_any().unbind();
|
||||
|
||||
// Return tuple
|
||||
let result = PyTuple::new(
|
||||
py,
|
||||
&[
|
||||
x_train_py.to_object(py),
|
||||
x_test_py.to_object(py),
|
||||
y_train_py.to_object(py),
|
||||
y_test_py.to_object(py),
|
||||
],
|
||||
);
|
||||
&[x_train_py, x_test_py, y_train_py, y_test_py],
|
||||
)?;
|
||||
|
||||
Ok(result.to_object(py))
|
||||
Ok(result.into_any().unbind())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Simplified sklearn-compatible preprocessing wrappers
|
||||
*/
|
||||
|
||||
use ndarray::{Array1, Array2, Axis};
|
||||
use numpy::ndarray::{Array1, Array2, Axis};
|
||||
use numpy::{PyArray1, PyArray2, PyReadonlyArrayDyn};
|
||||
use pyo3::prelude::*;
|
||||
|
||||
@@ -94,7 +94,7 @@ impl StandardScaler {
|
||||
))
|
||||
},
|
||||
)?;
|
||||
Ok(ArrayConverter::from_array2(py, transformed_2d)?.to_owned())
|
||||
Ok(ArrayConverter::from_array2(py, transformed_2d)?.unbind())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ impl StandardScaler {
|
||||
))
|
||||
},
|
||||
)?;
|
||||
Ok(ArrayConverter::from_array2(py, transformed_2d)?.to_owned())
|
||||
Ok(ArrayConverter::from_array2(py, transformed_2d)?.unbind())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ impl StandardScaler {
|
||||
e
|
||||
))
|
||||
})?;
|
||||
Ok(ArrayConverter::from_array2(py, inv_transformed_2d)?.to_owned())
|
||||
Ok(ArrayConverter::from_array2(py, inv_transformed_2d)?.unbind())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ impl StandardScaler {
|
||||
match &self.mean_ {
|
||||
Some(mean) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, mean.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, mean.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -197,7 +197,7 @@ impl StandardScaler {
|
||||
match &self.scale_ {
|
||||
Some(scale) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, scale.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, scale.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -282,7 +282,7 @@ impl MinMaxScaler {
|
||||
}
|
||||
}
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, transformed)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, transformed)?.unbind()))
|
||||
}
|
||||
|
||||
fn fit_transform(&mut self, x: PyReadonlyArrayDyn<f64>) -> PyResult<Py<PyArray2<f64>>> {
|
||||
@@ -320,7 +320,7 @@ impl MinMaxScaler {
|
||||
}
|
||||
}
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, transformed)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array2(py, transformed)?.unbind()))
|
||||
}
|
||||
|
||||
#[getter]
|
||||
@@ -328,7 +328,7 @@ impl MinMaxScaler {
|
||||
match &self.data_min_ {
|
||||
Some(data_min) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, data_min.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, data_min.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
@@ -355,20 +355,20 @@ impl OneHotEncoder {
|
||||
})
|
||||
}
|
||||
|
||||
fn fit(&mut self, x: &PyAny) -> PyResult<()> {
|
||||
fn fit<'py>(&mut self, _x: &Bound<'py, PyAny>) -> PyResult<()> {
|
||||
self.is_fitted = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transform(&self, x: &PyAny) -> PyResult<Py<PyArray2<f64>>> {
|
||||
fn transform<'py>(&self, _x: &Bound<'py, PyAny>) -> PyResult<Py<PyArray2<f64>>> {
|
||||
// Placeholder - return identity transform
|
||||
Python::with_gil(|py| {
|
||||
let dummy = Array2::eye(2);
|
||||
Ok(ArrayConverter::from_array2(py, dummy)?.to_owned())
|
||||
Ok(ArrayConverter::from_array2(py, dummy)?.unbind())
|
||||
})
|
||||
}
|
||||
|
||||
fn fit_transform(&mut self, x: &PyAny) -> PyResult<Py<PyArray2<f64>>> {
|
||||
fn fit_transform<'py>(&mut self, x: &Bound<'py, PyAny>) -> PyResult<Py<PyArray2<f64>>> {
|
||||
self.fit(x)?;
|
||||
self.transform(x)
|
||||
}
|
||||
@@ -392,20 +392,20 @@ impl LabelEncoder {
|
||||
})
|
||||
}
|
||||
|
||||
fn fit(&mut self, y: &PyAny) -> PyResult<()> {
|
||||
fn fit<'py>(&mut self, _y: &Bound<'py, PyAny>) -> PyResult<()> {
|
||||
self.is_fitted = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transform(&self, y: &PyAny) -> PyResult<Py<PyArray1<i64>>> {
|
||||
fn transform<'py>(&self, _y: &Bound<'py, PyAny>) -> PyResult<Py<PyArray1<i64>>> {
|
||||
// Placeholder - return dummy labels
|
||||
Python::with_gil(|py| {
|
||||
let dummy = Array1::zeros(10);
|
||||
Ok(ArrayConverter::from_array1(py, dummy)?.to_owned())
|
||||
Ok(ArrayConverter::from_array1(py, dummy)?.unbind())
|
||||
})
|
||||
}
|
||||
|
||||
fn fit_transform(&mut self, y: &PyAny) -> PyResult<Py<PyArray1<i64>>> {
|
||||
fn fit_transform<'py>(&mut self, y: &Bound<'py, PyAny>) -> PyResult<Py<PyArray1<i64>>> {
|
||||
self.fit(y)?;
|
||||
self.transform(y)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
Simplified sklearn-compatible regressor wrappers
|
||||
*/
|
||||
|
||||
use ndarray::Array1;
|
||||
use numpy::{PyArray1, PyReadonlyArrayDyn};
|
||||
use numpy::ndarray::Array1;
|
||||
use numpy::{PyArray1, PyReadonlyArrayDyn, PyArrayMethods};
|
||||
use pyo3::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -44,7 +44,7 @@ impl LinearRegression {
|
||||
ArrayConverter::validate_fit_input(&x, Some(&y)).map_err(|e| PyErr::from(e))?;
|
||||
|
||||
let x_view = ArrayConverter::to_array_view2(&x).map_err(|e| PyErr::from(e))?;
|
||||
let y_view = ArrayConverter::to_array_view1(&y).map_err(|e| PyErr::from(e))?;
|
||||
let _y_view = ArrayConverter::to_array_view1(&y).map_err(|e| PyErr::from(e))?;
|
||||
|
||||
self.n_features_in = Some(x_view.shape()[1]);
|
||||
|
||||
@@ -81,15 +81,18 @@ impl LinearRegression {
|
||||
predictions[i] = sum + intercept;
|
||||
}
|
||||
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, predictions)?.to_owned()))
|
||||
Python::with_gil(|py| Ok(ArrayConverter::from_array1(py, predictions)?.unbind()))
|
||||
}
|
||||
|
||||
fn score(&self, x: PyReadonlyArrayDyn<f64>, y: PyReadonlyArrayDyn<f64>) -> PyResult<f64> {
|
||||
let predictions = self.predict(x)?;
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let pred_array = predictions.as_ref(py).readonly();
|
||||
let pred_view = ArrayConverter::to_dyn_view(&pred_array);
|
||||
use numpy::PyArrayMethods;
|
||||
let pred_bound = predictions.bind(py);
|
||||
let pred_array = pred_bound.readonly();
|
||||
// Convert Ix1 readonly array view to ndarray view directly
|
||||
let pred_view = pred_array.as_array();
|
||||
let y_view = ArrayConverter::to_array_view1(&y).map_err(|e| PyErr::from(e))?;
|
||||
|
||||
let y_mean = y_view.iter().sum::<f64>() / y_view.len() as f64;
|
||||
@@ -97,7 +100,7 @@ impl LinearRegression {
|
||||
let ss_res: f64 = pred_view
|
||||
.iter()
|
||||
.zip(y_view.iter())
|
||||
.map(|(pred, actual)| (actual - pred).powi(2))
|
||||
.map(|(pred, actual)| (actual - pred) as f64 * (actual - pred) as f64)
|
||||
.sum();
|
||||
|
||||
let ss_tot: f64 = y_view.iter().map(|actual| (actual - y_mean).powi(2)).sum();
|
||||
@@ -107,13 +110,14 @@ impl LinearRegression {
|
||||
}
|
||||
|
||||
fn get_params(&self) -> PyResult<HashMap<String, PyObject>> {
|
||||
use pyo3::IntoPyObjectExt;
|
||||
Python::with_gil(|py| {
|
||||
let mut params = HashMap::new();
|
||||
params.insert(
|
||||
"fit_intercept".to_string(),
|
||||
self.fit_intercept.to_object(py),
|
||||
self.fit_intercept.into_py_any(py)?,
|
||||
);
|
||||
params.insert("device".to_string(), self.device.to_string().to_object(py));
|
||||
params.insert("device".to_string(), self.device.to_string().into_py_any(py)?);
|
||||
Ok(params)
|
||||
})
|
||||
}
|
||||
@@ -123,7 +127,7 @@ impl LinearRegression {
|
||||
match &self.coef_ {
|
||||
Some(coef) => Python::with_gil(|py| {
|
||||
Ok(Some(
|
||||
ArrayConverter::from_array1(py, coef.clone())?.to_owned(),
|
||||
ArrayConverter::from_array1(py, coef.clone())?.unbind(),
|
||||
))
|
||||
}),
|
||||
None => Ok(None),
|
||||
|
||||
Reference in New Issue
Block a user