8 Commits

Author SHA1 Message Date
Lorenzo (Mec-iS)
13bb222ca7 Merge branch 'development' into kmeans-with-fastpair 2023-05-04 17:19:01 +01:00
Lorenzo (Mec-iS)
bf65fe3753 Merge branch 'march-2023-improvements' into kmeans-with-fastpair 2023-03-24 12:09:55 +09:00
Lorenzo (Mec-iS)
074cfaf14f rustfmt 2023-03-24 12:06:54 +09:00
Lorenzo
393cf15534 Merge branch 'development' into march-2023-improvements 2023-03-24 12:05:06 +09:00
Lorenzo (Mec-iS)
80c406b37d Merge branch 'development' of github.com:smartcorelib/smartcore into march-2023-improvements 2023-03-21 17:38:35 +09:00
Lorenzo (Mec-iS)
50e040a7a2 Merge branch 'development' of github.com:smartcorelib/smartcore into kmeans-with-fastpair 2023-03-21 17:38:06 +09:00
Lorenzo (Mec-iS)
8765bd2173 Add fit_with_centroids 2023-03-21 17:37:58 +09:00
Lorenzo (Mec-iS)
0e1bf6ce7f Add ordered_pairs method to FastPair 2023-03-21 14:46:33 +09:00
50 changed files with 694 additions and 1045 deletions
-6
View File
@@ -4,12 +4,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.0] - 2023-04-05
## Added
- WARNING: Breaking changes!
- `DenseMatrix` constructor now returns `Result` to avoid user instantiating inconsistent rows/cols count. Their return values need to be unwrapped with `unwrap()`, see tests
## [0.3.0] - 2022-11-09 ## [0.3.0] - 2022-11-09
## Added ## Added
+2 -2
View File
@@ -2,7 +2,7 @@
name = "smartcore" name = "smartcore"
description = "Machine Learning in Rust." description = "Machine Learning in Rust."
homepage = "https://smartcorelib.org" homepage = "https://smartcorelib.org"
version = "0.4.0" version = "0.3.2"
authors = ["smartcore Developers"] authors = ["smartcore Developers"]
edition = "2021" edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
@@ -48,7 +48,7 @@ getrandom = { version = "0.2.8", optional = true }
wasm-bindgen-test = "0.3" wasm-bindgen-test = "0.3"
[dev-dependencies] [dev-dependencies]
itertools = "0.12.0" itertools = "0.10.5"
serde_json = "1.0" serde_json = "1.0"
bincode = "1.3.1" bincode = "1.3.1"
+3 -4
View File
@@ -40,11 +40,11 @@ impl BBDTreeNode {
impl BBDTree { impl BBDTree {
pub fn new<T: Number, M: Array2<T>>(data: &M) -> BBDTree { pub fn new<T: Number, M: Array2<T>>(data: &M) -> BBDTree {
let nodes: Vec<BBDTreeNode> = Vec::new(); let nodes = Vec::new();
let (n, _) = data.shape(); let (n, _) = data.shape();
let index = (0..n).collect::<Vec<usize>>(); let index = (0..n).collect::<Vec<_>>();
let mut tree = BBDTree { let mut tree = BBDTree {
nodes, nodes,
@@ -343,8 +343,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let tree = BBDTree::new(&data); let tree = BBDTree::new(&data);
+57 -11
View File
@@ -17,7 +17,7 @@
/// &[4.6, 3.1, 1.5, 0.2], /// &[4.6, 3.1, 1.5, 0.2],
/// &[5.0, 3.6, 1.4, 0.2], /// &[5.0, 3.6, 1.4, 0.2],
/// &[5.4, 3.9, 1.7, 0.4], /// &[5.4, 3.9, 1.7, 0.4],
/// ]).unwrap(); /// ]);
/// let fastpair = FastPair::new(&x); /// let fastpair = FastPair::new(&x);
/// let closest_pair: PairwiseDistance<f64> = fastpair.unwrap().closest_pair(); /// let closest_pair: PairwiseDistance<f64> = fastpair.unwrap().closest_pair();
/// ``` /// ```
@@ -179,6 +179,21 @@ impl<'a, T: RealNumber + FloatNumber, M: Array2<T>> FastPair<'a, T, M> {
} }
} }
///
/// Return order dissimilarities from closest to furthest
///
#[allow(dead_code)]
pub fn ordered_pairs(&self) -> std::vec::IntoIter<&PairwiseDistance<T>> {
// improvement: implement this to return `impl Iterator<Item = &PairwiseDistance<T>>`
// need to implement trait `Iterator` for `Vec<&PairwiseDistance<T>>`
let mut distances = self
.distances
.values()
.collect::<Vec<&PairwiseDistance<T>>>();
distances.sort_by(|a, b| a.partial_cmp(b).unwrap());
distances.into_iter()
}
// //
// Compute distances from input to all other points in data-structure. // Compute distances from input to all other points in data-structure.
// input is the row index of the sample matrix // input is the row index of the sample matrix
@@ -271,7 +286,7 @@ mod tests_fastpair {
fn dataset_has_at_least_three_points() { fn dataset_has_at_least_three_points() {
// Create a dataset which consists of only two points: // Create a dataset which consists of only two points:
// A(0.0, 0.0) and B(1.0, 1.0). // A(0.0, 0.0) and B(1.0, 1.0).
let dataset = DenseMatrix::<f64>::from_2d_array(&[&[0.0, 0.0], &[1.0, 1.0]]).unwrap(); let dataset = DenseMatrix::<f64>::from_2d_array(&[&[0.0, 0.0], &[1.0, 1.0]]);
// We expect an error when we run `FastPair` on this dataset, // We expect an error when we run `FastPair` on this dataset,
// becuase `FastPair` currently only works on a minimum of 3 // becuase `FastPair` currently only works on a minimum of 3
@@ -288,7 +303,7 @@ mod tests_fastpair {
#[test] #[test]
fn one_dimensional_dataset_minimal() { fn one_dimensional_dataset_minimal() {
let dataset = DenseMatrix::<f64>::from_2d_array(&[&[0.0], &[2.0], &[9.0]]).unwrap(); let dataset = DenseMatrix::<f64>::from_2d_array(&[&[0.0], &[2.0], &[9.0]]);
let result = FastPair::new(&dataset); let result = FastPair::new(&dataset);
assert!(result.is_ok()); assert!(result.is_ok());
@@ -308,8 +323,7 @@ mod tests_fastpair {
#[test] #[test]
fn one_dimensional_dataset_2() { fn one_dimensional_dataset_2() {
let dataset = let dataset = DenseMatrix::<f64>::from_2d_array(&[&[27.0], &[0.0], &[9.0], &[2.0]]);
DenseMatrix::<f64>::from_2d_array(&[&[27.0], &[0.0], &[9.0], &[2.0]]).unwrap();
let result = FastPair::new(&dataset); let result = FastPair::new(&dataset);
assert!(result.is_ok()); assert!(result.is_ok());
@@ -344,8 +358,7 @@ mod tests_fastpair {
&[6.9, 3.1, 4.9, 1.5], &[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3], &[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5], &[6.5, 2.8, 4.6, 1.5],
]) ]);
.unwrap();
let fastpair = FastPair::new(&x); let fastpair = FastPair::new(&x);
assert!(fastpair.is_ok()); assert!(fastpair.is_ok());
@@ -518,8 +531,7 @@ mod tests_fastpair {
&[6.9, 3.1, 4.9, 1.5], &[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3], &[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5], &[6.5, 2.8, 4.6, 1.5],
]) ]);
.unwrap();
// compute // compute
let fastpair = FastPair::new(&x); let fastpair = FastPair::new(&x);
assert!(fastpair.is_ok()); assert!(fastpair.is_ok());
@@ -567,8 +579,7 @@ mod tests_fastpair {
&[6.9, 3.1, 4.9, 1.5], &[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3], &[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5], &[6.5, 2.8, 4.6, 1.5],
]) ]);
.unwrap();
// compute // compute
let fastpair = FastPair::new(&x); let fastpair = FastPair::new(&x);
assert!(fastpair.is_ok()); assert!(fastpair.is_ok());
@@ -594,4 +605,39 @@ mod tests_fastpair {
assert_eq!(closest, min_dissimilarity); assert_eq!(closest, min_dissimilarity);
} }
#[test]
fn fastpair_ordered_pairs() {
let x = DenseMatrix::<f64>::from_2d_array(&[
&[5.1, 3.5, 1.4, 0.2],
&[4.9, 3.0, 1.4, 0.2],
&[4.7, 3.2, 1.3, 0.2],
&[4.6, 3.1, 1.5, 0.2],
&[5.0, 3.6, 1.4, 0.2],
&[5.4, 3.9, 1.7, 0.4],
&[4.9, 3.1, 1.5, 0.1],
&[7.0, 3.2, 4.7, 1.4],
&[6.4, 3.2, 4.5, 1.5],
&[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5],
&[4.6, 3.4, 1.4, 0.3],
&[5.0, 3.4, 1.5, 0.2],
&[4.4, 2.9, 1.4, 0.2],
]);
let fastpair = FastPair::new(&x).unwrap();
let ordered = fastpair.ordered_pairs();
let mut previous: f64 = -1.0;
for p in ordered {
if previous == -1.0 {
previous = p.distance.unwrap();
} else {
let current = p.distance.unwrap();
assert!(current >= previous);
previous = current;
}
}
}
} }
+4 -5
View File
@@ -315,7 +315,8 @@ impl<TX: Number, TY: Number, X: Array2<TX>, Y: Array1<TY>, D: Distance<Vec<TX>>>
} }
} }
while let Some(neighbor) = neighbors.pop() { while !neighbors.is_empty() {
let neighbor = neighbors.pop().unwrap();
let index = neighbor.0; let index = neighbor.0;
if y[index] == outlier { if y[index] == outlier {
@@ -442,8 +443,7 @@ mod tests {
&[2.2, 1.2], &[2.2, 1.2],
&[1.8, 0.8], &[1.8, 0.8],
&[3.0, 5.0], &[3.0, 5.0],
]) ]);
.unwrap();
let expected_labels = vec![1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0]; let expected_labels = vec![1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0];
@@ -488,8 +488,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let dbscan = DBSCAN::fit(&x, Default::default()).unwrap(); let dbscan = DBSCAN::fit(&x, Default::default()).unwrap();
+181 -7
View File
@@ -41,7 +41,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! //!
//! let kmeans = KMeans::fit(&x, KMeansParameters::default().with_k(2)).unwrap(); // Fit to data, 2 clusters //! let kmeans = KMeans::fit(&x, KMeansParameters::default().with_k(2)).unwrap(); // Fit to data, 2 clusters
//! let y_hat: Vec<u8> = kmeans.predict(&x).unwrap(); // use the same points for prediction //! let y_hat: Vec<u8> = kmeans.predict(&x).unwrap(); // use the same points for prediction
@@ -62,7 +62,7 @@ use serde::{Deserialize, Serialize};
use crate::algorithm::neighbour::bbd_tree::BBDTree; use crate::algorithm::neighbour::bbd_tree::BBDTree;
use crate::api::{Predictor, UnsupervisedEstimator}; use crate::api::{Predictor, UnsupervisedEstimator};
use crate::error::Failed; use crate::error::Failed;
use crate::linalg::basic::arrays::{Array1, Array2}; use crate::linalg::basic::arrays::{Array1, Array2, Array};
use crate::metrics::distance::euclidian::*; use crate::metrics::distance::euclidian::*;
use crate::numbers::basenum::Number; use crate::numbers::basenum::Number;
use crate::rand_custom::get_rng_impl; use crate::rand_custom::get_rng_impl;
@@ -322,6 +322,109 @@ impl<TX: Number, TY: Number, X: Array2<TX>, Y: Array1<TY>> KMeans<TX, TY, X, Y>
}) })
} }
/// Fit algorithm to _NxM_ matrix where _N_ is number of samples and _M_ is number of features.
/// * `data` - training instances to cluster
/// * `parameters` - cluster parameters
/// * `centroids` - starting centroids
pub fn fit_with_centroids(
data: &X,
parameters: KMeansParameters,
centroids: Vec<Vec<f64>>,
) -> Result<KMeans<TX, TY, X, Y>, Failed> {
// TODO: reuse existing methods in `crate::metrics`
fn euclidean_distance(point1: &Vec<f64>, point2: &Vec<f64>) -> f64 {
let mut dist = 0.0;
for i in 0..point1.len() {
dist += (point1[i] - point2[i]).powi(2);
}
dist.sqrt()
}
fn closest_centroid(point: &Vec<f64>, centroids: &Vec<Vec<f64>>) -> usize {
let mut closest_idx = 0;
let mut closest_dist = std::f64::MAX;
for (i, centroid) in centroids.iter().enumerate() {
let dist = euclidean_distance(point, centroid);
if dist < closest_dist {
closest_dist = dist;
closest_idx = i;
}
}
closest_idx
}
let bbd = BBDTree::new(data);
if centroids.len() != parameters.k {
return Err(Failed::fit(&format!(
"number of centroids ({}) must be equal to k ({})",
centroids.len(),
parameters.k
)));
}
let mut y = vec![0; data.shape().0];
for i in 0..data.shape().0 {
y[i] = closest_centroid(
&Vec::from_iterator(data.get_row(i).iterator(0).map(|e| e.to_f64().unwrap()),
data.shape().1), &centroids
);
}
let mut size = vec![0; parameters.k];
let mut new_centroids = vec![vec![0f64; data.shape().1]; parameters.k];
for i in 0..data.shape().0 {
size[y[i]] += 1;
}
for i in 0..data.shape().0 {
for j in 0..data.shape().1 {
new_centroids[y[i]][j] += data.get((i, j)).to_f64().unwrap();
}
}
for i in 0..parameters.k {
for j in 0..data.shape().1 {
new_centroids[i][j] /= size[i] as f64;
}
}
let mut sums = vec![vec![0f64; data.shape().1]; parameters.k];
let mut distortion = std::f64::MAX;
for _ in 1..=parameters.max_iter {
let dist = bbd.clustering(&new_centroids, &mut sums, &mut size, &mut y);
for i in 0..parameters.k {
if size[i] > 0 {
for j in 0..data.shape().1 {
new_centroids[i][j] = sums[i][j] / size[i] as f64;
}
}
}
if distortion <= dist {
break;
} else {
distortion = dist;
}
}
Ok(KMeans {
k: parameters.k,
_y: y,
size,
_distortion: distortion,
centroids: new_centroids,
_phantom_tx: PhantomData,
_phantom_ty: PhantomData,
_phantom_x: PhantomData,
_phantom_y: PhantomData,
})
}
/// Predict clusters for `x` /// Predict clusters for `x`
/// * `x` - matrix with new data to transform of size _KxM_ , where _K_ is number of new samples and _M_ is number of features. /// * `x` - matrix with new data to transform of size _KxM_ , where _K_ is number of new samples and _M_ is number of features.
pub fn predict(&self, x: &X) -> Result<Y, Failed> { pub fn predict(&self, x: &X) -> Result<Y, Failed> {
@@ -417,6 +520,7 @@ impl<TX: Number, TY: Number, X: Array2<TX>, Y: Array1<TY>> KMeans<TX, TY, X, Y>
mod tests { mod tests {
use super::*; use super::*;
use crate::linalg::basic::matrix::DenseMatrix; use crate::linalg::basic::matrix::DenseMatrix;
use crate::algorithm::neighbour::fastpair;
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")), all(target_arch = "wasm32", not(target_os = "wasi")),
@@ -424,7 +528,7 @@ mod tests {
)] )]
#[test] #[test]
fn invalid_k() { fn invalid_k() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert!(KMeans::<i32, i32, DenseMatrix<i32>, Vec<i32>>::fit( assert!(KMeans::<i32, i32, DenseMatrix<i32>, Vec<i32>>::fit(
&x, &x,
@@ -492,8 +596,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let kmeans = KMeans::fit(&x, Default::default()).unwrap(); let kmeans = KMeans::fit(&x, Default::default()).unwrap();
@@ -504,6 +607,78 @@ mod tests {
} }
} }
#[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")),
wasm_bindgen_test::wasm_bindgen_test
)]
#[test]
fn fit_with_centroids_predict() {
let x = DenseMatrix::from_2d_array(&[
&[5.1, 3.5, 1.4, 0.2],
&[4.9, 3.0, 1.4, 0.2],
&[4.7, 3.2, 1.3, 0.2],
&[4.6, 3.1, 1.5, 0.2],
&[5.0, 3.6, 1.4, 0.2],
&[5.4, 3.9, 1.7, 0.4],
&[4.6, 3.4, 1.4, 0.3],
&[5.0, 3.4, 1.5, 0.2],
&[4.4, 2.9, 1.4, 0.2],
&[4.9, 3.1, 1.5, 0.1],
&[7.0, 3.2, 4.7, 1.4],
&[6.4, 3.2, 4.5, 1.5],
&[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5],
&[5.7, 2.8, 4.5, 1.3],
&[6.3, 3.3, 4.7, 1.6],
&[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4],
]);
let parameters = KMeansParameters {
k: 3,
max_iter: 50,
..Default::default()
};
// compute pairs
let fastpair = fastpair::FastPair::new(&x).unwrap();
// compute centroids for N closest pairs
let mut n: isize = 2;
let mut centroids = vec![vec![0f64; x.shape().1]; n as usize + 1];
for p in fastpair.ordered_pairs() {
if n == -1 {
break
}
centroids[n as usize] = {
let mut result: Vec<f64> = Vec::with_capacity(x.shape().1);
for val1 in x.get_row(p.node).iterator(0) {
for val2 in x.get_row(p.neighbour.unwrap()).iterator(0) {
let sum = val1 + val2;
let avg = sum * 0.5f64;
result.push(avg);
}
}
result
};
n -= 1;
}
let kmeans = KMeans::fit_with_centroids(
&x, parameters, centroids).unwrap();
let y: Vec<usize> = kmeans.predict(&x).unwrap();
for (i, _y_i) in y.iter().enumerate() {
assert_eq!({ y[i] }, kmeans._y[i]);
}
}
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")), all(target_arch = "wasm32", not(target_os = "wasi")),
wasm_bindgen_test::wasm_bindgen_test wasm_bindgen_test::wasm_bindgen_test
@@ -532,8 +707,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let kmeans: KMeans<f32, f32, DenseMatrix<f32>, Vec<f32>> = let kmeans: KMeans<f32, f32, DenseMatrix<f32>, Vec<f32>> =
KMeans::fit(&x, Default::default()).unwrap(); KMeans::fit(&x, Default::default()).unwrap();
+1 -1
View File
@@ -40,7 +40,7 @@ pub fn load_dataset() -> Dataset<f32, u32> {
target: y, target: y,
num_samples, num_samples,
num_features, num_features,
feature_names: [ feature_names: vec![
"Age", "Sex", "BMI", "BP", "S1", "S2", "S3", "S4", "S5", "S6", "Age", "Sex", "BMI", "BP", "S1", "S2", "S3", "S4", "S5", "S6",
] ]
.iter() .iter()
+5 -3
View File
@@ -25,14 +25,16 @@ pub fn load_dataset() -> Dataset<f32, f32> {
target: y, target: y,
num_samples, num_samples,
num_features, num_features,
feature_names: ["sepal length (cm)", feature_names: vec![
"sepal length (cm)",
"sepal width (cm)", "sepal width (cm)",
"petal length (cm)", "petal length (cm)",
"petal width (cm)"] "petal width (cm)",
]
.iter() .iter()
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(), .collect(),
target_names: ["setosa", "versicolor", "virginica"] target_names: vec!["setosa", "versicolor", "virginica"]
.iter() .iter()
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(), .collect(),
+2 -2
View File
@@ -36,7 +36,7 @@ pub fn load_dataset() -> Dataset<f32, u32> {
target: y, target: y,
num_samples, num_samples,
num_features, num_features,
feature_names: [ feature_names: vec![
"sepal length (cm)", "sepal length (cm)",
"sepal width (cm)", "sepal width (cm)",
"petal length (cm)", "petal length (cm)",
@@ -45,7 +45,7 @@ pub fn load_dataset() -> Dataset<f32, u32> {
.iter() .iter()
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(), .collect(),
target_names: ["setosa", "versicolor", "virginica"] target_names: vec!["setosa", "versicolor", "virginica"]
.iter() .iter()
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(), .collect(),
+7 -13
View File
@@ -35,7 +35,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! //!
//! let pca = PCA::fit(&iris, PCAParameters::default().with_n_components(2)).unwrap(); // Reduce number of features to 2 //! let pca = PCA::fit(&iris, PCAParameters::default().with_n_components(2)).unwrap(); // Reduce number of features to 2
//! //!
@@ -443,7 +443,6 @@ mod tests {
&[2.6, 53.0, 66.0, 10.8], &[2.6, 53.0, 66.0, 10.8],
&[6.8, 161.0, 60.0, 15.6], &[6.8, 161.0, 60.0, 15.6],
]) ])
.unwrap()
} }
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")), all(target_arch = "wasm32", not(target_os = "wasi")),
@@ -458,8 +457,7 @@ mod tests {
&[0.9952, 0.0588], &[0.9952, 0.0588],
&[0.0463, 0.9769], &[0.0463, 0.9769],
&[0.0752, 0.2007], &[0.0752, 0.2007],
]) ]);
.unwrap();
let pca = PCA::fit(&us_arrests, Default::default()).unwrap(); let pca = PCA::fit(&us_arrests, Default::default()).unwrap();
@@ -502,8 +500,7 @@ mod tests {
-0.974080592182491, -0.974080592182491,
0.0723250196376097, 0.0723250196376097,
], ],
]) ]);
.unwrap();
let expected_projection = DenseMatrix::from_2d_array(&[ let expected_projection = DenseMatrix::from_2d_array(&[
&[-64.8022, -11.448, 2.4949, -2.4079], &[-64.8022, -11.448, 2.4949, -2.4079],
@@ -556,8 +553,7 @@ mod tests {
&[91.5446, -22.9529, 0.402, -0.7369], &[91.5446, -22.9529, 0.402, -0.7369],
&[118.1763, 5.5076, 2.7113, -0.205], &[118.1763, 5.5076, 2.7113, -0.205],
&[10.4345, -5.9245, 3.7944, 0.5179], &[10.4345, -5.9245, 3.7944, 0.5179],
]) ]);
.unwrap();
let expected_eigenvalues: Vec<f64> = vec![ let expected_eigenvalues: Vec<f64> = vec![
343544.6277001563, 343544.6277001563,
@@ -620,8 +616,7 @@ mod tests {
-0.0881962972508558, -0.0881962972508558,
-0.0096011588898465, -0.0096011588898465,
], ],
]) ]);
.unwrap();
let expected_projection = DenseMatrix::from_2d_array(&[ let expected_projection = DenseMatrix::from_2d_array(&[
&[0.9856, -1.1334, 0.4443, -0.1563], &[0.9856, -1.1334, 0.4443, -0.1563],
@@ -674,8 +669,7 @@ mod tests {
&[-2.1086, -1.4248, -0.1048, -0.1319], &[-2.1086, -1.4248, -0.1048, -0.1319],
&[-2.0797, 0.6113, 0.1389, -0.1841], &[-2.0797, 0.6113, 0.1389, -0.1841],
&[-0.6294, -0.321, 0.2407, 0.1667], &[-0.6294, -0.321, 0.2407, 0.1667],
]) ]);
.unwrap();
let expected_eigenvalues: Vec<f64> = vec![ let expected_eigenvalues: Vec<f64> = vec![
2.480241579149493, 2.480241579149493,
@@ -738,7 +732,7 @@ mod tests {
// &[4.9, 2.4, 3.3, 1.0], // &[4.9, 2.4, 3.3, 1.0],
// &[6.6, 2.9, 4.6, 1.3], // &[6.6, 2.9, 4.6, 1.3],
// &[5.2, 2.7, 3.9, 1.4], // &[5.2, 2.7, 3.9, 1.4],
// ]).unwrap(); // ]);
// let pca = PCA::fit(&iris, Default::default()).unwrap(); // let pca = PCA::fit(&iris, Default::default()).unwrap();
+4 -6
View File
@@ -32,7 +32,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! //!
//! let svd = SVD::fit(&iris, SVDParameters::default(). //! let svd = SVD::fit(&iris, SVDParameters::default().
//! with_n_components(2)).unwrap(); // Reduce number of features to 2 //! with_n_components(2)).unwrap(); // Reduce number of features to 2
@@ -292,8 +292,7 @@ mod tests {
&[5.7, 81.0, 39.0, 9.3], &[5.7, 81.0, 39.0, 9.3],
&[2.6, 53.0, 66.0, 10.8], &[2.6, 53.0, 66.0, 10.8],
&[6.8, 161.0, 60.0, 15.6], &[6.8, 161.0, 60.0, 15.6],
]) ]);
.unwrap();
let expected = DenseMatrix::from_2d_array(&[ let expected = DenseMatrix::from_2d_array(&[
&[243.54655757, -18.76673788], &[243.54655757, -18.76673788],
@@ -301,8 +300,7 @@ mod tests {
&[305.93972467, -15.39087376], &[305.93972467, -15.39087376],
&[197.28420365, -11.66808306], &[197.28420365, -11.66808306],
&[293.43187394, 1.91163633], &[293.43187394, 1.91163633],
]) ]);
.unwrap();
let svd = SVD::fit(&x, Default::default()).unwrap(); let svd = SVD::fit(&x, Default::default()).unwrap();
let x_transformed = svd.transform(&x).unwrap(); let x_transformed = svd.transform(&x).unwrap();
@@ -343,7 +341,7 @@ mod tests {
// &[4.9, 2.4, 3.3, 1.0], // &[4.9, 2.4, 3.3, 1.0],
// &[6.6, 2.9, 4.6, 1.3], // &[6.6, 2.9, 4.6, 1.3],
// &[5.2, 2.7, 3.9, 1.4], // &[5.2, 2.7, 3.9, 1.4],
// ]).unwrap(); // ]);
// let svd = SVD::fit(&iris, Default::default()).unwrap(); // let svd = SVD::fit(&iris, Default::default()).unwrap();
+4 -104
View File
@@ -33,7 +33,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y = vec![ //! let y = vec![
//! 0, 0, 0, 0, 0, 0, 0, 0, //! 0, 0, 0, 0, 0, 0, 0, 0,
//! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -580,37 +580,6 @@ impl<TX: FloatNumber + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY
which_max(&result) which_max(&result)
} }
/// Predict the per-class probabilties for each observation.
/// The probability is calculated as the fraction of trees that predicted a given class
pub fn predict_proba<R: Array2<f64>>(&self, x: &X) -> Result<R, Failed> {
let mut result: R = R::zeros(x.shape().0, self.classes.as_ref().unwrap().len());
let (n, _) = x.shape();
for i in 0..n {
let row_probs = self.predict_proba_for_row(x, i);
for (j, item) in row_probs.iter().enumerate() {
result.set((i, j), *item);
}
}
Ok(result)
}
fn predict_proba_for_row(&self, x: &X, row: usize) -> Vec<f64> {
let mut result = vec![0; self.classes.as_ref().unwrap().len()];
for tree in self.trees.as_ref().unwrap().iter() {
result[tree.predict_for_row(x, row)] += 1;
}
result
.iter()
.map(|n| *n as f64 / self.trees.as_ref().unwrap().len() as f64)
.collect()
}
fn sample_with_replacement(y: &[usize], num_classes: usize, rng: &mut impl Rng) -> Vec<usize> { fn sample_with_replacement(y: &[usize], num_classes: usize, rng: &mut impl Rng) -> Vec<usize> {
let class_weight = vec![1.; num_classes]; let class_weight = vec![1.; num_classes];
let nrows = y.len(); let nrows = y.len();
@@ -638,7 +607,6 @@ impl<TX: FloatNumber + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::linalg::basic::arrays::Array;
use crate::linalg::basic::matrix::DenseMatrix; use crate::linalg::basic::matrix::DenseMatrix;
use crate::metrics::*; use crate::metrics::*;
@@ -692,8 +660,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let classifier = RandomForestClassifier::fit( let classifier = RandomForestClassifier::fit(
@@ -766,8 +733,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let classifier = RandomForestClassifier::fit( let classifier = RandomForestClassifier::fit(
@@ -820,8 +786,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let forest = RandomForestClassifier::fit(&x, &y, Default::default()).unwrap(); let forest = RandomForestClassifier::fit(&x, &y, Default::default()).unwrap();
@@ -831,69 +796,4 @@ mod tests {
assert_eq!(forest, deserialized_forest); assert_eq!(forest, deserialized_forest);
} }
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[test]
fn fit_predict_probabilities() {
let x = DenseMatrix::<f64>::from_2d_array(&[
&[5.1, 3.5, 1.4, 0.2],
&[4.9, 3.0, 1.4, 0.2],
&[4.7, 3.2, 1.3, 0.2],
&[4.6, 3.1, 1.5, 0.2],
&[5.0, 3.6, 1.4, 0.2],
&[5.4, 3.9, 1.7, 0.4],
&[4.6, 3.4, 1.4, 0.3],
&[5.0, 3.4, 1.5, 0.2],
&[4.4, 2.9, 1.4, 0.2],
&[4.9, 3.1, 1.5, 0.1],
&[7.0, 3.2, 4.7, 1.4],
&[6.4, 3.2, 4.5, 1.5],
&[6.9, 3.1, 4.9, 1.5],
&[5.5, 2.3, 4.0, 1.3],
&[6.5, 2.8, 4.6, 1.5],
&[5.7, 2.8, 4.5, 1.3],
&[6.3, 3.3, 4.7, 1.6],
&[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4],
]);
let y = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let classifier = RandomForestClassifier::fit(
&x,
&y,
RandomForestClassifierParameters {
criterion: SplitCriterion::Gini,
max_depth: None,
min_samples_leaf: 1,
min_samples_split: 2,
n_trees: 100, // this is n_estimators in sklearn
m: Option::None,
keep_samples: false,
seed: 0,
},
)
.unwrap();
println!("{:?}", classifier.classes);
let results: DenseMatrix<f64> = classifier.predict_proba(&x).unwrap();
println!("{:?}", x.shape());
println!("{:?}", results);
println!("{:?}", results.shape());
assert_eq!(
results,
DenseMatrix::<f64>::new(
20,
2,
vec![
1.0, 0.0, 0.78, 0.22, 0.95, 0.05, 0.82, 0.18, 1.0, 0.0, 0.92, 0.08, 0.99, 0.01,
0.96, 0.04, 0.36, 0.64, 0.33, 0.67, 0.02, 0.98, 0.02, 0.98, 0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0, 0.03, 0.97, 0.05, 0.95, 0.0, 1.0, 0.02, 0.98
],
true
)
);
}
} }
+4 -7
View File
@@ -29,7 +29,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! let y = vec![ //! let y = vec![
//! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, //! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2,
//! 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9 //! 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9
@@ -574,8 +574,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y = vec![ let y = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
@@ -649,8 +648,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y = vec![ let y = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
@@ -704,8 +702,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y = vec![ let y = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
-19
View File
@@ -32,8 +32,6 @@ pub enum FailedError {
SolutionFailed, SolutionFailed,
/// Error in input parameters /// Error in input parameters
ParametersError, ParametersError,
/// Invalid state error (should never happen)
InvalidStateError,
} }
impl Failed { impl Failed {
@@ -66,22 +64,6 @@ impl Failed {
} }
} }
/// new instance of `FailedError::ParametersError`
pub fn input(msg: &str) -> Self {
Failed {
err: FailedError::ParametersError,
msg: msg.to_string(),
}
}
/// new instance of `FailedError::InvalidStateError`
pub fn invalid_state(msg: &str) -> Self {
Failed {
err: FailedError::InvalidStateError,
msg: msg.to_string(),
}
}
/// new instance of `err` /// new instance of `err`
pub fn because(err: FailedError, msg: &str) -> Self { pub fn because(err: FailedError, msg: &str) -> Self {
Failed { Failed {
@@ -115,7 +97,6 @@ impl fmt::Display for FailedError {
FailedError::DecompositionFailed => "Decomposition failed", FailedError::DecompositionFailed => "Decomposition failed",
FailedError::SolutionFailed => "Can't find solution", FailedError::SolutionFailed => "Can't find solution",
FailedError::ParametersError => "Error in input, check parameters", FailedError::ParametersError => "Error in input, check parameters",
FailedError::InvalidStateError => "Invalid state, this should never happen", // useful in development phase of lib
}; };
write!(f, "{failed_err_str}") write!(f, "{failed_err_str}")
} }
+1 -1
View File
@@ -64,7 +64,7 @@
//! &[3., 4.], //! &[3., 4.],
//! &[5., 6.], //! &[5., 6.],
//! &[7., 8.], //! &[7., 8.],
//! &[9., 10.]]).unwrap(); //! &[9., 10.]]);
//! // Our classes are defined as a vector //! // Our classes are defined as a vector
//! let y = vec![2, 2, 2, 3, 3]; //! let y = vec![2, 2, 2, 3, 3];
//! //!
+88 -124
View File
@@ -188,7 +188,8 @@ pub trait ArrayView1<T: Debug + Display + Copy + Sized>: Array<T, usize> {
_ => max, _ => max,
} }
}; };
self.iterator(0).fold(T::min_value(), max_f) self.iterator(0)
.fold(T::min_value(), |max, x| max_f(max, x))
} }
/// return min value from the view /// return min value from the view
fn min(&self) -> T fn min(&self) -> T
@@ -201,7 +202,8 @@ pub trait ArrayView1<T: Debug + Display + Copy + Sized>: Array<T, usize> {
_ => min, _ => min,
} }
}; };
self.iterator(0).fold(T::max_value(), min_f) self.iterator(0)
.fold(T::max_value(), |max, x| min_f(max, x))
} }
/// return the position of the max value of the view /// return the position of the max value of the view
fn argmax(&self) -> usize fn argmax(&self) -> usize
@@ -1775,7 +1777,7 @@ mod tests {
#[test] #[test]
fn test_xa() { fn test_xa() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!(vec![7, 8].xa(false, &a), vec![39, 54, 69]); assert_eq!(vec![7, 8].xa(false, &a), vec![39, 54, 69]);
assert_eq!(vec![7, 8, 9].xa(true, &a), vec![50, 122]); assert_eq!(vec![7, 8, 9].xa(true, &a), vec![50, 122]);
} }
@@ -1783,27 +1785,19 @@ mod tests {
#[test] #[test]
fn test_min_max() { fn test_min_max() {
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]) DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).max(0),
.unwrap()
.max(0),
vec!(4, 5, 6) vec!(4, 5, 6)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]) DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).max(1),
.unwrap()
.max(1),
vec!(3, 6) vec!(3, 6)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]) DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).min(0),
.unwrap()
.min(0),
vec!(1., 2., 3.) vec!(1., 2., 3.)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]) DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).min(1),
.unwrap()
.min(1),
vec!(1., 4.) vec!(1., 4.)
); );
} }
@@ -1811,15 +1805,11 @@ mod tests {
#[test] #[test]
fn test_argmax() { fn test_argmax() {
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 5, 3], &[4, 2, 6]]) DenseMatrix::from_2d_array(&[&[1, 5, 3], &[4, 2, 6]]).argmax(0),
.unwrap()
.argmax(0),
vec!(1, 0, 1) vec!(1, 0, 1)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[4, 2, 3], &[1, 5, 6]]) DenseMatrix::from_2d_array(&[&[4, 2, 3], &[1, 5, 6]]).argmax(1),
.unwrap()
.argmax(1),
vec!(0, 2) vec!(0, 2)
); );
} }
@@ -1827,181 +1817,168 @@ mod tests {
#[test] #[test]
fn test_sum() { fn test_sum() {
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]) DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).sum(0),
.unwrap()
.sum(0),
vec!(5, 7, 9) vec!(5, 7, 9)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]) DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).sum(1),
.unwrap()
.sum(1),
vec!(6., 15.) vec!(6., 15.)
); );
} }
#[test] #[test]
fn test_abs() { fn test_abs() {
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]).unwrap(); let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]);
x.abs_mut(); x.abs_mut();
assert_eq!( assert_eq!(x, DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]));
x,
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap()
);
} }
#[test] #[test]
fn test_neg() { fn test_neg() {
let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]).unwrap(); let mut x = DenseMatrix::from_2d_array(&[&[-1, 2, -3], &[4, -5, 6]]);
x.neg_mut(); x.neg_mut();
assert_eq!( assert_eq!(x, DenseMatrix::from_2d_array(&[&[1, -2, 3], &[-4, 5, -6]]));
x,
DenseMatrix::from_2d_array(&[&[1, -2, 3], &[-4, 5, -6]]).unwrap()
);
} }
#[test] #[test]
fn test_copy_from() { fn test_copy_from() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let mut y = DenseMatrix::<i32>::zeros(2, 3); let mut y = DenseMatrix::<i32>::zeros(2, 3);
y.copy_from(&x); y.copy_from(&x);
assert_eq!( assert_eq!(y, DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]));
y,
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap()
);
} }
#[test] #[test]
fn test_init() { fn test_init() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!( assert_eq!(
DenseMatrix::<i32>::zeros(2, 2), DenseMatrix::<i32>::zeros(2, 2),
DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]]).unwrap() DenseMatrix::from_2d_array(&[&[0, 0], &[0, 0]])
); );
assert_eq!( assert_eq!(
DenseMatrix::<i32>::ones(2, 2), DenseMatrix::<i32>::ones(2, 2),
DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 1], &[1, 1]])
); );
assert_eq!( assert_eq!(
DenseMatrix::<i32>::eye(3), DenseMatrix::<i32>::eye(3),
DenseMatrix::from_2d_array(&[&[1, 0, 0], &[0, 1, 0], &[0, 0, 1]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 0, 0], &[0, 1, 0], &[0, 0, 1]])
); );
assert_eq!( assert_eq!(
DenseMatrix::from_slice(x.slice(0..2, 0..2).as_ref()), // internal only? DenseMatrix::from_slice(x.slice(0..2, 0..2).as_ref()),
DenseMatrix::from_2d_array(&[&[1, 2], &[4, 5]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2], &[4, 5]])
); );
assert_eq!( assert_eq!(
DenseMatrix::from_row(x.get_row(0).as_ref()), // internal only? DenseMatrix::from_row(x.get_row(0).as_ref()),
DenseMatrix::from_2d_array(&[&[1, 2, 3]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2, 3]])
); );
assert_eq!( assert_eq!(
DenseMatrix::from_column(x.get_col(0).as_ref()), // internal only? DenseMatrix::from_column(x.get_col(0).as_ref()),
DenseMatrix::from_2d_array(&[&[1], &[4]]).unwrap() DenseMatrix::from_2d_array(&[&[1], &[4]])
); );
} }
#[test] #[test]
fn test_transpose() { fn test_transpose() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!( assert_eq!(
x.transpose(), x.transpose(),
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]])
); );
} }
#[test] #[test]
fn test_reshape() { fn test_reshape() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!( assert_eq!(
x.reshape(3, 2, 0), x.reshape(3, 2, 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]])
); );
assert_eq!( assert_eq!(
x.reshape(3, 2, 1), x.reshape(3, 2, 1),
DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 4], &[2, 5], &[3, 6]])
); );
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_failed_reshape() { fn test_failed_reshape() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!( assert_eq!(
x.reshape(4, 2, 0), x.reshape(4, 2, 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]])
); );
} }
#[test] #[test]
fn test_matmul() { fn test_matmul() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
assert_eq!( assert_eq!(
a.matmul(&(*b.slice(0..3, 0..2))), a.matmul(&(*b.slice(0..3, 0..2))),
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]]).unwrap() DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]])
); );
assert_eq!( assert_eq!(
a.matmul(&b), a.matmul(&b),
DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]]).unwrap() DenseMatrix::from_2d_array(&[&[22, 28], &[49, 64]])
); );
} }
#[test] #[test]
fn test_concat() { fn test_concat() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]);
assert_eq!( assert_eq!(
DenseMatrix::concatenate_1d(&[&vec!(1, 2, 3), &vec!(4, 5, 6)], 0), DenseMatrix::concatenate_1d(&[&vec!(1, 2, 3), &vec!(4, 5, 6)], 0),
DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]])
); );
assert_eq!( assert_eq!(
DenseMatrix::concatenate_1d(&[&vec!(1, 2), &vec!(3, 4)], 1), DenseMatrix::concatenate_1d(&[&vec!(1, 2), &vec!(3, 4)], 1),
DenseMatrix::from_2d_array(&[&[1, 3], &[2, 4]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 3], &[2, 4]])
); );
assert_eq!( assert_eq!(
DenseMatrix::concatenate_2d(&[&a, &b], 0), DenseMatrix::concatenate_2d(&[&a, &b], 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]])
); );
assert_eq!( assert_eq!(
DenseMatrix::concatenate_2d(&[&a, &b], 1), DenseMatrix::concatenate_2d(&[&a, &b], 1),
DenseMatrix::from_2d_array(&[&[1, 2, 5, 6], &[3, 4, 7, 8]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2, 5, 6], &[3, 4, 7, 8]])
); );
} }
#[test] #[test]
fn test_take() { fn test_take() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
assert_eq!( assert_eq!(
a.take(&[0, 2], 1), a.take(&[0, 2], 1),
DenseMatrix::from_2d_array(&[&[1, 3], &[4, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 3], &[4, 6]])
); );
assert_eq!( assert_eq!(
b.take(&[0, 2], 0), b.take(&[0, 2], 0),
DenseMatrix::from_2d_array(&[&[1, 2], &[5, 6]]).unwrap() DenseMatrix::from_2d_array(&[&[1, 2], &[5, 6]])
); );
} }
#[test] #[test]
fn test_merge() { fn test_merge() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]).unwrap(), DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6], &[7, 8]]),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, true) a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, true)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8], &[1, 2], &[3, 4]]).unwrap(), DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8], &[1, 2], &[3, 4]]),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, false) a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 0, false)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2, 5, 7], &[3, 4, 6, 8]]).unwrap(), DenseMatrix::from_2d_array(&[&[1, 2, 5, 7], &[3, 4, 6, 8]]),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, true) a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, true)
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[5, 7, 1, 2], &[6, 8, 3, 4]]).unwrap(), DenseMatrix::from_2d_array(&[&[5, 7, 1, 2], &[6, 8, 3, 4]]),
a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, false) a.merge_1d(&[&vec!(5, 6), &vec!(7, 8)], 1, false)
); );
} }
@@ -2009,28 +1986,20 @@ mod tests {
#[test] #[test]
fn test_ops() { fn test_ops() {
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]) DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).mul_scalar(2),
.unwrap() DenseMatrix::from_2d_array(&[&[2, 4], &[6, 8]])
.mul_scalar(2),
DenseMatrix::from_2d_array(&[&[2, 4], &[6, 8]]).unwrap()
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]) DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).add_scalar(2),
.unwrap() DenseMatrix::from_2d_array(&[&[3, 4], &[5, 6]])
.add_scalar(2),
DenseMatrix::from_2d_array(&[&[3, 4], &[5, 6]]).unwrap()
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]) DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).sub_scalar(1),
.unwrap() DenseMatrix::from_2d_array(&[&[0, 1], &[2, 3]])
.sub_scalar(1),
DenseMatrix::from_2d_array(&[&[0, 1], &[2, 3]]).unwrap()
); );
assert_eq!( assert_eq!(
DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]) DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).div_scalar(2),
.unwrap() DenseMatrix::from_2d_array(&[&[0, 1], &[1, 2]])
.div_scalar(2),
DenseMatrix::from_2d_array(&[&[0, 1], &[1, 2]]).unwrap()
); );
} }
@@ -2044,45 +2013,42 @@ mod tests {
#[test] #[test]
fn test_vstack() { fn test_vstack() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let expected = DenseMatrix::from_2d_array(&[ let expected = DenseMatrix::from_2d_array(&[
&[1, 2, 3], &[1, 2, 3],
&[4, 5, 6], &[4, 5, 6],
&[7, 8, 9], &[7, 8, 9],
&[1, 2, 3], &[1, 2, 3],
&[4, 5, 6], &[4, 5, 6],
]) ]);
.unwrap();
let result = a.v_stack(&b); let result = a.v_stack(&b);
assert_eq!(result, expected); assert_eq!(result, expected);
} }
#[test] #[test]
fn test_hstack() { fn test_hstack() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
let expected = let expected =
DenseMatrix::from_2d_array(&[&[1, 2, 3, 1, 2], &[4, 5, 6, 3, 4], &[7, 8, 9, 5, 6]]) DenseMatrix::from_2d_array(&[&[1, 2, 3, 1, 2], &[4, 5, 6, 3, 4], &[7, 8, 9, 5, 6]]);
.unwrap();
let result = a.h_stack(&b); let result = a.h_stack(&b);
assert_eq!(result, expected); assert_eq!(result, expected);
} }
#[test] #[test]
fn test_map() { fn test_map() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]).unwrap(); let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]);
let result: DenseMatrix<f64> = a.map(|&v| v as f64); let result: DenseMatrix<f64> = a.map(|&v| v as f64);
assert_eq!(result, expected); assert_eq!(result, expected);
} }
#[test] #[test]
fn scale() { fn scale() {
let mut m = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).unwrap(); let mut m = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]);
let expected_0 = DenseMatrix::from_2d_array(&[&[-1., -1., -1.], &[1., 1., 1.]]).unwrap(); let expected_0 = DenseMatrix::from_2d_array(&[&[-1., -1., -1.], &[1., 1., 1.]]);
let expected_1 = let expected_1 = DenseMatrix::from_2d_array(&[&[-1.22, 0.0, 1.22], &[-1.22, 0.0, 1.22]]);
DenseMatrix::from_2d_array(&[&[-1.22, 0.0, 1.22], &[-1.22, 0.0, 1.22]]).unwrap();
{ {
let mut m = m.clone(); let mut m = m.clone();
@@ -2096,52 +2062,52 @@ mod tests {
#[test] #[test]
fn test_pow_mut() { fn test_pow_mut() {
let mut a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]).unwrap(); let mut a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]]);
a.pow_mut(2.0); a.pow_mut(2.0);
assert_eq!( assert_eq!(
a, a,
DenseMatrix::from_2d_array(&[&[1.0, 4.0, 9.0], &[16.0, 25.0, 36.0]]).unwrap() DenseMatrix::from_2d_array(&[&[1.0, 4.0, 9.0], &[16.0, 25.0, 36.0]])
); );
} }
#[test] #[test]
fn test_ab() { fn test_ab() {
let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4]]);
let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[5, 6], &[7, 8]]);
assert_eq!( assert_eq!(
a.ab(false, &b, false), a.ab(false, &b, false),
DenseMatrix::from_2d_array(&[&[19, 22], &[43, 50]]).unwrap() DenseMatrix::from_2d_array(&[&[19, 22], &[43, 50]])
); );
assert_eq!( assert_eq!(
a.ab(true, &b, false), a.ab(true, &b, false),
DenseMatrix::from_2d_array(&[&[26, 30], &[38, 44]]).unwrap() DenseMatrix::from_2d_array(&[&[26, 30], &[38, 44]])
); );
assert_eq!( assert_eq!(
a.ab(false, &b, true), a.ab(false, &b, true),
DenseMatrix::from_2d_array(&[&[17, 23], &[39, 53]]).unwrap() DenseMatrix::from_2d_array(&[&[17, 23], &[39, 53]])
); );
assert_eq!( assert_eq!(
a.ab(true, &b, true), a.ab(true, &b, true),
DenseMatrix::from_2d_array(&[&[23, 31], &[34, 46]]).unwrap() DenseMatrix::from_2d_array(&[&[23, 31], &[34, 46]])
); );
} }
#[test] #[test]
fn test_ax() { fn test_ax() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
assert_eq!( assert_eq!(
a.ax(false, &vec![7, 8, 9]).transpose(), a.ax(false, &vec![7, 8, 9]).transpose(),
DenseMatrix::from_2d_array(&[&[50, 122]]).unwrap() DenseMatrix::from_2d_array(&[&[50, 122]])
); );
assert_eq!( assert_eq!(
a.ax(true, &vec![7, 8]).transpose(), a.ax(true, &vec![7, 8]).transpose(),
DenseMatrix::from_2d_array(&[&[39, 54, 69]]).unwrap() DenseMatrix::from_2d_array(&[&[39, 54, 69]])
); );
} }
#[test] #[test]
fn diag() { fn diag() {
let x = DenseMatrix::from_2d_array(&[&[0, 1, 2], &[3, 4, 5], &[6, 7, 8]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[0, 1, 2], &[3, 4, 5], &[6, 7, 8]]);
assert_eq!(x.diag(), vec![0, 4, 8]); assert_eq!(x.diag(), vec![0, 4, 8]);
} }
@@ -2153,15 +2119,13 @@ mod tests {
&[68, 590, 37], &[68, 590, 37],
&[69, 660, 46], &[69, 660, 46],
&[73, 600, 55], &[73, 600, 55],
]) ]);
.unwrap();
let mut result = DenseMatrix::zeros(3, 3); let mut result = DenseMatrix::zeros(3, 3);
let expected = DenseMatrix::from_2d_array(&[ let expected = DenseMatrix::from_2d_array(&[
&[11.5, 50.0, 34.75], &[11.5, 50.0, 34.75],
&[50.0, 1250.0, 205.0], &[50.0, 1250.0, 205.0],
&[34.75, 205.0, 110.0], &[34.75, 205.0, 110.0],
]) ]);
.unwrap();
a.cov(&mut result); a.cov(&mut result);
+79 -208
View File
@@ -19,8 +19,6 @@ use crate::linalg::traits::svd::SVDDecomposable;
use crate::numbers::basenum::Number; use crate::numbers::basenum::Number;
use crate::numbers::realnum::RealNumber; use crate::numbers::realnum::RealNumber;
use crate::error::Failed;
/// Dense matrix /// Dense matrix
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -52,26 +50,26 @@ pub struct DenseMatrixMutView<'a, T: Debug + Display + Copy + Sized> {
} }
impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> { impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixView<'a, T> {
fn new( fn new(m: &'a DenseMatrix<T>, rows: Range<usize>, cols: Range<usize>) -> Self {
m: &'a DenseMatrix<T>, let (start, end, stride) = if m.column_major {
vrows: Range<usize>, (
vcols: Range<usize>, rows.start + cols.start * m.nrows,
) -> Result<Self, Failed> { rows.end + (cols.end - 1) * m.nrows,
if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) { m.nrows,
Err(Failed::input( )
"The specified view is outside of the matrix range",
))
} else { } else {
let (start, end, stride) = (
m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major); rows.start * m.ncols + cols.start,
(rows.end - 1) * m.ncols + cols.end,
Ok(DenseMatrixView { m.ncols,
values: &m.values[start..end], )
stride, };
nrows: vrows.end - vrows.start, DenseMatrixView {
ncols: vcols.end - vcols.start, values: &m.values[start..end],
column_major: m.column_major, stride,
}) nrows: rows.end - rows.start,
ncols: cols.end - cols.start,
column_major: m.column_major,
} }
} }
@@ -104,26 +102,26 @@ impl<'a, T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrixView<'a,
} }
impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> { impl<'a, T: Debug + Display + Copy + Sized> DenseMatrixMutView<'a, T> {
fn new( fn new(m: &'a mut DenseMatrix<T>, rows: Range<usize>, cols: Range<usize>) -> Self {
m: &'a mut DenseMatrix<T>, let (start, end, stride) = if m.column_major {
vrows: Range<usize>, (
vcols: Range<usize>, rows.start + cols.start * m.nrows,
) -> Result<Self, Failed> { rows.end + (cols.end - 1) * m.nrows,
if m.is_valid_view(m.shape().0, m.shape().1, &vrows, &vcols) { m.nrows,
Err(Failed::input( )
"The specified view is outside of the matrix range",
))
} else { } else {
let (start, end, stride) = (
m.stride_range(m.shape().0, m.shape().1, &vrows, &vcols, m.column_major); rows.start * m.ncols + cols.start,
(rows.end - 1) * m.ncols + cols.end,
Ok(DenseMatrixMutView { m.ncols,
values: &mut m.values[start..end], )
stride, };
nrows: vrows.end - vrows.start, DenseMatrixMutView {
ncols: vcols.end - vcols.start, values: &mut m.values[start..end],
column_major: m.column_major, stride,
}) nrows: rows.end - rows.start,
ncols: cols.end - cols.start,
column_major: m.column_major,
} }
} }
@@ -184,102 +182,42 @@ impl<'a, T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrixMutView<
impl<T: Debug + Display + Copy + Sized> DenseMatrix<T> { impl<T: Debug + Display + Copy + Sized> DenseMatrix<T> {
/// Create new instance of `DenseMatrix` without copying data. /// Create new instance of `DenseMatrix` without copying data.
/// `values` should be in column-major order. /// `values` should be in column-major order.
pub fn new( pub fn new(nrows: usize, ncols: usize, values: Vec<T>, column_major: bool) -> Self {
nrows: usize, DenseMatrix {
ncols: usize, ncols,
values: Vec<T>, nrows,
column_major: bool, values,
) -> Result<Self, Failed> { column_major,
let data_len = values.len();
if nrows * ncols != values.len() {
Err(Failed::input(&format!(
"The specified shape: (cols: {ncols}, rows: {nrows}) does not align with data len: {data_len}"
)))
} else {
Ok(DenseMatrix {
ncols,
nrows,
values,
column_major,
})
} }
} }
/// New instance of `DenseMatrix` from 2d array. /// New instance of `DenseMatrix` from 2d array.
pub fn from_2d_array(values: &[&[T]]) -> Result<Self, Failed> { pub fn from_2d_array(values: &[&[T]]) -> Self {
DenseMatrix::from_2d_vec(&values.iter().map(|row| Vec::from(*row)).collect()) DenseMatrix::from_2d_vec(&values.iter().map(|row| Vec::from(*row)).collect())
} }
/// New instance of `DenseMatrix` from 2d vector. /// New instance of `DenseMatrix` from 2d vector.
#[allow(clippy::ptr_arg)] pub fn from_2d_vec(values: &Vec<Vec<T>>) -> Self {
pub fn from_2d_vec(values: &Vec<Vec<T>>) -> Result<Self, Failed> { let nrows = values.len();
if values.is_empty() || values[0].is_empty() { let ncols = values
Err(Failed::input( .first()
"The 2d vec provided is empty; cannot instantiate the matrix", .unwrap_or_else(|| panic!("Cannot create 2d matrix from an empty vector"))
)) .len();
} else { let mut m_values = Vec::with_capacity(nrows * ncols);
let nrows = values.len();
let ncols = values
.first()
.unwrap_or_else(|| {
panic!("Invalid state: Cannot create 2d matrix from an empty vector")
})
.len();
let mut m_values = Vec::with_capacity(nrows * ncols);
for c in 0..ncols { for c in 0..ncols {
for r in values.iter().take(nrows) { for r in values.iter().take(nrows) {
m_values.push(r[c]) m_values.push(r[c])
}
} }
DenseMatrix::new(nrows, ncols, m_values, true)
} }
DenseMatrix::new(nrows, ncols, m_values, true)
} }
/// Iterate over values of matrix /// Iterate over values of matrix
pub fn iter(&self) -> Iter<'_, T> { pub fn iter(&self) -> Iter<'_, T> {
self.values.iter() self.values.iter()
} }
/// Check if the size of the requested view is bounded to matrix rows/cols count
fn is_valid_view(
&self,
n_rows: usize,
n_cols: usize,
vrows: &Range<usize>,
vcols: &Range<usize>,
) -> bool {
!(vrows.end <= n_rows
&& vcols.end <= n_cols
&& vrows.start <= n_rows
&& vcols.start <= n_cols)
}
/// Compute the range of the requested view: start, end, size of the slice
fn stride_range(
&self,
n_rows: usize,
n_cols: usize,
vrows: &Range<usize>,
vcols: &Range<usize>,
column_major: bool,
) -> (usize, usize, usize) {
let (start, end, stride) = if column_major {
(
vrows.start + vcols.start * n_rows,
vrows.end + (vcols.end - 1) * n_rows,
n_rows,
)
} else {
(
vrows.start * n_cols + vcols.start,
(vrows.end - 1) * n_cols + vcols.end,
n_cols,
)
};
(start, end, stride)
}
} }
impl<T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrix<T> { impl<T: Debug + Display + Copy + Sized> fmt::Display for DenseMatrix<T> {
@@ -366,7 +304,6 @@ where
impl<T: Debug + Display + Copy + Sized> Array<T, (usize, usize)> for DenseMatrix<T> { impl<T: Debug + Display + Copy + Sized> Array<T, (usize, usize)> for DenseMatrix<T> {
fn get(&self, pos: (usize, usize)) -> &T { fn get(&self, pos: (usize, usize)) -> &T {
let (row, col) = pos; let (row, col) = pos;
if row >= self.nrows || col >= self.ncols { if row >= self.nrows || col >= self.ncols {
panic!( panic!(
"Invalid index ({},{}) for {}x{} matrix", "Invalid index ({},{}) for {}x{} matrix",
@@ -446,15 +383,15 @@ impl<T: Debug + Display + Copy + Sized> MutArrayView2<T> for DenseMatrix<T> {}
impl<T: Debug + Display + Copy + Sized> Array2<T> for DenseMatrix<T> { impl<T: Debug + Display + Copy + Sized> Array2<T> for DenseMatrix<T> {
fn get_row<'a>(&'a self, row: usize) -> Box<dyn ArrayView1<T> + 'a> { fn get_row<'a>(&'a self, row: usize) -> Box<dyn ArrayView1<T> + 'a> {
Box::new(DenseMatrixView::new(self, row..row + 1, 0..self.ncols).unwrap()) Box::new(DenseMatrixView::new(self, row..row + 1, 0..self.ncols))
} }
fn get_col<'a>(&'a self, col: usize) -> Box<dyn ArrayView1<T> + 'a> { fn get_col<'a>(&'a self, col: usize) -> Box<dyn ArrayView1<T> + 'a> {
Box::new(DenseMatrixView::new(self, 0..self.nrows, col..col + 1).unwrap()) Box::new(DenseMatrixView::new(self, 0..self.nrows, col..col + 1))
} }
fn slice<'a>(&'a self, rows: Range<usize>, cols: Range<usize>) -> Box<dyn ArrayView2<T> + 'a> { fn slice<'a>(&'a self, rows: Range<usize>, cols: Range<usize>) -> Box<dyn ArrayView2<T> + 'a> {
Box::new(DenseMatrixView::new(self, rows, cols).unwrap()) Box::new(DenseMatrixView::new(self, rows, cols))
} }
fn slice_mut<'a>( fn slice_mut<'a>(
@@ -465,17 +402,15 @@ impl<T: Debug + Display + Copy + Sized> Array2<T> for DenseMatrix<T> {
where where
Self: Sized, Self: Sized,
{ {
Box::new(DenseMatrixMutView::new(self, rows, cols).unwrap()) Box::new(DenseMatrixMutView::new(self, rows, cols))
} }
// private function so for now assume infalible
fn fill(nrows: usize, ncols: usize, value: T) -> Self { fn fill(nrows: usize, ncols: usize, value: T) -> Self {
DenseMatrix::new(nrows, ncols, vec![value; nrows * ncols], true).unwrap() DenseMatrix::new(nrows, ncols, vec![value; nrows * ncols], true)
} }
// private function so for now assume infalible
fn from_iterator<I: Iterator<Item = T>>(iter: I, nrows: usize, ncols: usize, axis: u8) -> Self { fn from_iterator<I: Iterator<Item = T>>(iter: I, nrows: usize, ncols: usize, axis: u8) -> Self {
DenseMatrix::new(nrows, ncols, iter.collect(), axis != 0).unwrap() DenseMatrix::new(nrows, ncols, iter.collect(), axis != 0)
} }
fn transpose(&self) -> Self { fn transpose(&self) -> Self {
@@ -608,75 +543,16 @@ mod tests {
use super::*; use super::*;
use approx::relative_eq; use approx::relative_eq;
#[test]
fn test_instantiate_from_2d() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
assert!(x.is_ok());
}
#[test]
fn test_instantiate_from_2d_empty() {
let input: &[&[f64]] = &[&[]];
let x = DenseMatrix::from_2d_array(input);
assert!(x.is_err());
}
#[test]
fn test_instantiate_from_2d_empty2() {
let input: &[&[f64]] = &[&[], &[]];
let x = DenseMatrix::from_2d_array(input);
assert!(x.is_err());
}
#[test]
fn test_instantiate_ok_view1() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..2, 0..2);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view2() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view3() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 2..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_ok_view4() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 3..3, 0..3);
assert!(v.is_ok());
}
#[test]
fn test_instantiate_err_view1() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 3..4, 0..3);
assert!(v.is_err());
}
#[test]
fn test_instantiate_err_view2() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 3..4);
assert!(v.is_err());
}
#[test]
fn test_instantiate_err_view3() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap();
let v = DenseMatrixView::new(&x, 0..3, 4..3);
assert!(v.is_err());
}
#[test] #[test]
fn test_display() { fn test_display() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
println!("{}", &x); println!("{}", &x);
} }
#[test] #[test]
fn test_get_row_col() { fn test_get_row_col() {
let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
assert_eq!(15.0, x.get_col(1).sum()); assert_eq!(15.0, x.get_col(1).sum());
assert_eq!(15.0, x.get_row(1).sum()); assert_eq!(15.0, x.get_row(1).sum());
@@ -685,7 +561,7 @@ mod tests {
#[test] #[test]
fn test_row_major() { fn test_row_major() {
let mut x = DenseMatrix::new(2, 3, vec![1, 2, 3, 4, 5, 6], false).unwrap(); let mut x = DenseMatrix::new(2, 3, vec![1, 2, 3, 4, 5, 6], false);
assert_eq!(5, *x.get_col(1).get(1)); assert_eq!(5, *x.get_col(1).get(1));
assert_eq!(7, x.get_col(1).sum()); assert_eq!(7, x.get_col(1).sum());
@@ -699,8 +575,7 @@ mod tests {
#[test] #[test]
fn test_get_slice() { fn test_get_slice() {
let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]) let x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]);
.unwrap();
assert_eq!( assert_eq!(
vec![4, 5, 6], vec![4, 5, 6],
@@ -714,7 +589,7 @@ mod tests {
#[test] #[test]
fn test_iter_mut() { fn test_iter_mut() {
let mut x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap(); let mut x = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
assert_eq!(vec![1, 4, 7, 2, 5, 8, 3, 6, 9], x.values); assert_eq!(vec![1, 4, 7, 2, 5, 8, 3, 6, 9], x.values);
// add +2 to some elements // add +2 to some elements
@@ -750,8 +625,7 @@ mod tests {
#[test] #[test]
fn test_str_array() { fn test_str_array() {
let mut x = let mut x =
DenseMatrix::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"], &["7", "8", "9"]]) DenseMatrix::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"], &["7", "8", "9"]]);
.unwrap();
assert_eq!(vec!["1", "4", "7", "2", "5", "8", "3", "6", "9"], x.values); assert_eq!(vec!["1", "4", "7", "2", "5", "8", "3", "6", "9"], x.values);
x.iterator_mut(0).for_each(|v| *v = "str"); x.iterator_mut(0).for_each(|v| *v = "str");
@@ -763,7 +637,7 @@ mod tests {
#[test] #[test]
fn test_transpose() { fn test_transpose() {
let x = DenseMatrix::<&str>::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"]]).unwrap(); let x = DenseMatrix::<&str>::from_2d_array(&[&["1", "2", "3"], &["4", "5", "6"]]);
assert_eq!(vec!["1", "4", "2", "5", "3", "6"], x.values); assert_eq!(vec!["1", "4", "2", "5", "3", "6"], x.values);
assert!(x.column_major); assert!(x.column_major);
@@ -776,7 +650,7 @@ mod tests {
#[test] #[test]
fn test_from_iterator() { fn test_from_iterator() {
let data = [1, 2, 3, 4, 5, 6]; let data = vec![1, 2, 3, 4, 5, 6];
let m = DenseMatrix::from_iterator(data.iter(), 2, 3, 0); let m = DenseMatrix::from_iterator(data.iter(), 2, 3, 0);
@@ -790,8 +664,8 @@ mod tests {
#[test] #[test]
fn test_take() { fn test_take() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6]]);
let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1, 2], &[3, 4], &[5, 6]]);
println!("{a}"); println!("{a}");
// take column 0 and 2 // take column 0 and 2
@@ -803,7 +677,7 @@ mod tests {
#[test] #[test]
fn test_mut() { fn test_mut() {
let a = DenseMatrix::from_2d_array(&[&[1.3, -2.1, 3.4], &[-4., -5.3, 6.1]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1.3, -2.1, 3.4], &[-4., -5.3, 6.1]]);
let a = a.abs(); let a = a.abs();
assert_eq!(vec![1.3, 4.0, 2.1, 5.3, 3.4, 6.1], a.values); assert_eq!(vec![1.3, 4.0, 2.1, 5.3, 3.4, 6.1], a.values);
@@ -814,8 +688,7 @@ mod tests {
#[test] #[test]
fn test_reshape() { fn test_reshape() {
let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]) let a = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9], &[10, 11, 12]]);
.unwrap();
let a = a.reshape(2, 6, 0); let a = a.reshape(2, 6, 0);
assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], a.values); assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], a.values);
@@ -828,15 +701,13 @@ mod tests {
#[test] #[test]
fn test_eq() { fn test_eq() {
let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.]]);
let b = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]).unwrap(); let b = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[4., 5., 6.], &[7., 8., 9.]]);
let c = DenseMatrix::from_2d_array(&[ let c = DenseMatrix::from_2d_array(&[
&[1. + f32::EPSILON, 2., 3.], &[1. + f32::EPSILON, 2., 3.],
&[4., 5., 6. + f32::EPSILON], &[4., 5., 6. + f32::EPSILON],
]) ]);
.unwrap(); let d = DenseMatrix::from_2d_array(&[&[1. + 0.5, 2., 3.], &[4., 5., 6. + f32::EPSILON]]);
let d = DenseMatrix::from_2d_array(&[&[1. + 0.5, 2., 3.], &[4., 5., 6. + f32::EPSILON]])
.unwrap();
assert!(!relative_eq!(a, b)); assert!(!relative_eq!(a, b));
assert!(!relative_eq!(a, d)); assert!(!relative_eq!(a, d));
+1 -2
View File
@@ -55,7 +55,6 @@ impl<T: Debug + Display + Copy + Sized> Array<T, usize> for Vec<T> {
impl<T: Debug + Display + Copy + Sized> MutArray<T, usize> for Vec<T> { impl<T: Debug + Display + Copy + Sized> MutArray<T, usize> for Vec<T> {
fn set(&mut self, i: usize, x: T) { fn set(&mut self, i: usize, x: T) {
// NOTE: this panics in case of out of bounds index
self[i] = x self[i] = x
} }
@@ -212,7 +211,7 @@ mod tests {
#[test] #[test]
fn test_len() { fn test_len() {
let x = [1, 2, 3]; let x = vec![1, 2, 3];
assert_eq!(3, x.len()); assert_eq!(3, x.len());
} }
+7 -11
View File
@@ -15,7 +15,7 @@
//! &[25., 15., -5.], //! &[25., 15., -5.],
//! &[15., 18., 0.], //! &[15., 18., 0.],
//! &[-5., 0., 11.] //! &[-5., 0., 11.]
//! ]).unwrap(); //! ]);
//! //!
//! let cholesky = A.cholesky().unwrap(); //! let cholesky = A.cholesky().unwrap();
//! let lower_triangular: DenseMatrix<f64> = cholesky.L(); //! let lower_triangular: DenseMatrix<f64> = cholesky.L();
@@ -175,14 +175,11 @@ mod tests {
)] )]
#[test] #[test]
fn cholesky_decompose() { fn cholesky_decompose() {
let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]);
.unwrap();
let l = let l =
DenseMatrix::from_2d_array(&[&[5.0, 0.0, 0.0], &[3.0, 3.0, 0.0], &[-1.0, 1.0, 3.0]]) DenseMatrix::from_2d_array(&[&[5.0, 0.0, 0.0], &[3.0, 3.0, 0.0], &[-1.0, 1.0, 3.0]]);
.unwrap();
let u = let u =
DenseMatrix::from_2d_array(&[&[5.0, 3.0, -1.0], &[0.0, 3.0, 1.0], &[0.0, 0.0, 3.0]]) DenseMatrix::from_2d_array(&[&[5.0, 3.0, -1.0], &[0.0, 3.0, 1.0], &[0.0, 0.0, 3.0]]);
.unwrap();
let cholesky = a.cholesky().unwrap(); let cholesky = a.cholesky().unwrap();
assert!(relative_eq!(cholesky.L().abs(), l.abs(), epsilon = 1e-4)); assert!(relative_eq!(cholesky.L().abs(), l.abs(), epsilon = 1e-4));
@@ -200,10 +197,9 @@ mod tests {
)] )]
#[test] #[test]
fn cholesky_solve_mut() { fn cholesky_solve_mut() {
let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]);
.unwrap(); let b = DenseMatrix::from_2d_array(&[&[40., 51., 28.]]);
let b = DenseMatrix::from_2d_array(&[&[40., 51., 28.]]).unwrap(); let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0]]);
let expected = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0]]).unwrap();
let cholesky = a.cholesky().unwrap(); let cholesky = a.cholesky().unwrap();
+7 -13
View File
@@ -19,7 +19,7 @@
//! &[0.9000, 0.4000, 0.7000], //! &[0.9000, 0.4000, 0.7000],
//! &[0.4000, 0.5000, 0.3000], //! &[0.4000, 0.5000, 0.3000],
//! &[0.7000, 0.3000, 0.8000], //! &[0.7000, 0.3000, 0.8000],
//! ]).unwrap(); //! ]);
//! //!
//! let evd = A.evd(true).unwrap(); //! let evd = A.evd(true).unwrap();
//! let eigenvectors: DenseMatrix<f64> = evd.V; //! let eigenvectors: DenseMatrix<f64> = evd.V;
@@ -820,8 +820,7 @@ mod tests {
&[0.9000, 0.4000, 0.7000], &[0.9000, 0.4000, 0.7000],
&[0.4000, 0.5000, 0.3000], &[0.4000, 0.5000, 0.3000],
&[0.7000, 0.3000, 0.8000], &[0.7000, 0.3000, 0.8000],
]) ]);
.unwrap();
let eigen_values: Vec<f64> = vec![1.7498382, 0.3165784, 0.1335834]; let eigen_values: Vec<f64> = vec![1.7498382, 0.3165784, 0.1335834];
@@ -829,8 +828,7 @@ mod tests {
&[0.6881997, -0.07121225, 0.7220180], &[0.6881997, -0.07121225, 0.7220180],
&[0.3700456, 0.89044952, -0.2648886], &[0.3700456, 0.89044952, -0.2648886],
&[0.6240573, -0.44947578, -0.6391588], &[0.6240573, -0.44947578, -0.6391588],
]) ]);
.unwrap();
let evd = A.evd(true).unwrap(); let evd = A.evd(true).unwrap();
@@ -854,8 +852,7 @@ mod tests {
&[0.9000, 0.4000, 0.7000], &[0.9000, 0.4000, 0.7000],
&[0.4000, 0.5000, 0.3000], &[0.4000, 0.5000, 0.3000],
&[0.8000, 0.3000, 0.8000], &[0.8000, 0.3000, 0.8000],
]) ]);
.unwrap();
let eigen_values: Vec<f64> = vec![1.79171122, 0.31908143, 0.08920735]; let eigen_values: Vec<f64> = vec![1.79171122, 0.31908143, 0.08920735];
@@ -863,8 +860,7 @@ mod tests {
&[0.7178958, 0.05322098, 0.6812010], &[0.7178958, 0.05322098, 0.6812010],
&[0.3837711, -0.84702111, -0.1494582], &[0.3837711, -0.84702111, -0.1494582],
&[0.6952105, 0.43984484, -0.7036135], &[0.6952105, 0.43984484, -0.7036135],
]) ]);
.unwrap();
let evd = A.evd(false).unwrap(); let evd = A.evd(false).unwrap();
@@ -889,8 +885,7 @@ mod tests {
&[4.0, -1.0, 1.0, 1.0], &[4.0, -1.0, 1.0, 1.0],
&[1.0, 1.0, 3.0, -2.0], &[1.0, 1.0, 3.0, -2.0],
&[1.0, 1.0, 4.0, -1.0], &[1.0, 1.0, 4.0, -1.0],
]) ]);
.unwrap();
let eigen_values_d: Vec<f64> = vec![0.0, 2.0, 2.0, 0.0]; let eigen_values_d: Vec<f64> = vec![0.0, 2.0, 2.0, 0.0];
let eigen_values_e: Vec<f64> = vec![2.2361, 0.9999, -0.9999, -2.2361]; let eigen_values_e: Vec<f64> = vec![2.2361, 0.9999, -0.9999, -2.2361];
@@ -900,8 +895,7 @@ mod tests {
&[-0.6707, 0.1059, 0.901, 0.6289], &[-0.6707, 0.1059, 0.901, 0.6289],
&[0.9159, -0.1378, 0.3816, 0.0806], &[0.9159, -0.1378, 0.3816, 0.0806],
&[0.6707, 0.1059, 0.901, -0.6289], &[0.6707, 0.1059, 0.901, -0.6289],
]) ]);
.unwrap();
let evd = A.evd(false).unwrap(); let evd = A.evd(false).unwrap();
+3 -3
View File
@@ -12,9 +12,9 @@ pub trait HighOrderOperations<T: Number>: Array2<T> {
/// use smartcore::linalg::traits::high_order::HighOrderOperations; /// use smartcore::linalg::traits::high_order::HighOrderOperations;
/// use smartcore::linalg::basic::arrays::Array2; /// use smartcore::linalg::basic::arrays::Array2;
/// ///
/// let a = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.]]).unwrap(); /// let a = DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.]]);
/// let b = DenseMatrix::from_2d_array(&[&[5., 6.], &[7., 8.], &[9., 10.]]).unwrap(); /// let b = DenseMatrix::from_2d_array(&[&[5., 6.], &[7., 8.], &[9., 10.]]);
/// let expected = DenseMatrix::from_2d_array(&[&[71., 80.], &[92., 104.]]).unwrap(); /// let expected = DenseMatrix::from_2d_array(&[&[71., 80.], &[92., 104.]]);
/// ///
/// assert_eq!(a.ab(true, &b, false), expected); /// assert_eq!(a.ab(true, &b, false), expected);
/// ``` /// ```
+7 -8
View File
@@ -18,7 +18,7 @@
//! &[1., 2., 3.], //! &[1., 2., 3.],
//! &[0., 1., 5.], //! &[0., 1., 5.],
//! &[5., 6., 0.] //! &[5., 6., 0.]
//! ]).unwrap(); //! ]);
//! //!
//! let lu = A.lu().unwrap(); //! let lu = A.lu().unwrap();
//! let lower: DenseMatrix<f64> = lu.L(); //! let lower: DenseMatrix<f64> = lu.L();
@@ -263,13 +263,13 @@ mod tests {
)] )]
#[test] #[test]
fn decompose() { fn decompose() {
let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]);
let expected_L = let expected_L =
DenseMatrix::from_2d_array(&[&[1., 0., 0.], &[0., 1., 0.], &[0.2, 0.8, 1.]]).unwrap(); DenseMatrix::from_2d_array(&[&[1., 0., 0.], &[0., 1., 0.], &[0.2, 0.8, 1.]]);
let expected_U = let expected_U =
DenseMatrix::from_2d_array(&[&[5., 6., 0.], &[0., 1., 5.], &[0., 0., -1.]]).unwrap(); DenseMatrix::from_2d_array(&[&[5., 6., 0.], &[0., 1., 5.], &[0., 0., -1.]]);
let expected_pivot = let expected_pivot =
DenseMatrix::from_2d_array(&[&[0., 0., 1.], &[0., 1., 0.], &[1., 0., 0.]]).unwrap(); DenseMatrix::from_2d_array(&[&[0., 0., 1.], &[0., 1., 0.], &[1., 0., 0.]]);
let lu = a.lu().unwrap(); let lu = a.lu().unwrap();
assert!(relative_eq!(lu.L(), expected_L, epsilon = 1e-4)); assert!(relative_eq!(lu.L(), expected_L, epsilon = 1e-4));
assert!(relative_eq!(lu.U(), expected_U, epsilon = 1e-4)); assert!(relative_eq!(lu.U(), expected_U, epsilon = 1e-4));
@@ -281,10 +281,9 @@ mod tests {
)] )]
#[test] #[test]
fn inverse() { fn inverse() {
let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]).unwrap(); let a = DenseMatrix::from_2d_array(&[&[1., 2., 3.], &[0., 1., 5.], &[5., 6., 0.]]);
let expected = let expected =
DenseMatrix::from_2d_array(&[&[-6.0, 3.6, 1.4], &[5.0, -3.0, -1.0], &[-1.0, 0.8, 0.2]]) DenseMatrix::from_2d_array(&[&[-6.0, 3.6, 1.4], &[5.0, -3.0, -1.0], &[-1.0, 0.8, 0.2]]);
.unwrap();
let a_inv = a.lu().and_then(|lu| lu.inverse()).unwrap(); let a_inv = a.lu().and_then(|lu| lu.inverse()).unwrap();
assert!(relative_eq!(a_inv, expected, epsilon = 1e-4)); assert!(relative_eq!(a_inv, expected, epsilon = 1e-4));
} }
+7 -12
View File
@@ -13,7 +13,7 @@
//! &[0.9, 0.4, 0.7], //! &[0.9, 0.4, 0.7],
//! &[0.4, 0.5, 0.3], //! &[0.4, 0.5, 0.3],
//! &[0.7, 0.3, 0.8] //! &[0.7, 0.3, 0.8]
//! ]).unwrap(); //! ]);
//! //!
//! let qr = A.qr().unwrap(); //! let qr = A.qr().unwrap();
//! let orthogonal: DenseMatrix<f64> = qr.Q(); //! let orthogonal: DenseMatrix<f64> = qr.Q();
@@ -201,20 +201,17 @@ mod tests {
)] )]
#[test] #[test]
fn decompose() { fn decompose() {
let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]);
.unwrap();
let q = DenseMatrix::from_2d_array(&[ let q = DenseMatrix::from_2d_array(&[
&[-0.7448, 0.2436, 0.6212], &[-0.7448, 0.2436, 0.6212],
&[-0.331, -0.9432, -0.027], &[-0.331, -0.9432, -0.027],
&[-0.5793, 0.2257, -0.7832], &[-0.5793, 0.2257, -0.7832],
]) ]);
.unwrap();
let r = DenseMatrix::from_2d_array(&[ let r = DenseMatrix::from_2d_array(&[
&[-1.2083, -0.6373, -1.0842], &[-1.2083, -0.6373, -1.0842],
&[0.0, -0.3064, 0.0682], &[0.0, -0.3064, 0.0682],
&[0.0, 0.0, -0.1999], &[0.0, 0.0, -0.1999],
]) ]);
.unwrap();
let qr = a.qr().unwrap(); let qr = a.qr().unwrap();
assert!(relative_eq!(qr.Q().abs(), q.abs(), epsilon = 1e-4)); assert!(relative_eq!(qr.Q().abs(), q.abs(), epsilon = 1e-4));
assert!(relative_eq!(qr.R().abs(), r.abs(), epsilon = 1e-4)); assert!(relative_eq!(qr.R().abs(), r.abs(), epsilon = 1e-4));
@@ -226,15 +223,13 @@ mod tests {
)] )]
#[test] #[test]
fn qr_solve_mut() { fn qr_solve_mut() {
let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]);
.unwrap(); let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]);
let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]).unwrap();
let expected_w = DenseMatrix::from_2d_array(&[ let expected_w = DenseMatrix::from_2d_array(&[
&[-0.2027027, -1.2837838], &[-0.2027027, -1.2837838],
&[0.8783784, 2.2297297], &[0.8783784, 2.2297297],
&[0.4729730, 0.6621622], &[0.4729730, 0.6621622],
]) ]);
.unwrap();
let w = a.qr_solve_mut(b).unwrap(); let w = a.qr_solve_mut(b).unwrap();
assert!(relative_eq!(w, expected_w, epsilon = 1e-2)); assert!(relative_eq!(w, expected_w, epsilon = 1e-2));
} }
+11 -15
View File
@@ -136,8 +136,8 @@ pub trait MatrixPreprocessing<T: RealNumber>: MutArrayView2<T> + Clone {
/// ```rust /// ```rust
/// use smartcore::linalg::basic::matrix::DenseMatrix; /// use smartcore::linalg::basic::matrix::DenseMatrix;
/// use smartcore::linalg::traits::stats::MatrixPreprocessing; /// use smartcore::linalg::traits::stats::MatrixPreprocessing;
/// let mut a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]).unwrap(); /// let mut a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]);
/// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]).unwrap(); /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]);
/// a.binarize_mut(0.); /// a.binarize_mut(0.);
/// ///
/// assert_eq!(a, expected); /// assert_eq!(a, expected);
@@ -159,8 +159,8 @@ pub trait MatrixPreprocessing<T: RealNumber>: MutArrayView2<T> + Clone {
/// ```rust /// ```rust
/// use smartcore::linalg::basic::matrix::DenseMatrix; /// use smartcore::linalg::basic::matrix::DenseMatrix;
/// use smartcore::linalg::traits::stats::MatrixPreprocessing; /// use smartcore::linalg::traits::stats::MatrixPreprocessing;
/// let a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]).unwrap(); /// let a = DenseMatrix::from_2d_array(&[&[0., 2., 3.], &[-5., -6., -7.]]);
/// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]).unwrap(); /// let expected = DenseMatrix::from_2d_array(&[&[0., 1., 1.],&[0., 0., 0.]]);
/// ///
/// assert_eq!(a.binarize(0.), expected); /// assert_eq!(a.binarize(0.), expected);
/// ``` /// ```
@@ -186,8 +186,7 @@ mod tests {
&[1., 2., 3., 1., 2.], &[1., 2., 3., 1., 2.],
&[4., 5., 6., 3., 4.], &[4., 5., 6., 3., 4.],
&[7., 8., 9., 5., 6.], &[7., 8., 9., 5., 6.],
]) ]);
.unwrap();
let expected_0 = vec![4., 5., 6., 3., 4.]; let expected_0 = vec![4., 5., 6., 3., 4.];
let expected_1 = vec![1.8, 4.4, 7.]; let expected_1 = vec![1.8, 4.4, 7.];
@@ -197,7 +196,7 @@ mod tests {
#[test] #[test]
fn test_var() { fn test_var() {
let m = DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]).unwrap(); let m = DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]);
let expected_0 = vec![4., 4., 4., 4.]; let expected_0 = vec![4., 4., 4., 4.];
let expected_1 = vec![1.25, 1.25]; let expected_1 = vec![1.25, 1.25];
@@ -212,8 +211,7 @@ mod tests {
let m = DenseMatrix::from_2d_array(&[ let m = DenseMatrix::from_2d_array(&[
&[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25], &[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25],
&[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25], &[0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25],
]) ]);
.unwrap();
let expected_0 = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; let expected_0 = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let expected_1 = vec![1.25, 1.25]; let expected_1 = vec![1.25, 1.25];
@@ -232,8 +230,7 @@ mod tests {
&[1., 2., 3., 1., 2.], &[1., 2., 3., 1., 2.],
&[4., 5., 6., 3., 4.], &[4., 5., 6., 3., 4.],
&[7., 8., 9., 5., 6.], &[7., 8., 9., 5., 6.],
]) ]);
.unwrap();
let expected_0 = vec![ let expected_0 = vec![
2.449489742783178, 2.449489742783178,
2.449489742783178, 2.449489742783178,
@@ -254,10 +251,10 @@ mod tests {
#[test] #[test]
fn test_scale() { fn test_scale() {
let m: DenseMatrix<f64> = let m: DenseMatrix<f64> =
DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]).unwrap(); DenseMatrix::from_2d_array(&[&[1., 2., 3., 4.], &[5., 6., 7., 8.]]);
let expected_0: DenseMatrix<f64> = let expected_0: DenseMatrix<f64> =
DenseMatrix::from_2d_array(&[&[-1., -1., -1., -1.], &[1., 1., 1., 1.]]).unwrap(); DenseMatrix::from_2d_array(&[&[-1., -1., -1., -1.], &[1., 1., 1., 1.]]);
let expected_1: DenseMatrix<f64> = DenseMatrix::from_2d_array(&[ let expected_1: DenseMatrix<f64> = DenseMatrix::from_2d_array(&[
&[ &[
-1.3416407864998738, -1.3416407864998738,
@@ -271,8 +268,7 @@ mod tests {
0.4472135954999579, 0.4472135954999579,
1.3416407864998738, 1.3416407864998738,
], ],
]) ]);
.unwrap();
assert_eq!(m.mean(0), vec![3.0, 4.0, 5.0, 6.0]); assert_eq!(m.mean(0), vec![3.0, 4.0, 5.0, 6.0]);
assert_eq!(m.mean(1), vec![2.5, 6.5]); assert_eq!(m.mean(1), vec![2.5, 6.5]);
+11 -19
View File
@@ -17,7 +17,7 @@
//! &[0.9, 0.4, 0.7], //! &[0.9, 0.4, 0.7],
//! &[0.4, 0.5, 0.3], //! &[0.4, 0.5, 0.3],
//! &[0.7, 0.3, 0.8] //! &[0.7, 0.3, 0.8]
//! ]).unwrap(); //! ]);
//! //!
//! let svd = A.svd().unwrap(); //! let svd = A.svd().unwrap();
//! let u: DenseMatrix<f64> = svd.U; //! let u: DenseMatrix<f64> = svd.U;
@@ -489,8 +489,7 @@ mod tests {
&[0.9000, 0.4000, 0.7000], &[0.9000, 0.4000, 0.7000],
&[0.4000, 0.5000, 0.3000], &[0.4000, 0.5000, 0.3000],
&[0.7000, 0.3000, 0.8000], &[0.7000, 0.3000, 0.8000],
]) ]);
.unwrap();
let s: Vec<f64> = vec![1.7498382, 0.3165784, 0.1335834]; let s: Vec<f64> = vec![1.7498382, 0.3165784, 0.1335834];
@@ -498,15 +497,13 @@ mod tests {
&[0.6881997, -0.07121225, 0.7220180], &[0.6881997, -0.07121225, 0.7220180],
&[0.3700456, 0.89044952, -0.2648886], &[0.3700456, 0.89044952, -0.2648886],
&[0.6240573, -0.44947578, -0.639158], &[0.6240573, -0.44947578, -0.639158],
]) ]);
.unwrap();
let V = DenseMatrix::from_2d_array(&[ let V = DenseMatrix::from_2d_array(&[
&[0.6881997, -0.07121225, 0.7220180], &[0.6881997, -0.07121225, 0.7220180],
&[0.3700456, 0.89044952, -0.2648886], &[0.3700456, 0.89044952, -0.2648886],
&[0.6240573, -0.44947578, -0.6391588], &[0.6240573, -0.44947578, -0.6391588],
]) ]);
.unwrap();
let svd = A.svd().unwrap(); let svd = A.svd().unwrap();
@@ -580,8 +577,7 @@ mod tests {
-0.2158704, -0.2158704,
-0.27529472, -0.27529472,
], ],
]) ]);
.unwrap();
let s: Vec<f64> = vec![ let s: Vec<f64> = vec![
3.8589375, 3.4396766, 2.6487176, 2.2317399, 1.5165054, 0.8109055, 0.2706515, 3.8589375, 3.4396766, 2.6487176, 2.2317399, 1.5165054, 0.8109055, 0.2706515,
@@ -651,8 +647,7 @@ mod tests {
0.73034065, 0.73034065,
-0.43965505, -0.43965505,
], ],
]) ]);
.unwrap();
let V = DenseMatrix::from_2d_array(&[ let V = DenseMatrix::from_2d_array(&[
&[ &[
@@ -712,8 +707,7 @@ mod tests {
0.1654796, 0.1654796,
-0.32346758, -0.32346758,
], ],
]) ]);
.unwrap();
let svd = A.svd().unwrap(); let svd = A.svd().unwrap();
@@ -729,11 +723,10 @@ mod tests {
)] )]
#[test] #[test]
fn solve() { fn solve() {
let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]) let a = DenseMatrix::from_2d_array(&[&[0.9, 0.4, 0.7], &[0.4, 0.5, 0.3], &[0.7, 0.3, 0.8]]);
.unwrap(); let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]);
let b = DenseMatrix::from_2d_array(&[&[0.5, 0.2], &[0.5, 0.8], &[0.5, 0.3]]).unwrap();
let expected_w = let expected_w =
DenseMatrix::from_2d_array(&[&[-0.20, -1.28], &[0.87, 2.22], &[0.47, 0.66]]).unwrap(); DenseMatrix::from_2d_array(&[&[-0.20, -1.28], &[0.87, 2.22], &[0.47, 0.66]]);
let w = a.svd_solve_mut(b).unwrap(); let w = a.svd_solve_mut(b).unwrap();
assert!(relative_eq!(w, expected_w, epsilon = 1e-2)); assert!(relative_eq!(w, expected_w, epsilon = 1e-2));
} }
@@ -744,8 +737,7 @@ mod tests {
)] )]
#[test] #[test]
fn decompose_restore() { fn decompose_restore() {
let a = let a = DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0, 4.0], &[5.0, 6.0, 7.0, 8.0]]);
DenseMatrix::from_2d_array(&[&[1.0, 2.0, 3.0, 4.0], &[5.0, 6.0, 7.0, 8.0]]).unwrap();
let svd = a.svd().unwrap(); let svd = a.svd().unwrap();
let u: &DenseMatrix<f32> = &svd.U; //U let u: &DenseMatrix<f32> = &svd.U; //U
let v: &DenseMatrix<f32> = &svd.V; // V let v: &DenseMatrix<f32> = &svd.V; // V
+3 -5
View File
@@ -12,8 +12,7 @@
//! pub struct BGSolver {} //! pub struct BGSolver {}
//! impl<'a, T: FloatNumber, X: Array2<T>> BiconjugateGradientSolver<'a, T, X> for BGSolver {} //! impl<'a, T: FloatNumber, X: Array2<T>> BiconjugateGradientSolver<'a, T, X> for BGSolver {}
//! //!
//! let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., //! let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]);
//! 11.]]).unwrap();
//! let b = vec![40., 51., 28.]; //! let b = vec![40., 51., 28.];
//! let expected = vec![1.0, 2.0, 3.0]; //! let expected = vec![1.0, 2.0, 3.0];
//! let mut x = Vec::zeros(3); //! let mut x = Vec::zeros(3);
@@ -159,10 +158,9 @@ mod tests {
#[test] #[test]
fn bg_solver() { fn bg_solver() {
let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]) let a = DenseMatrix::from_2d_array(&[&[25., 15., -5.], &[15., 18., 0.], &[-5., 0., 11.]]);
.unwrap();
let b = vec![40., 51., 28.]; let b = vec![40., 51., 28.];
let expected = [1.0, 2.0, 3.0]; let expected = vec![1.0, 2.0, 3.0];
let mut x = Vec::zeros(3); let mut x = Vec::zeros(3);
+4 -6
View File
@@ -38,7 +38,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! //!
//! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0,
//! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9];
@@ -511,8 +511,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
@@ -563,8 +562,7 @@ mod tests {
&[17.0, 1918.0, 1.4054969025700674], &[17.0, 1918.0, 1.4054969025700674],
&[18.0, 1929.0, 1.3271699396384906], &[18.0, 1929.0, 1.3271699396384906],
&[19.0, 1915.0, 1.1373332337674806], &[19.0, 1915.0, 1.1373332337674806],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
1.48, 2.72, 4.52, 5.72, 5.25, 4.07, 3.75, 4.75, 6.77, 4.72, 6.78, 6.79, 8.3, 7.42, 1.48, 2.72, 4.52, 5.72, 5.25, 4.07, 3.75, 4.75, 6.77, 4.72, 6.78, 6.79, 8.3, 7.42,
@@ -629,7 +627,7 @@ mod tests {
// &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
// &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
// &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
// ]).unwrap(); // ]);
// let y = vec![ // let y = vec![
// 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
+1 -2
View File
@@ -418,8 +418,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
+3 -4
View File
@@ -40,7 +40,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! //!
//! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0,
//! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9];
@@ -341,8 +341,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8,
@@ -394,7 +393,7 @@ mod tests {
// &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
// &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
// &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
// ]).unwrap(); // ]);
// let y = vec![ // let y = vec![
// 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
+38 -84
View File
@@ -35,7 +35,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y: Vec<i32> = vec![ //! let y: Vec<i32> = vec![
//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//! ]; //! ];
@@ -611,8 +611,7 @@ mod tests {
&[10., -2.], &[10., -2.],
&[8., 2.], &[8., 2.],
&[9., 0.], &[9., 0.],
]) ]);
.unwrap();
let y = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; let y = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1];
@@ -672,8 +671,7 @@ mod tests {
&[10., -2.], &[10., -2.],
&[8., 2.], &[8., 2.],
&[9., 0.], &[9., 0.],
]) ]);
.unwrap();
let y = vec![0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1]; let y = vec![0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1];
@@ -735,8 +733,7 @@ mod tests {
&[10., -2.], &[10., -2.],
&[8., 2.], &[8., 2.],
&[9., 0.], &[9., 0.],
]) ]);
.unwrap();
let y: Vec<i32> = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1]; let y: Vec<i32> = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1];
let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap();
@@ -821,41 +818,37 @@ mod tests {
assert!(reg_coeff_sum < coeff); assert!(reg_coeff_sum < coeff);
} }
//TODO: serialization for the new DenseMatrix needs to be implemented // TODO: serialization for the new DenseMatrix needs to be implemented
#[cfg_attr( // #[cfg_attr(all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test::wasm_bindgen_test)]
all(target_arch = "wasm32", not(target_os = "wasi")), // #[test]
wasm_bindgen_test::wasm_bindgen_test // #[cfg(feature = "serde")]
)] // fn serde() {
#[test] // let x = DenseMatrix::from_2d_array(&[
#[cfg(feature = "serde")] // &[1., -5.],
fn serde() { // &[2., 5.],
let x: DenseMatrix<f64> = DenseMatrix::from_2d_array(&[ // &[3., -2.],
&[1., -5.], // &[1., 2.],
&[2., 5.], // &[2., 0.],
&[3., -2.], // &[6., -5.],
&[1., 2.], // &[7., 5.],
&[2., 0.], // &[6., -2.],
&[6., -5.], // &[7., 2.],
&[7., 5.], // &[6., 0.],
&[6., -2.], // &[8., -5.],
&[7., 2.], // &[9., 5.],
&[6., 0.], // &[10., -2.],
&[8., -5.], // &[8., 2.],
&[9., 5.], // &[9., 0.],
&[10., -2.], // ]);
&[8., 2.], // let y: Vec<i32> = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1];
&[9., 0.],
])
.unwrap();
let y: Vec<i32> = vec![0, 0, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1];
let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); // let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap();
let deserialized_lr: LogisticRegression<f64, i32, DenseMatrix<f64>, Vec<i32>> = // let deserialized_lr: LogisticRegression<f64, i32, DenseMatrix<f64>, Vec<i32>> =
serde_json::from_str(&serde_json::to_string(&lr).unwrap()).unwrap(); // serde_json::from_str(&serde_json::to_string(&lr).unwrap()).unwrap();
assert_eq!(lr, deserialized_lr); // assert_eq!(lr, deserialized_lr);
} // }
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")), all(target_arch = "wasm32", not(target_os = "wasi")),
@@ -884,8 +877,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<i32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y: Vec<i32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap(); let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap();
@@ -898,7 +890,11 @@ mod tests {
let y_hat = lr.predict(&x).unwrap(); let y_hat = lr.predict(&x).unwrap();
let error: i32 = y.into_iter().zip(y_hat).map(|(a, b)| (a - b).abs()).sum(); let error: i32 = y
.into_iter()
.zip(y_hat.into_iter())
.map(|(a, b)| (a - b).abs())
.sum();
assert!(error <= 1); assert!(error <= 1);
@@ -907,46 +903,4 @@ mod tests {
assert!(reg_coeff_sum < coeff); assert!(reg_coeff_sum < coeff);
} }
#[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")),
wasm_bindgen_test::wasm_bindgen_test
)]
#[test]
fn lr_fit_predict_random() {
let x: DenseMatrix<f32> = DenseMatrix::rand(52181, 94);
let y1: Vec<i32> = vec![1; 2181];
let y2: Vec<i32> = vec![0; 50000];
let y: Vec<i32> = y1.into_iter().chain(y2.into_iter()).collect();
let lr = LogisticRegression::fit(&x, &y, Default::default()).unwrap();
let lr_reg = LogisticRegression::fit(
&x,
&y,
LogisticRegressionParameters::default().with_alpha(1.0),
)
.unwrap();
let y_hat = lr.predict(&x).unwrap();
let y_hat_reg = lr_reg.predict(&x).unwrap();
assert_eq!(y.len(), y_hat.len());
assert_eq!(y.len(), y_hat_reg.len());
}
#[test]
fn test_logit() {
let x: &DenseMatrix<f64> = &DenseMatrix::rand(52181, 94);
let y1: Vec<u32> = vec![1; 2181];
let y2: Vec<u32> = vec![0; 50000];
let y: &Vec<u32> = &(y1.into_iter().chain(y2.into_iter()).collect());
println!("y vec height: {:?}", y.len());
println!("x matrix shape: {:?}", x.shape());
let lr = LogisticRegression::fit(x, y, Default::default()).unwrap();
let y_hat = lr.predict(&x).unwrap();
println!("y_hat shape: {:?}", y_hat.shape());
assert_eq!(y_hat.shape(), 52181);
}
} }
+3 -4
View File
@@ -40,7 +40,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! //!
//! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0,
//! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9];
@@ -455,8 +455,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
@@ -514,7 +513,7 @@ mod tests {
// &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], // &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
// &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], // &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
// &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], // &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
// ]).unwrap(); // ]);
// let y = vec![ // let y = vec![
// 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, // 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
+2 -3
View File
@@ -25,7 +25,7 @@
//! &[68., 590., 37.], //! &[68., 590., 37.],
//! &[69., 660., 46.], //! &[69., 660., 46.],
//! &[73., 600., 55.], //! &[73., 600., 55.],
//! ]).unwrap(); //! ]);
//! //!
//! let a = data.mean_by(0); //! let a = data.mean_by(0);
//! let b = vec![66., 640., 44.]; //! let b = vec![66., 640., 44.];
@@ -151,8 +151,7 @@ mod tests {
&[68., 590., 37.], &[68., 590., 37.],
&[69., 660., 46.], &[69., 660., 46.],
&[73., 600., 55.], &[73., 600., 55.],
]) ]);
.unwrap();
let a = data.mean_by(0); let a = data.mean_by(0);
let b = vec![66., 640., 44.]; let b = vec![66., 640., 44.];
+1 -1
View File
@@ -37,7 +37,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y: Vec<i8> = vec![ //! let y: Vec<i8> = vec![
//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//! ]; //! ];
@@ -3,9 +3,9 @@
use crate::{ use crate::{
api::{Predictor, SupervisedEstimator}, api::{Predictor, SupervisedEstimator},
error::{Failed, FailedError}, error::{Failed, FailedError},
linalg::basic::arrays::{Array1, Array2}, linalg::basic::arrays::{Array2, Array1},
numbers::basenum::Number,
numbers::realnum::RealNumber, numbers::realnum::RealNumber,
numbers::basenum::Number,
}; };
use crate::model_selection::{cross_validate, BaseKFold, CrossValidationResult}; use crate::model_selection::{cross_validate, BaseKFold, CrossValidationResult};
+6 -10
View File
@@ -36,7 +36,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y: Vec<f64> = vec![ //! let y: Vec<f64> = vec![
//! 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., //! 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
//! ]; //! ];
@@ -84,7 +84,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y: Vec<i32> = vec![ //! let y: Vec<i32> = vec![
//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//! ]; //! ];
@@ -396,8 +396,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y: Vec<u32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let cv = KFold { let cv = KFold {
@@ -442,8 +441,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y = vec![ let y = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
@@ -491,8 +489,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
@@ -542,8 +539,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<i32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y: Vec<i32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let cv = KFold::default().with_n_splits(3); let cv = KFold::default().with_n_splits(3);
+6 -9
View File
@@ -19,14 +19,14 @@
//! &[0, 1, 0, 0, 1, 0], //! &[0, 1, 0, 0, 1, 0],
//! &[0, 1, 0, 1, 0, 0], //! &[0, 1, 0, 1, 0, 0],
//! &[0, 1, 1, 0, 0, 1], //! &[0, 1, 1, 0, 0, 1],
//! ]).unwrap(); //! ]);
//! let y: Vec<u32> = vec![0, 0, 0, 1]; //! let y: Vec<u32> = vec![0, 0, 0, 1];
//! //!
//! let nb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); //! let nb = BernoulliNB::fit(&x, &y, Default::default()).unwrap();
//! //!
//! // Testing data point is: //! // Testing data point is:
//! // Chinese Chinese Chinese Tokyo Japan //! // Chinese Chinese Chinese Tokyo Japan
//! let x_test = DenseMatrix::from_2d_array(&[&[0, 1, 1, 0, 0, 1]]).unwrap(); //! let x_test = DenseMatrix::from_2d_array(&[&[0, 1, 1, 0, 0, 1]]);
//! let y_hat = nb.predict(&x_test).unwrap(); //! let y_hat = nb.predict(&x_test).unwrap();
//! ``` //! ```
//! //!
@@ -527,8 +527,7 @@ mod tests {
&[0.0, 1.0, 0.0, 0.0, 1.0, 0.0], &[0.0, 1.0, 0.0, 0.0, 1.0, 0.0],
&[0.0, 1.0, 0.0, 1.0, 0.0, 0.0], &[0.0, 1.0, 0.0, 1.0, 0.0, 0.0],
&[0.0, 1.0, 1.0, 0.0, 0.0, 1.0], &[0.0, 1.0, 1.0, 0.0, 0.0, 1.0],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 0, 1]; let y: Vec<u32> = vec![0, 0, 0, 1];
let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap();
@@ -559,7 +558,7 @@ mod tests {
// Testing data point is: // Testing data point is:
// Chinese Chinese Chinese Tokyo Japan // Chinese Chinese Chinese Tokyo Japan
let x_test = DenseMatrix::from_2d_array(&[&[0.0, 1.0, 1.0, 0.0, 0.0, 1.0]]).unwrap(); let x_test = DenseMatrix::from_2d_array(&[&[0.0, 1.0, 1.0, 0.0, 0.0, 1.0]]);
let y_hat = bnb.predict(&x_test).unwrap(); let y_hat = bnb.predict(&x_test).unwrap();
assert_eq!(y_hat, &[1]); assert_eq!(y_hat, &[1]);
@@ -587,8 +586,7 @@ mod tests {
&[2, 0, 3, 3, 1, 2, 0, 2, 4, 1], &[2, 0, 3, 3, 1, 2, 0, 2, 4, 1],
&[2, 4, 0, 4, 2, 4, 1, 3, 1, 4], &[2, 4, 0, 4, 2, 4, 1, 3, 1, 4],
&[0, 2, 2, 3, 4, 0, 4, 4, 4, 4], &[0, 2, 2, 3, 4, 0, 4, 4, 4, 4],
]) ]);
.unwrap();
let y: Vec<u32> = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2]; let y: Vec<u32> = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2];
let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap();
@@ -645,8 +643,7 @@ mod tests {
&[0, 1, 0, 0, 1, 0], &[0, 1, 0, 0, 1, 0],
&[0, 1, 0, 1, 0, 0], &[0, 1, 0, 1, 0, 0],
&[0, 1, 1, 0, 0, 1], &[0, 1, 1, 0, 0, 1],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 0, 1]; let y: Vec<u32> = vec![0, 0, 0, 1];
let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap(); let bnb = BernoulliNB::fit(&x, &y, Default::default()).unwrap();
+5 -8
View File
@@ -24,7 +24,7 @@
//! &[3, 4, 2, 4], //! &[3, 4, 2, 4],
//! &[0, 3, 1, 2], //! &[0, 3, 1, 2],
//! &[0, 4, 1, 2], //! &[0, 4, 1, 2],
//! ]).unwrap(); //! ]);
//! let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; //! let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0];
//! //!
//! let nb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); //! let nb = CategoricalNB::fit(&x, &y, Default::default()).unwrap();
@@ -455,8 +455,7 @@ mod tests {
&[1, 1, 1, 1], &[1, 1, 1, 1],
&[1, 2, 0, 0], &[1, 2, 0, 0],
&[2, 1, 1, 1], &[2, 1, 1, 1],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0];
let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap();
@@ -514,7 +513,7 @@ mod tests {
] ]
); );
let x_test = DenseMatrix::from_2d_array(&[&[0, 2, 1, 0], &[2, 2, 0, 0]]).unwrap(); let x_test = DenseMatrix::from_2d_array(&[&[0, 2, 1, 0], &[2, 2, 0, 0]]);
let y_hat = cnb.predict(&x_test).unwrap(); let y_hat = cnb.predict(&x_test).unwrap();
assert_eq!(y_hat, vec![0, 1]); assert_eq!(y_hat, vec![0, 1]);
} }
@@ -540,8 +539,7 @@ mod tests {
&[3, 4, 2, 4], &[3, 4, 2, 4],
&[0, 3, 1, 2], &[0, 3, 1, 2],
&[0, 4, 1, 2], &[0, 4, 1, 2],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0];
let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap();
@@ -573,8 +571,7 @@ mod tests {
&[3, 4, 2, 4], &[3, 4, 2, 4],
&[0, 3, 1, 2], &[0, 3, 1, 2],
&[0, 4, 1, 2], &[0, 4, 1, 2],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0]; let y: Vec<u32> = vec![0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0];
let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap(); let cnb = CategoricalNB::fit(&x, &y, Default::default()).unwrap();
+4 -7
View File
@@ -16,7 +16,7 @@
//! &[ 1., 1.], //! &[ 1., 1.],
//! &[ 2., 1.], //! &[ 2., 1.],
//! &[ 3., 2.], //! &[ 3., 2.],
//! ]).unwrap(); //! ]);
//! let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2]; //! let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2];
//! //!
//! let nb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); //! let nb = GaussianNB::fit(&x, &y, Default::default()).unwrap();
@@ -395,8 +395,7 @@ mod tests {
&[1., 1.], &[1., 1.],
&[2., 1.], &[2., 1.],
&[3., 2.], &[3., 2.],
]) ]);
.unwrap();
let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2]; let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2];
let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap();
@@ -436,8 +435,7 @@ mod tests {
&[1., 1.], &[1., 1.],
&[2., 1.], &[2., 1.],
&[3., 2.], &[3., 2.],
]) ]);
.unwrap();
let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2]; let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2];
let priors = vec![0.3, 0.7]; let priors = vec![0.3, 0.7];
@@ -464,8 +462,7 @@ mod tests {
&[1., 1.], &[1., 1.],
&[2., 1.], &[2., 1.],
&[3., 2.], &[3., 2.],
]) ]);
.unwrap();
let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2]; let y: Vec<u32> = vec![1, 1, 1, 2, 2, 2];
let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap(); let gnb = GaussianNB::fit(&x, &y, Default::default()).unwrap();
+10 -84
View File
@@ -40,7 +40,7 @@ use crate::linalg::basic::arrays::{Array1, Array2, ArrayView1};
use crate::numbers::basenum::Number; use crate::numbers::basenum::Number;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{cmp::Ordering, marker::PhantomData}; use std::marker::PhantomData;
/// Distribution used in the Naive Bayes classifier. /// Distribution used in the Naive Bayes classifier.
pub(crate) trait NBDistribution<X: Number, Y: Number>: Clone { pub(crate) trait NBDistribution<X: Number, Y: Number>: Clone {
@@ -92,10 +92,11 @@ impl<TX: Number, TY: Number, X: Array2<TX>, Y: Array1<TY>, D: NBDistribution<TX,
/// Returns a vector of size N with class estimates. /// Returns a vector of size N with class estimates.
pub fn predict(&self, x: &X) -> Result<Y, Failed> { pub fn predict(&self, x: &X) -> Result<Y, Failed> {
let y_classes = self.distribution.classes(); let y_classes = self.distribution.classes();
let predictions = x let (rows, _) = x.shape();
.row_iter() let predictions = (0..rows)
.map(|row| { .map(|row_index| {
y_classes let row = x.get_row(row_index);
let (prediction, _probability) = y_classes
.iter() .iter()
.enumerate() .enumerate()
.map(|(class_index, class)| { .map(|(class_index, class)| {
@@ -105,26 +106,11 @@ impl<TX: Number, TY: Number, X: Array2<TX>, Y: Array1<TY>, D: NBDistribution<TX,
+ self.distribution.prior(class_index).ln(), + self.distribution.prior(class_index).ln(),
) )
}) })
// For some reason, the max_by method cannot use NaNs for finding the maximum value, it panics. .max_by(|(_, p1), (_, p2)| p1.partial_cmp(p2).unwrap())
// NaN must be considered as minimum values, .unwrap();
// therefore it's like NaNs would not be considered for choosing the maximum value. *prediction
// So we need to handle this case for avoiding panicking by using `Option::unwrap`.
.max_by(|(_, p1), (_, p2)| match p1.partial_cmp(p2) {
Some(ordering) => ordering,
None => {
if p1.is_nan() {
Ordering::Less
} else if p2.is_nan() {
Ordering::Greater
} else {
Ordering::Equal
}
}
})
.map(|(prediction, _probability)| *prediction)
.ok_or_else(|| Failed::predict("Failed to predict, there is no result"))
}) })
.collect::<Result<Vec<TY>, Failed>>()?; .collect::<Vec<TY>>();
let y_hat = Y::from_vec_slice(&predictions); let y_hat = Y::from_vec_slice(&predictions);
Ok(y_hat) Ok(y_hat)
} }
@@ -133,63 +119,3 @@ pub mod bernoulli;
pub mod categorical; pub mod categorical;
pub mod gaussian; pub mod gaussian;
pub mod multinomial; pub mod multinomial;
#[cfg(test)]
mod tests {
use super::*;
use crate::linalg::basic::arrays::Array;
use crate::linalg::basic::matrix::DenseMatrix;
use num_traits::float::Float;
type Model<'d> = BaseNaiveBayes<i32, i32, DenseMatrix<i32>, Vec<i32>, TestDistribution<'d>>;
#[derive(Debug, PartialEq, Clone)]
struct TestDistribution<'d>(&'d Vec<i32>);
impl<'d> NBDistribution<i32, i32> for TestDistribution<'d> {
fn prior(&self, _class_index: usize) -> f64 {
1.
}
fn log_likelihood<'a>(
&'a self,
class_index: usize,
_j: &'a Box<dyn ArrayView1<i32> + 'a>,
) -> f64 {
match self.0.get(class_index) {
&v @ 2 | &v @ 10 | &v @ 20 => v as f64,
_ => f64::nan(),
}
}
fn classes(&self) -> &Vec<i32> {
&self.0
}
}
#[test]
fn test_predict() {
let matrix = DenseMatrix::from_2d_array(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]).unwrap();
let val = vec![];
match Model::fit(TestDistribution(&val)).unwrap().predict(&matrix) {
Ok(_) => panic!("Should return error in case of empty classes"),
Err(err) => assert_eq!(
err.to_string(),
"Predict failed: Failed to predict, there is no result"
),
}
let val = vec![1, 2, 3];
match Model::fit(TestDistribution(&val)).unwrap().predict(&matrix) {
Ok(r) => assert_eq!(r, vec![2, 2, 2]),
Err(_) => panic!("Should success in normal case with NaNs"),
}
let val = vec![20, 2, 10];
match Model::fit(TestDistribution(&val)).unwrap().predict(&matrix) {
Ok(r) => assert_eq!(r, vec![20, 20, 20]),
Err(_) => panic!("Should success in normal case without NaNs"),
}
}
}
+6 -9
View File
@@ -20,13 +20,13 @@
//! &[0, 2, 0, 0, 1, 0], //! &[0, 2, 0, 0, 1, 0],
//! &[0, 1, 0, 1, 0, 0], //! &[0, 1, 0, 1, 0, 0],
//! &[0, 1, 1, 0, 0, 1], //! &[0, 1, 1, 0, 0, 1],
//! ]).unwrap(); //! ]);
//! let y: Vec<u32> = vec![0, 0, 0, 1]; //! let y: Vec<u32> = vec![0, 0, 0, 1];
//! let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); //! let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap();
//! //!
//! // Testing data point is: //! // Testing data point is:
//! // Chinese Chinese Chinese Tokyo Japan //! // Chinese Chinese Chinese Tokyo Japan
//! let x_test = DenseMatrix::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]).unwrap(); //! let x_test = DenseMatrix::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]);
//! let y_hat = nb.predict(&x_test).unwrap(); //! let y_hat = nb.predict(&x_test).unwrap();
//! ``` //! ```
//! //!
@@ -433,8 +433,7 @@ mod tests {
&[0, 2, 0, 0, 1, 0], &[0, 2, 0, 0, 1, 0],
&[0, 1, 0, 1, 0, 0], &[0, 1, 0, 1, 0, 0],
&[0, 1, 1, 0, 0, 1], &[0, 1, 1, 0, 0, 1],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 0, 1]; let y: Vec<u32> = vec![0, 0, 0, 1];
let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap();
@@ -468,7 +467,7 @@ mod tests {
// Testing data point is: // Testing data point is:
// Chinese Chinese Chinese Tokyo Japan // Chinese Chinese Chinese Tokyo Japan
let x_test = DenseMatrix::<u32>::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]).unwrap(); let x_test = DenseMatrix::<u32>::from_2d_array(&[&[0, 3, 1, 0, 0, 1]]);
let y_hat = mnb.predict(&x_test).unwrap(); let y_hat = mnb.predict(&x_test).unwrap();
assert_eq!(y_hat, &[0]); assert_eq!(y_hat, &[0]);
@@ -496,8 +495,7 @@ mod tests {
&[2, 0, 3, 3, 1, 2, 0, 2, 4, 1], &[2, 0, 3, 3, 1, 2, 0, 2, 4, 1],
&[2, 4, 0, 4, 2, 4, 1, 3, 1, 4], &[2, 4, 0, 4, 2, 4, 1, 3, 1, 4],
&[0, 2, 2, 3, 4, 0, 4, 4, 4, 4], &[0, 2, 2, 3, 4, 0, 4, 4, 4, 4],
]) ]);
.unwrap();
let y: Vec<u32> = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2]; let y: Vec<u32> = vec![2, 2, 0, 0, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 2];
let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); let nb = MultinomialNB::fit(&x, &y, Default::default()).unwrap();
@@ -556,8 +554,7 @@ mod tests {
&[0, 1, 0, 0, 1, 0], &[0, 1, 0, 0, 1, 0],
&[0, 1, 0, 1, 0, 0], &[0, 1, 0, 1, 0, 0],
&[0, 1, 1, 0, 0, 1], &[0, 1, 1, 0, 0, 1],
]) ]);
.unwrap();
let y = vec![0, 0, 0, 1]; let y = vec![0, 0, 0, 1];
let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap(); let mnb = MultinomialNB::fit(&x, &y, Default::default()).unwrap();
+5 -9
View File
@@ -22,7 +22,7 @@
//! &[3., 4.], //! &[3., 4.],
//! &[5., 6.], //! &[5., 6.],
//! &[7., 8.], //! &[7., 8.],
//! &[9., 10.]]).unwrap(); //! &[9., 10.]]);
//! let y = vec![2, 2, 2, 3, 3]; //your class labels //! let y = vec![2, 2, 2, 3, 3]; //your class labels
//! //!
//! let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap(); //! let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap();
@@ -311,8 +311,7 @@ mod tests {
#[test] #[test]
fn knn_fit_predict() { fn knn_fit_predict() {
let x = let x =
DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]);
.unwrap();
let y = vec![2, 2, 2, 3, 3]; let y = vec![2, 2, 2, 3, 3];
let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap(); let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap();
let y_hat = knn.predict(&x).unwrap(); let y_hat = knn.predict(&x).unwrap();
@@ -326,7 +325,7 @@ mod tests {
)] )]
#[test] #[test]
fn knn_fit_predict_weighted() { fn knn_fit_predict_weighted() {
let x = DenseMatrix::from_2d_array(&[&[1.], &[2.], &[3.], &[4.], &[5.]]).unwrap(); let x = DenseMatrix::from_2d_array(&[&[1.], &[2.], &[3.], &[4.], &[5.]]);
let y = vec![2, 2, 2, 3, 3]; let y = vec![2, 2, 2, 3, 3];
let knn = KNNClassifier::fit( let knn = KNNClassifier::fit(
&x, &x,
@@ -337,9 +336,7 @@ mod tests {
.with_weight(KNNWeightFunction::Distance), .with_weight(KNNWeightFunction::Distance),
) )
.unwrap(); .unwrap();
let y_hat = knn let y_hat = knn.predict(&DenseMatrix::from_2d_array(&[&[4.1]])).unwrap();
.predict(&DenseMatrix::from_2d_array(&[&[4.1]]).unwrap())
.unwrap();
assert_eq!(vec![3], y_hat); assert_eq!(vec![3], y_hat);
} }
@@ -351,8 +348,7 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn serde() { fn serde() {
let x = let x =
DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]);
.unwrap();
let y = vec![2, 2, 2, 3, 3]; let y = vec![2, 2, 2, 3, 3];
let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap(); let knn = KNNClassifier::fit(&x, &y, Default::default()).unwrap();
+6 -9
View File
@@ -24,7 +24,7 @@
//! &[2., 2.], //! &[2., 2.],
//! &[3., 3.], //! &[3., 3.],
//! &[4., 4.], //! &[4., 4.],
//! &[5., 5.]]).unwrap(); //! &[5., 5.]]);
//! let y = vec![1., 2., 3., 4., 5.]; //your target values //! let y = vec![1., 2., 3., 4., 5.]; //your target values
//! //!
//! let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap(); //! let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap();
@@ -295,10 +295,9 @@ mod tests {
#[test] #[test]
fn knn_fit_predict_weighted() { fn knn_fit_predict_weighted() {
let x = let x =
DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]);
.unwrap();
let y: Vec<f64> = vec![1., 2., 3., 4., 5.]; let y: Vec<f64> = vec![1., 2., 3., 4., 5.];
let y_exp = [1., 2., 3., 4., 5.]; let y_exp = vec![1., 2., 3., 4., 5.];
let knn = KNNRegressor::fit( let knn = KNNRegressor::fit(
&x, &x,
&y, &y,
@@ -323,10 +322,9 @@ mod tests {
#[test] #[test]
fn knn_fit_predict_uniform() { fn knn_fit_predict_uniform() {
let x = let x =
DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]);
.unwrap();
let y: Vec<f64> = vec![1., 2., 3., 4., 5.]; let y: Vec<f64> = vec![1., 2., 3., 4., 5.];
let y_exp = [2., 2., 3., 4., 4.]; let y_exp = vec![2., 2., 3., 4., 4.];
let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap(); let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap();
let y_hat = knn.predict(&x).unwrap(); let y_hat = knn.predict(&x).unwrap();
assert_eq!(5, Vec::len(&y_hat)); assert_eq!(5, Vec::len(&y_hat));
@@ -343,8 +341,7 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn serde() { fn serde() {
let x = let x =
DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]) DenseMatrix::from_2d_array(&[&[1., 2.], &[3., 4.], &[5., 6.], &[7., 8.], &[9., 10.]]);
.unwrap();
let y = vec![1., 2., 3., 4., 5.]; let y = vec![1., 2., 3., 4., 5.];
let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap(); let knn = KNNRegressor::fit(&x, &y, Default::default()).unwrap();
+7 -12
View File
@@ -12,7 +12,7 @@
//! &[1.5, 2.0, 1.5, 4.0], //! &[1.5, 2.0, 1.5, 4.0],
//! &[1.5, 1.0, 1.5, 5.0], //! &[1.5, 1.0, 1.5, 5.0],
//! &[1.5, 2.0, 1.5, 6.0], //! &[1.5, 2.0, 1.5, 6.0],
//! ]).unwrap(); //! ]);
//! let encoder_params = OneHotEncoderParams::from_cat_idx(&[1, 3]); //! let encoder_params = OneHotEncoderParams::from_cat_idx(&[1, 3]);
//! // Infer number of categories from data and return a reusable encoder //! // Infer number of categories from data and return a reusable encoder
//! let encoder = OneHotEncoder::fit(&data, encoder_params).unwrap(); //! let encoder = OneHotEncoder::fit(&data, encoder_params).unwrap();
@@ -240,16 +240,14 @@ mod tests {
&[2.0, 1.5, 4.0], &[2.0, 1.5, 4.0],
&[1.0, 1.5, 5.0], &[1.0, 1.5, 5.0],
&[2.0, 1.5, 6.0], &[2.0, 1.5, 6.0],
]) ]);
.unwrap();
let oh_enc = DenseMatrix::from_2d_array(&[ let oh_enc = DenseMatrix::from_2d_array(&[
&[1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0], &[1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0],
&[0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0], &[0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0],
&[1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0], &[1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0],
&[0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0], &[0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0],
]) ]);
.unwrap();
(orig, oh_enc) (orig, oh_enc)
} }
@@ -261,16 +259,14 @@ mod tests {
&[1.5, 2.0, 1.5, 4.0], &[1.5, 2.0, 1.5, 4.0],
&[1.5, 1.0, 1.5, 5.0], &[1.5, 1.0, 1.5, 5.0],
&[1.5, 2.0, 1.5, 6.0], &[1.5, 2.0, 1.5, 6.0],
]) ]);
.unwrap();
let oh_enc = DenseMatrix::from_2d_array(&[ let oh_enc = DenseMatrix::from_2d_array(&[
&[1.5, 1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0], &[1.5, 1.0, 0.0, 1.5, 1.0, 0.0, 0.0, 0.0],
&[1.5, 0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0], &[1.5, 0.0, 1.0, 1.5, 0.0, 1.0, 0.0, 0.0],
&[1.5, 1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0], &[1.5, 1.0, 0.0, 1.5, 0.0, 0.0, 1.0, 0.0],
&[1.5, 0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0], &[1.5, 0.0, 1.0, 1.5, 0.0, 0.0, 0.0, 1.0],
]) ]);
.unwrap();
(orig, oh_enc) (orig, oh_enc)
} }
@@ -281,7 +277,7 @@ mod tests {
)] )]
#[test] #[test]
fn hash_encode_f64_series() { fn hash_encode_f64_series() {
let series = [3.0, 1.0, 2.0, 1.0]; let series = vec![3.0, 1.0, 2.0, 1.0];
let hashable_series: Vec<CategoricalFloat> = let hashable_series: Vec<CategoricalFloat> =
series.iter().map(|v| v.to_category()).collect(); series.iter().map(|v| v.to_category()).collect();
let enc = CategoryMapper::from_positional_category_vec(hashable_series); let enc = CategoryMapper::from_positional_category_vec(hashable_series);
@@ -338,8 +334,7 @@ mod tests {
&[2.0, 1.5, 4.0], &[2.0, 1.5, 4.0],
&[1.0, 1.5, 5.0], &[1.0, 1.5, 5.0],
&[2.0, 1.5, 6.0], &[2.0, 1.5, 6.0],
]) ]);
.unwrap();
let params = OneHotEncoderParams::from_cat_idx(&[1]); let params = OneHotEncoderParams::from_cat_idx(&[1]);
let result = OneHotEncoder::fit(&m, params); let result = OneHotEncoder::fit(&m, params);
+38 -47
View File
@@ -11,7 +11,7 @@
//! vec![0.0, 0.0], //! vec![0.0, 0.0],
//! vec![1.0, 1.0], //! vec![1.0, 1.0],
//! vec![1.0, 1.0], //! vec![1.0, 1.0],
//! ]).unwrap(); //! ]);
//! //!
//! let standard_scaler = //! let standard_scaler =
//! numerical::StandardScaler::fit(&data, numerical::StandardScalerParameters::default()) //! numerical::StandardScaler::fit(&data, numerical::StandardScalerParameters::default())
@@ -24,7 +24,7 @@
//! vec![-1.0, -1.0], //! vec![-1.0, -1.0],
//! vec![1.0, 1.0], //! vec![1.0, 1.0],
//! vec![1.0, 1.0], //! vec![1.0, 1.0],
//! ]).unwrap() //! ])
//! ); //! );
//! ``` //! ```
use std::marker::PhantomData; use std::marker::PhantomData;
@@ -197,18 +197,15 @@ mod tests {
fn combine_three_columns() { fn combine_three_columns() {
assert_eq!( assert_eq!(
build_matrix_from_columns(vec![ build_matrix_from_columns(vec![
DenseMatrix::from_2d_vec(&vec![vec![1.0], vec![1.0], vec![1.0],]).unwrap(), DenseMatrix::from_2d_vec(&vec![vec![1.0], vec![1.0], vec![1.0],]),
DenseMatrix::from_2d_vec(&vec![vec![2.0], vec![2.0], vec![2.0],]).unwrap(), DenseMatrix::from_2d_vec(&vec![vec![2.0], vec![2.0], vec![2.0],]),
DenseMatrix::from_2d_vec(&vec![vec![3.0], vec![3.0], vec![3.0],]).unwrap() DenseMatrix::from_2d_vec(&vec![vec![3.0], vec![3.0], vec![3.0],])
]), ]),
Some( Some(DenseMatrix::from_2d_vec(&vec![
DenseMatrix::from_2d_vec(&vec![ vec![1.0, 2.0, 3.0],
vec![1.0, 2.0, 3.0], vec![1.0, 2.0, 3.0],
vec![1.0, 2.0, 3.0], vec![1.0, 2.0, 3.0]
vec![1.0, 2.0, 3.0] ]))
])
.unwrap()
)
) )
} }
@@ -290,15 +287,13 @@ mod tests {
/// sklearn. /// sklearn.
#[test] #[test]
fn fit_transform_random_values() { fn fit_transform_random_values() {
let transformed_values = fit_transform_with_default_standard_scaler( let transformed_values =
&DenseMatrix::from_2d_array(&[ fit_transform_with_default_standard_scaler(&DenseMatrix::from_2d_array(&[
&[0.1004222429, 0.2194113576, 0.9310663354, 0.3313593793], &[0.1004222429, 0.2194113576, 0.9310663354, 0.3313593793],
&[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264],
&[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046],
&[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442],
]) ]));
.unwrap(),
);
println!("{transformed_values}"); println!("{transformed_values}");
assert!(transformed_values.approximate_eq( assert!(transformed_values.approximate_eq(
&DenseMatrix::from_2d_array(&[ &DenseMatrix::from_2d_array(&[
@@ -306,8 +301,7 @@ mod tests {
&[-0.7615464283, -0.7076698384, -1.1075452562, 1.2632979631], &[-0.7615464283, -0.7076698384, -1.1075452562, 1.2632979631],
&[0.4832504303, -0.6106747444, 1.0630075435, 0.5494084257], &[0.4832504303, -0.6106747444, 1.0630075435, 0.5494084257],
&[1.3936980634, 1.7215431158, -0.8839228078, -1.3855590021], &[1.3936980634, 1.7215431158, -0.8839228078, -1.3855590021],
]) ]),
.unwrap(),
1.0 1.0
)) ))
} }
@@ -316,10 +310,13 @@ mod tests {
#[test] #[test]
fn fit_transform_with_zero_variance() { fn fit_transform_with_zero_variance() {
assert_eq!( assert_eq!(
fit_transform_with_default_standard_scaler( fit_transform_with_default_standard_scaler(&DenseMatrix::from_2d_array(&[
&DenseMatrix::from_2d_array(&[&[1.0], &[1.0], &[1.0], &[1.0]]).unwrap() &[1.0],
), &[1.0],
DenseMatrix::from_2d_array(&[&[0.0], &[0.0], &[0.0], &[0.0]]).unwrap(), &[1.0],
&[1.0]
])),
DenseMatrix::from_2d_array(&[&[0.0], &[0.0], &[0.0], &[0.0]]),
"When scaling values with zero variance, zero is expected as return value" "When scaling values with zero variance, zero is expected as return value"
) )
} }
@@ -334,8 +331,7 @@ mod tests {
&[1.0, 2.0, 5.0], &[1.0, 2.0, 5.0],
&[1.0, 1.0, 1.0], &[1.0, 1.0, 1.0],
&[1.0, 2.0, 5.0] &[1.0, 2.0, 5.0]
]) ]),
.unwrap(),
StandardScalerParameters::default(), StandardScalerParameters::default(),
), ),
Ok(StandardScaler { Ok(StandardScaler {
@@ -358,8 +354,7 @@ mod tests {
&[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264],
&[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046],
&[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442],
]) ]),
.unwrap(),
StandardScalerParameters::default(), StandardScalerParameters::default(),
) )
.unwrap(); .unwrap();
@@ -369,18 +364,17 @@ mod tests {
vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625], vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625],
); );
assert!(&DenseMatrix::<f64>::from_2d_vec(&vec![fitted_scaler.stds]) assert!(
.unwrap() &DenseMatrix::<f64>::from_2d_vec(&vec![fitted_scaler.stds]).approximate_eq(
.approximate_eq(
&DenseMatrix::from_2d_array(&[&[ &DenseMatrix::from_2d_array(&[&[
0.29426447500954, 0.29426447500954,
0.16758497615485, 0.16758497615485,
0.20820945786863, 0.20820945786863,
0.23329718831165 0.23329718831165
],]) ],]),
.unwrap(),
0.00000000000001 0.00000000000001
)) )
)
} }
/// If `with_std` is set to `false` the values should not be /// If `with_std` is set to `false` the values should not be
@@ -398,9 +392,8 @@ mod tests {
}; };
assert_eq!( assert_eq!(
standard_scaler standard_scaler.transform(&DenseMatrix::from_2d_array(&[&[0.0, 2.0], &[2.0, 4.0]])),
.transform(&DenseMatrix::from_2d_array(&[&[0.0, 2.0], &[2.0, 4.0]]).unwrap()), Ok(DenseMatrix::from_2d_array(&[&[-1.0, -1.0], &[1.0, 1.0]]))
Ok(DenseMatrix::from_2d_array(&[&[-1.0, -1.0], &[1.0, 1.0]]).unwrap())
) )
} }
@@ -420,8 +413,8 @@ mod tests {
assert_eq!( assert_eq!(
standard_scaler standard_scaler
.transform(&DenseMatrix::from_2d_array(&[&[0.0, 9.0], &[4.0, 12.0]]).unwrap()), .transform(&DenseMatrix::from_2d_array(&[&[0.0, 9.0], &[4.0, 12.0]])),
Ok(DenseMatrix::from_2d_array(&[&[0.0, 3.0], &[2.0, 4.0]]).unwrap()) Ok(DenseMatrix::from_2d_array(&[&[0.0, 3.0], &[2.0, 4.0]]))
) )
} }
@@ -440,8 +433,7 @@ mod tests {
&[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264], &[0.2045493861, 0.1683865411, 0.5071506765, 0.7257355264],
&[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046], &[0.5708488802, 0.1846414616, 0.9590802982, 0.5591871046],
&[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442], &[0.8387612750, 0.5754861361, 0.5537109852, 0.1077646442],
]) ]),
.unwrap(),
StandardScalerParameters::default(), StandardScalerParameters::default(),
) )
.unwrap(); .unwrap();
@@ -454,18 +446,17 @@ mod tests {
vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625], vec![0.42864544605, 0.2869813741, 0.737752073825, 0.431011663625],
); );
assert!(&DenseMatrix::from_2d_vec(&vec![deserialized_scaler.stds]) assert!(
.unwrap() &DenseMatrix::from_2d_vec(&vec![deserialized_scaler.stds]).approximate_eq(
.approximate_eq(
&DenseMatrix::from_2d_array(&[&[ &DenseMatrix::from_2d_array(&[&[
0.29426447500954, 0.29426447500954,
0.16758497615485, 0.16758497615485,
0.20820945786863, 0.20820945786863,
0.23329718831165 0.23329718831165
],]) ],]),
.unwrap(),
0.00000000000001 0.00000000000001
)) )
)
} }
} }
} }
+2 -3
View File
@@ -238,8 +238,7 @@ mod tests {
&[5.1, 3.5, 1.4, 0.2], &[5.1, 3.5, 1.4, 0.2],
&[4.9, 3.0, 1.4, 0.2], &[4.9, 3.0, 1.4, 0.2],
&[4.7, 3.2, 1.3, 0.2], &[4.7, 3.2, 1.3, 0.2],
]) ]))
.unwrap())
) )
} }
#[test] #[test]
@@ -262,7 +261,7 @@ mod tests {
&[5.1, 3.5, 1.4, 0.2], &[5.1, 3.5, 1.4, 0.2],
&[4.9, 3.0, 1.4, 0.2], &[4.9, 3.0, 1.4, 0.2],
&[4.7, 3.2, 1.3, 0.2], &[4.7, 3.2, 1.3, 0.2],
]).unwrap()) ]))
) )
} }
#[test] #[test]
+1 -1
View File
@@ -56,7 +56,7 @@ pub struct Kernels;
impl Kernels { impl Kernels {
/// Return a default linear /// Return a default linear
pub fn linear() -> LinearKernel { pub fn linear() -> LinearKernel {
LinearKernel LinearKernel::default()
} }
/// Return a default RBF /// Return a default RBF
pub fn rbf() -> RBFKernel { pub fn rbf() -> RBFKernel {
+6 -11
View File
@@ -53,7 +53,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y = vec![ -1, -1, -1, -1, -1, -1, -1, -1, //! let y = vec![ -1, -1, -1, -1, -1, -1, -1, -1,
//! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
//! //!
@@ -957,8 +957,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<i32> = vec![ let y: Vec<i32> = vec![
-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -984,8 +983,7 @@ mod tests {
)] )]
#[test] #[test]
fn svc_fit_decision_function() { fn svc_fit_decision_function() {
let x = DenseMatrix::from_2d_array(&[&[4.0, 0.0], &[0.0, 4.0], &[8.0, 0.0], &[0.0, 8.0]]) let x = DenseMatrix::from_2d_array(&[&[4.0, 0.0], &[0.0, 4.0], &[8.0, 0.0], &[0.0, 8.0]]);
.unwrap();
let x2 = DenseMatrix::from_2d_array(&[ let x2 = DenseMatrix::from_2d_array(&[
&[3.0, 3.0], &[3.0, 3.0],
@@ -994,8 +992,7 @@ mod tests {
&[10.0, 10.0], &[10.0, 10.0],
&[1.0, 1.0], &[1.0, 1.0],
&[0.0, 0.0], &[0.0, 0.0],
]) ]);
.unwrap();
let y: Vec<i32> = vec![-1, -1, 1, 1]; let y: Vec<i32> = vec![-1, -1, 1, 1];
@@ -1048,8 +1045,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<i32> = vec![ let y: Vec<i32> = vec![
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1098,8 +1094,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<i32> = vec![ let y: Vec<i32> = vec![
-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+3 -5
View File
@@ -44,7 +44,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! //!
//! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, //! let y: Vec<f64> = vec![83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0,
//! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9]; //! 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9];
@@ -640,8 +640,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
@@ -689,8 +688,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
+27 -93
View File
@@ -48,7 +48,7 @@
//! &[4.9, 2.4, 3.3, 1.0], //! &[4.9, 2.4, 3.3, 1.0],
//! &[6.6, 2.9, 4.6, 1.3], //! &[6.6, 2.9, 4.6, 1.3],
//! &[5.2, 2.7, 3.9, 1.4], //! &[5.2, 2.7, 3.9, 1.4],
//! ]).unwrap(); //! ]);
//! let y = vec![ 0, 0, 0, 0, 0, 0, 0, 0, //! let y = vec![ 0, 0, 0, 0, 0, 0, 0, 0,
//! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; //! 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
//! //!
@@ -116,7 +116,6 @@ pub struct DecisionTreeClassifier<
num_classes: usize, num_classes: usize,
classes: Vec<TY>, classes: Vec<TY>,
depth: u16, depth: u16,
num_features: usize,
_phantom_tx: PhantomData<TX>, _phantom_tx: PhantomData<TX>,
_phantom_x: PhantomData<X>, _phantom_x: PhantomData<X>,
_phantom_y: PhantomData<Y>, _phantom_y: PhantomData<Y>,
@@ -160,13 +159,11 @@ pub enum SplitCriterion {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Node { struct Node {
output: usize, output: usize,
n_node_samples: usize,
split_feature: usize, split_feature: usize,
split_value: Option<f64>, split_value: Option<f64>,
split_score: Option<f64>, split_score: Option<f64>,
true_child: Option<usize>, true_child: Option<usize>,
false_child: Option<usize>, false_child: Option<usize>,
impurity: Option<f64>,
} }
impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>> PartialEq impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>> PartialEq
@@ -403,16 +400,14 @@ impl Default for DecisionTreeClassifierSearchParameters {
} }
impl Node { impl Node {
fn new(output: usize, n_node_samples: usize) -> Self { fn new(output: usize) -> Self {
Node { Node {
output, output,
n_node_samples,
split_feature: 0, split_feature: 0,
split_value: Option::None, split_value: Option::None,
split_score: Option::None, split_score: Option::None,
true_child: Option::None, true_child: Option::None,
false_child: Option::None, false_child: Option::None,
impurity: Option::None,
} }
} }
} }
@@ -512,7 +507,6 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
num_classes: 0usize, num_classes: 0usize,
classes: vec![], classes: vec![],
depth: 0u16, depth: 0u16,
num_features: 0usize,
_phantom_tx: PhantomData, _phantom_tx: PhantomData,
_phantom_x: PhantomData, _phantom_x: PhantomData,
_phantom_y: PhantomData, _phantom_y: PhantomData,
@@ -584,7 +578,7 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
count[yi[i]] += samples[i]; count[yi[i]] += samples[i];
} }
let root = Node::new(which_max(&count), y_ncols); let root = Node::new(which_max(&count));
change_nodes.push(root); change_nodes.push(root);
let mut order: Vec<Vec<usize>> = Vec::new(); let mut order: Vec<Vec<usize>> = Vec::new();
@@ -599,7 +593,6 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
num_classes: k, num_classes: k,
classes, classes,
depth: 0u16, depth: 0u16,
num_features: num_attributes,
_phantom_tx: PhantomData, _phantom_tx: PhantomData,
_phantom_x: PhantomData, _phantom_x: PhantomData,
_phantom_y: PhantomData, _phantom_y: PhantomData,
@@ -685,7 +678,16 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
} }
} }
if is_pure {
return false;
}
let n = visitor.samples.iter().sum(); let n = visitor.samples.iter().sum();
if n <= self.parameters().min_samples_split {
return false;
}
let mut count = vec![0; self.num_classes]; let mut count = vec![0; self.num_classes];
let mut false_count = vec![0; self.num_classes]; let mut false_count = vec![0; self.num_classes];
for i in 0..n_rows { for i in 0..n_rows {
@@ -694,15 +696,7 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
} }
} }
self.nodes[visitor.node].impurity = Some(impurity(&self.parameters().criterion, &count, n)); let parent_impurity = impurity(&self.parameters().criterion, &count, n);
if is_pure {
return false;
}
if n <= self.parameters().min_samples_split {
return false;
}
let mut variables = (0..n_attr).collect::<Vec<_>>(); let mut variables = (0..n_attr).collect::<Vec<_>>();
@@ -711,7 +705,14 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
} }
for variable in variables.iter().take(mtry) { for variable in variables.iter().take(mtry) {
self.find_best_split(visitor, n, &count, &mut false_count, *variable); self.find_best_split(
visitor,
n,
&count,
&mut false_count,
parent_impurity,
*variable,
);
} }
self.nodes()[visitor.node].split_score.is_some() self.nodes()[visitor.node].split_score.is_some()
@@ -723,6 +724,7 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
n: usize, n: usize,
count: &[usize], count: &[usize],
false_count: &mut [usize], false_count: &mut [usize],
parent_impurity: f64,
j: usize, j: usize,
) { ) {
let mut true_count = vec![0; self.num_classes]; let mut true_count = vec![0; self.num_classes];
@@ -758,7 +760,6 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
let true_label = which_max(&true_count); let true_label = which_max(&true_count);
let false_label = which_max(false_count); let false_label = which_max(false_count);
let parent_impurity = self.nodes()[visitor.node].impurity.unwrap();
let gain = parent_impurity let gain = parent_impurity
- tc as f64 / n as f64 - tc as f64 / n as f64
* impurity(&self.parameters().criterion, &true_count, tc) * impurity(&self.parameters().criterion, &true_count, tc)
@@ -826,9 +827,9 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
let true_child_idx = self.nodes().len(); let true_child_idx = self.nodes().len();
self.nodes.push(Node::new(visitor.true_child_output, tc)); self.nodes.push(Node::new(visitor.true_child_output));
let false_child_idx = self.nodes().len(); let false_child_idx = self.nodes().len();
self.nodes.push(Node::new(visitor.false_child_output, fc)); self.nodes.push(Node::new(visitor.false_child_output));
self.nodes[visitor.node].true_child = Some(true_child_idx); self.nodes[visitor.node].true_child = Some(true_child_idx);
self.nodes[visitor.node].false_child = Some(false_child_idx); self.nodes[visitor.node].false_child = Some(false_child_idx);
@@ -862,33 +863,6 @@ impl<TX: Number + PartialOrd, TY: Number + Ord, X: Array2<TX>, Y: Array1<TY>>
true true
} }
/// Compute feature importances for the fitted tree.
pub fn compute_feature_importances(&self, normalize: bool) -> Vec<f64> {
let mut importances = vec![0f64; self.num_features];
for node in self.nodes().iter() {
if node.true_child.is_none() && node.false_child.is_none() {
continue;
}
let left = &self.nodes()[node.true_child.unwrap()];
let right = &self.nodes()[node.false_child.unwrap()];
importances[node.split_feature] += node.n_node_samples as f64 * node.impurity.unwrap()
- left.n_node_samples as f64 * left.impurity.unwrap()
- right.n_node_samples as f64 * right.impurity.unwrap();
}
for item in importances.iter_mut() {
*item /= self.nodes()[0].n_node_samples as f64;
}
if normalize {
let sum = importances.iter().sum::<f64>();
for importance in importances.iter_mut() {
*importance /= sum;
}
}
importances
}
} }
#[cfg(test)] #[cfg(test)]
@@ -964,8 +938,7 @@ mod tests {
&[4.9, 2.4, 3.3, 1.0], &[4.9, 2.4, 3.3, 1.0],
&[6.6, 2.9, 4.6, 1.3], &[6.6, 2.9, 4.6, 1.3],
&[5.2, 2.7, 3.9, 1.4], &[5.2, 2.7, 3.9, 1.4],
]) ]);
.unwrap();
let y: Vec<u32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let y: Vec<u32> = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
assert_eq!( assert_eq!(
@@ -1032,8 +1005,7 @@ mod tests {
&[0., 0., 1., 1.], &[0., 0., 1., 1.],
&[0., 0., 0., 0.], &[0., 0., 0., 0.],
&[0., 0., 0., 1.], &[0., 0., 0., 1.],
]) ]);
.unwrap();
let y: Vec<u32> = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; let y: Vec<u32> = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0];
assert_eq!( assert_eq!(
@@ -1044,43 +1016,6 @@ mod tests {
); );
} }
#[test]
fn test_compute_feature_importances() {
let x: DenseMatrix<f64> = DenseMatrix::from_2d_array(&[
&[1., 1., 1., 0.],
&[1., 1., 1., 0.],
&[1., 1., 1., 1.],
&[1., 1., 0., 0.],
&[1., 1., 0., 1.],
&[1., 0., 1., 0.],
&[1., 0., 1., 0.],
&[1., 0., 1., 1.],
&[1., 0., 0., 0.],
&[1., 0., 0., 1.],
&[0., 1., 1., 0.],
&[0., 1., 1., 0.],
&[0., 1., 1., 1.],
&[0., 1., 0., 0.],
&[0., 1., 0., 1.],
&[0., 0., 1., 0.],
&[0., 0., 1., 0.],
&[0., 0., 1., 1.],
&[0., 0., 0., 0.],
&[0., 0., 0., 1.],
])
.unwrap();
let y: Vec<u32> = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0];
let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap();
assert_eq!(
tree.compute_feature_importances(false),
vec![0., 0., 0.21333333333333332, 0.26666666666666666]
);
assert_eq!(
tree.compute_feature_importances(true),
vec![0., 0., 0.4444444444444444, 0.5555555555555556]
);
}
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", not(target_os = "wasi")), all(target_arch = "wasm32", not(target_os = "wasi")),
wasm_bindgen_test::wasm_bindgen_test wasm_bindgen_test::wasm_bindgen_test
@@ -1109,8 +1044,7 @@ mod tests {
&[0., 0., 1., 1.], &[0., 0., 1., 1.],
&[0., 0., 0., 0.], &[0., 0., 0., 0.],
&[0., 0., 0., 1.], &[0., 0., 0., 1.],
]) ]);
.unwrap();
let y = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0]; let y = vec![1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0];
let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap(); let tree = DecisionTreeClassifier::fit(&x, &y, Default::default()).unwrap();
+5 -7
View File
@@ -39,7 +39,7 @@
//! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564], //! &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
//! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331], //! &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
//! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551], //! &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
//! ]).unwrap(); //! ]);
//! let y: Vec<f64> = vec![ //! let y: Vec<f64> = vec![
//! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, //! 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0,
//! 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9, //! 101.2, 104.6, 108.4, 110.8, 112.6, 114.2, 115.7, 116.9,
@@ -753,8 +753,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,
@@ -768,7 +767,7 @@ mod tests {
assert!((y_hat[i] - y[i]).abs() < 0.1); assert!((y_hat[i] - y[i]).abs() < 0.1);
} }
let expected_y = [ let expected_y = vec![
87.3, 87.3, 87.3, 87.3, 98.9, 98.9, 98.9, 98.9, 98.9, 107.9, 107.9, 107.9, 114.85, 87.3, 87.3, 87.3, 87.3, 98.9, 98.9, 98.9, 98.9, 98.9, 107.9, 107.9, 107.9, 114.85,
114.85, 114.85, 114.85, 114.85, 114.85, 114.85,
]; ];
@@ -789,7 +788,7 @@ mod tests {
assert!((y_hat[i] - expected_y[i]).abs() < 0.1); assert!((y_hat[i] - expected_y[i]).abs() < 0.1);
} }
let expected_y = [ let expected_y = vec![
83.0, 88.35, 88.35, 89.5, 97.15, 97.15, 99.5, 99.5, 101.2, 104.6, 109.6, 109.6, 113.4, 83.0, 88.35, 88.35, 89.5, 97.15, 97.15, 99.5, 99.5, 101.2, 104.6, 109.6, 109.6, 113.4,
113.4, 116.30, 116.30, 113.4, 116.30, 116.30,
]; ];
@@ -835,8 +834,7 @@ mod tests {
&[502.601, 393.1, 251.4, 125.368, 1960., 69.564], &[502.601, 393.1, 251.4, 125.368, 1960., 69.564],
&[518.173, 480.6, 257.2, 127.852, 1961., 69.331], &[518.173, 480.6, 257.2, 127.852, 1961., 69.331],
&[554.894, 400.7, 282.7, 130.081, 1962., 70.551], &[554.894, 400.7, 282.7, 130.081, 1962., 70.551],
]) ]);
.unwrap();
let y: Vec<f64> = vec![ let y: Vec<f64> = vec![
83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6, 83.0, 88.5, 88.2, 89.5, 96.2, 98.1, 99.0, 100.0, 101.2, 104.6, 108.4, 110.8, 112.6,
114.2, 115.7, 116.9, 114.2, 115.7, 116.9,