lawkit_core/laws/pareto/
analysis.rs

1use super::result::ParetoResult;
2use crate::error::Result;
3
4/// パレート法則(80/20原則)の分析を実行
5pub fn analyze_pareto_distribution(numbers: &[f64], dataset_name: &str) -> Result<ParetoResult> {
6    ParetoResult::new(dataset_name.to_string(), numbers)
7}
8
9/// ビジネスパレート分析を実行
10pub fn analyze_business_pareto(
11    numbers: &[f64],
12    dataset_name: &str,
13) -> Result<BusinessParetoAnalysis> {
14    let pareto_result = analyze_pareto_distribution(numbers, dataset_name)?;
15
16    let business_insights = generate_business_insights(&pareto_result);
17    let action_recommendations = generate_action_recommendations(&pareto_result);
18
19    Ok(BusinessParetoAnalysis {
20        pareto_result,
21        business_insights,
22        action_recommendations,
23    })
24}
25
26/// ビジネス洞察を生成
27fn generate_business_insights(pareto_result: &ParetoResult) -> Vec<BusinessInsight> {
28    let mut insights = Vec::new();
29
30    // 80/20原則の適合度による洞察
31    if pareto_result.pareto_ratio > 0.8 && pareto_result.pareto_ratio < 1.2 {
32        insights.push(BusinessInsight {
33            category: "Distribution".to_string(),
34            message: "データは典型的なパレート分布を示しています".to_string(),
35            impact_level: "High".to_string(),
36        });
37    }
38
39    // 集中度による洞察
40    if pareto_result.concentration_index > 0.6 {
41        insights.push(BusinessInsight {
42            category: "Concentration".to_string(),
43            message: "高度な集中が見られます - 少数の要素が大きな影響を持っています".to_string(),
44            impact_level: "Critical".to_string(),
45        });
46    }
47
48    insights
49}
50
51/// アクション推奨を生成
52fn generate_action_recommendations(pareto_result: &ParetoResult) -> Vec<ActionRecommendation> {
53    let mut recommendations = Vec::new();
54
55    // 上位20%の影響度に基づく推奨
56    if pareto_result.top_20_percent_share > 80.0 {
57        recommendations.push(ActionRecommendation {
58            priority: "High".to_string(),
59            action: "上位20%の要素に集中的にリソースを配分してください".to_string(),
60            expected_impact: "効率的な成果向上が期待できます".to_string(),
61        });
62    }
63
64    recommendations
65}
66
67/// ビジネス洞察
68#[derive(Debug, Clone)]
69pub struct BusinessInsight {
70    pub category: String,
71    pub message: String,
72    pub impact_level: String,
73}
74
75/// アクション推奨
76#[derive(Debug, Clone)]
77pub struct ActionRecommendation {
78    pub priority: String,
79    pub action: String,
80    pub expected_impact: String,
81}
82
83/// ビジネスパレート分析結果
84#[derive(Debug, Clone)]
85pub struct BusinessParetoAnalysis {
86    pub pareto_result: ParetoResult,
87    pub business_insights: Vec<BusinessInsight>,
88    pub action_recommendations: Vec<ActionRecommendation>,
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_perfect_pareto_distribution() {
97        // 80/20分布に近いテストデータ
98        let numbers = vec![
99            100.0, 90.0, 80.0, 70.0, 60.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0,
100        ];
101        let result = analyze_pareto_distribution(&numbers, "test").unwrap();
102
103        assert_eq!(result.numbers_analyzed, 15);
104        assert!(result.top_20_percent_share > 50.0); // 上位20%がかなりの割合を占有
105    }
106
107    #[test]
108    fn test_uniform_distribution() {
109        // 均等分布(パレート原則に合わない)
110        let numbers = vec![10.0; 20]; // 全て同じ値
111        let result = analyze_pareto_distribution(&numbers, "uniform").unwrap();
112
113        assert_eq!(result.numbers_analyzed, 20);
114        assert!((result.top_20_percent_share - 20.0).abs() < 1.0); // 上位20%が約20%を占有
115        assert!(matches!(
116            result.risk_level,
117            crate::common::risk::RiskLevel::Critical
118        ));
119    }
120
121    #[test]
122    fn test_business_analysis() {
123        let numbers = vec![
124            1000.0, 800.0, 600.0, 400.0, 200.0, 50.0, 40.0, 30.0, 20.0, 10.0,
125        ];
126        let result = analyze_pareto_distribution(&numbers, "sales").unwrap();
127
128        assert_eq!(result.dataset_name, "sales");
129        assert_eq!(result.numbers_analyzed, 10);
130    }
131
132    #[test]
133    fn test_insufficient_data() {
134        let numbers = vec![1.0, 2.0]; // 5個未満
135        let result = analyze_pareto_distribution(&numbers, "test");
136
137        assert!(result.is_err());
138    }
139}