sklears_feature_selection/genetic_optimization/
fairnessawareobjective_traits.rs1use super::functions::*;
12use super::types::*;
13use scirs2_core::ndarray::{Array1, Array2};
14use sklears_core::error::{Result as SklResult, SklearsError};
15
16impl ObjectiveFunction for FairnessAwareObjective {
17 fn evaluate(
18 &self,
19 x: &Array2<f64>,
20 y_classif: Option<&Array1<i32>>,
21 y_regression: Option<&Array1<f64>>,
22 feature_mask: &[bool],
23 ) -> SklResult<f64> {
24 let selected_indices: Vec<usize> = feature_mask
25 .iter()
26 .enumerate()
27 .filter_map(|(i, &selected)| if selected { Some(i) } else { None })
28 .collect();
29 if selected_indices.is_empty() {
30 return Ok(1.0);
31 }
32 let mut total_performance = 0.0;
33 if let Some(y) = y_classif {
34 for &idx in &selected_indices {
35 let feature = x.column(idx).to_owned();
36 let y_float = y.mapv(|v| v as f64);
37 let correlation = compute_pearson_correlation(&feature, &y_float).abs();
38 total_performance += correlation;
39 }
40 } else if let Some(y) = y_regression {
41 for &idx in &selected_indices {
42 let feature = x.column(idx).to_owned();
43 let correlation = compute_pearson_correlation(&feature, y).abs();
44 total_performance += correlation;
45 }
46 } else {
47 return Err(SklearsError::InvalidInput(
48 "Need either classification or regression target".to_string(),
49 ));
50 }
51 let avg_performance = total_performance / selected_indices.len() as f64;
52 let fairness_score = match self.fairness_metric {
53 FairnessMetric::DemographicParity | FairnessMetric::StatisticalParityDifference => {
54 let protected_float = self.protected_groups.mapv(|v| v as f64);
55 let mut total_bias = 0.0;
56 for &idx in &selected_indices {
57 let feature = x.column(idx).to_owned();
58 let correlation = compute_pearson_correlation(&feature, &protected_float).abs();
59 total_bias += correlation;
60 }
61 let avg_bias = total_bias / selected_indices.len() as f64;
62 1.0 - avg_bias
63 }
64 _ => {
65 let protected_float = self.protected_groups.mapv(|v| v as f64);
66 let mut total_bias = 0.0;
67 for &idx in &selected_indices {
68 let feature = x.column(idx).to_owned();
69 let correlation = compute_pearson_correlation(&feature, &protected_float).abs();
70 total_bias += correlation;
71 }
72 let avg_bias = total_bias / selected_indices.len() as f64;
73 1.0 - avg_bias
74 }
75 };
76 let fairness_aware_score =
77 (1.0 - self.fairness_weight) * avg_performance + self.fairness_weight * fairness_score;
78 Ok(fairness_aware_score)
79 }
80 fn name(&self) -> &str {
81 "fairness_aware"
82 }
83 fn clone_box(&self) -> Box<dyn ObjectiveFunction> {
84 Box::new(self.clone())
85 }
86}