use crate::tensor::Tensor;
use crate::utils;
pub struct ConfusionMatrix {
pub data: Vec<Vec<usize>>,
}
impl ConfusionMatrix {
pub fn new(y_true: Tensor, y_pred: Tensor) -> ConfusionMatrix {
assert_eq!(y_true.shape, y_pred.shape);
let cm_shape = vec![y_true.shape[1], y_true.shape[1]];
let mut cm = vec![vec![0; cm_shape[0]]; cm_shape[0]];
let y_pred_categories = utils::one_hot_encoded_tensor_to_indices(&y_pred);
let y_true_categories = utils::one_hot_encoded_tensor_to_indices(&y_true);
for index in 0..y_pred_categories.len() {
cm[y_true_categories[index]][y_pred_categories[index]] += 1;
}
ConfusionMatrix { data: cm }
}
pub fn accuracy_score(&self) -> f64 {
let correct_classif: f64 =
(0..self.data.len()).map(|v| self.data[v][v]).sum::<usize>() as f64;
let cm_sum: f64 = self
.data
.iter()
.map(|v| v.iter().sum::<usize>() as f64)
.sum();
correct_classif as f64 / cm_sum
}
pub fn recall_score(&self, class: usize) -> f64 {
let correct_class: usize = self.data[class][class];
let all_predicted_class = (0..self.data.len())
.map(|v| self.data[v][class])
.sum::<usize>() as f64;
correct_class as f64 / all_predicted_class
}
pub fn precision_score(&self, class: usize) -> f64 {
let correct_class: usize = self.data[class][class];
let actual_class = (0..self.data.len())
.map(|v| self.data[class][v])
.sum::<usize>() as f64;
correct_class as f64 / actual_class
}
pub fn f1_score(&self, class: usize) -> f64 {
(2.0 * self.recall_score(class) * self.precision_score(class))
/ (self.recall_score(class) + self.precision_score(class))
}
}