1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! # ModelAnalytics - compute_kendall_correlations_group Methods
//!
//! This module contains method implementations for `ModelAnalytics`.
//!
//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
use super::modelanalytics_type::ModelAnalytics;
use crate::analytics::{
CorrelationDirection, CorrelationInsight, CorrelationStrength, PropertyCorrelationMatrix,
};
use scirs2_core::ndarray_ext::Array1;
use std::collections::{HashMap, HashSet};
fn generate_correlation_interpretation(feat1: &str, feat2: &str, coef: f64) -> String {
let direction = if coef > 0.0 { "increases" } else { "decreases" };
let strength = if coef.abs() > 0.7 {
"strongly"
} else if coef.abs() > 0.5 {
"moderately"
} else {
"weakly"
};
format!(
"As {} increases, {} {} {}",
feat1, feat2, strength, direction
)
}
impl ModelAnalytics {
/// Compute Kendall tau correlations between model properties
///
/// Kendall tau is a non-parametric measure of ordinal association.
/// It measures the similarity of orderings when ranked by each variable.
/// More robust to errors and discrepancies in data than other methods.
///
/// # Returns
///
/// A correlation matrix with Kendall tau correlation coefficients and insights
///
/// # Example
///
/// ```rust,ignore
/// use oxirs_samm::analytics::ModelAnalytics;
/// use oxirs_samm::metamodel::Aspect;
///
/// # fn example(aspect: &Aspect) -> Result<(), Box<dyn std::error::Error>> {
/// let analytics = ModelAnalytics::from_aspect(aspect)?;
/// let kendall = analytics.compute_kendall_correlations();
///
/// println!("Kendall tau correlation matrix computed");
/// println!("Features analyzed: {:?}", kendall.feature_names);
/// for insight in &kendall.insights {
/// println!(" {} <-> {}: {:.3}", insight.feature1, insight.feature2, insight.coefficient);
/// }
/// # Ok(())
/// # }
/// ```
pub fn compute_kendall_correlations(&self) -> PropertyCorrelationMatrix {
use scirs2_stats::{CorrelationBuilder, CorrelationMethod};
let features = [
(
"property_count",
self.distributions.property_distribution.mean,
),
(
"structural_complexity",
self.complexity_assessment.structural,
),
("cognitive_complexity", self.complexity_assessment.cognitive),
("coupling", self.complexity_assessment.coupling * 100.0),
("quality_score", self.quality_score),
];
let n = features.len();
let mut matrix = vec![vec![0.0; n]; n];
let mut insights = Vec::new();
for i in 0..n {
for j in 0..n {
if i == j {
matrix[i][j] = 1.0;
continue;
}
if i > j {
matrix[i][j] = matrix[j][i];
continue;
}
let x = Array1::from_vec(vec![features[i].1]);
let y = Array1::from_vec(vec![features[j].1]);
let corr_result = CorrelationBuilder::new()
.method(CorrelationMethod::Kendall)
.compute(x.view(), y.view());
let coefficient: f64 = match corr_result {
Ok(result) => result.value.correlation,
Err(_) => 0.0,
};
matrix[i][j] = coefficient;
let abs_coef = coefficient.abs();
if abs_coef > 0.3 && i != j {
let strength = if abs_coef > 0.7 {
CorrelationStrength::Strong
} else if abs_coef > 0.5 {
CorrelationStrength::Moderate
} else {
CorrelationStrength::Weak
};
let direction = if coefficient > 0.0 {
CorrelationDirection::Positive
} else {
CorrelationDirection::Negative
};
insights.push(CorrelationInsight {
feature1: features[i].0.to_string(),
feature2: features[j].0.to_string(),
coefficient,
strength,
direction,
interpretation: generate_correlation_interpretation(
features[i].0,
features[j].0,
coefficient,
),
});
}
}
}
PropertyCorrelationMatrix {
feature_names: features.iter().map(|(name, _)| name.to_string()).collect(),
correlation_matrix: matrix,
insights,
method: "Kendall".to_string(),
}
}
}