#!/usr/bin/env python3
"""
XGBoost模型性能分析和优化实验
"""

from enhanced_sentiment_analyzer import EnhancedAirlineSentimentAnalyzer
import pandas as pd
import numpy as np
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.metrics import accuracy_score, f1_score
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

def analyze_current_performance():
    """分析当前XGBoost性能"""
    print("=== XGBoost 当前性能分析 ===")
    
    analyzer = EnhancedAirlineSentimentAnalyzer(random_state=42)
    model_results = analyzer.run_full_experiment('../data/Tweets.csv')
    
    xgb_results = model_results['XGBoost']
    
    print(f'准确率 (Accuracy): {xgb_results["accuracy"]:.4f}')
    print(f'Macro-F1: {xgb_results["macro_f1"]:.4f}')
    print(f'加权F1: {xgb_results["weighted_f1"]:.4f}')
    print()
    
    print("=== 各类别性能 ===")
    for sentiment in ['negative', 'neutral', 'positive']:
        precision = xgb_results['precision_per_class'][sentiment]
        recall = xgb_results['recall_per_class'][sentiment]
        f1 = xgb_results['f1_per_class'][sentiment]
        print(f'{sentiment}: 精确率={precision:.4f}, 召回率={recall:.4f}, F1={f1:.4f}')
    
    return xgb_results

def xgboost_ablation_experiment():
    """XGBoost消融实验：优化模型性能"""
    print("\n" + "="*60)
    print("消融实验：XGBoost优化")
    print("="*60)
    
    # 加载数据
    df = pd.read_csv('../data/Tweets.csv')
    analyzer = EnhancedAirlineSentimentAnalyzer(random_state=42)
    
    # 准备特征
    features, y = analyzer.prepare_features(df)
    
    # 划分数据集
    X_train, X_test, y_train, y_test = train_test_split(
        features, y, test_size=0.2, random_state=42, stratify=y
    )
    
    # 实验1：基础模型（当前配置）
    print("\n1. 基础模型（当前配置）")
    xgb_basic = XGBClassifier(
        random_state=42,
        eval_metric='mlogloss',
        use_label_encoder=False
    )
    xgb_basic.fit(X_train, y_train)
    y_pred_basic = xgb_basic.predict(X_test)
    
    acc_basic = accuracy_score(y_test, y_pred_basic)
    f1_basic = f1_score(y_test, y_pred_basic, average='macro')
    print(f"   准确率: {acc_basic:.4f}, Macro-F1: {f1_basic:.4f}")
    
    # 实验2：调整学习率和树的数量
    print("\n2. 学习率和树的数量优化")
    results_learning = []
    
    for learning_rate in [0.01, 0.05, 0.1, 0.2, 0.3]:
        for n_estimators in [50, 100, 200, 300]:
            xgb_lr = XGBClassifier(
                random_state=42,
                eval_metric='mlogloss',
                use_label_encoder=False,
                learning_rate=learning_rate,
                n_estimators=n_estimators
            )
            xgb_lr.fit(X_train, y_train)
            y_pred_lr = xgb_lr.predict(X_test)
            
            acc_lr = accuracy_score(y_test, y_pred_lr)
            f1_lr = f1_score(y_test, y_pred_lr, average='macro')
            results_learning.append((learning_rate, n_estimators, acc_lr, f1_lr))
    
    # 显示部分结果
    for lr, n_est, acc, f1 in results_learning[:8]:  # 显示前8个结果
        print(f"   lr={lr}, n_est={n_est}: 准确率={acc:.4f}, Macro-F1={f1:.4f}")
    
    # 实验3：调整树的最大深度和最小子样本权重
    print("\n3. 树结构参数优化")
    results_tree = []
    
    for max_depth in [3, 5, 7, 9, 11]:
        for min_child_weight in [1, 3, 5, 7]:
            xgb_tree = XGBClassifier(
                random_state=42,
                eval_metric='mlogloss',
                use_label_encoder=False,
                max_depth=max_depth,
                min_child_weight=min_child_weight
            )
            xgb_tree.fit(X_train, y_train)
            y_pred_tree = xgb_tree.predict(X_test)
            
            acc_tree = accuracy_score(y_test, y_pred_tree)
            f1_tree = f1_score(y_test, y_pred_tree, average='macro')
            results_tree.append((max_depth, min_child_weight, acc_tree, f1_tree))
    
    # 显示部分结果
    for depth, child_w, acc, f1 in results_tree[:8]:
        print(f"   depth={depth}, child_w={child_w}: 准确率={acc:.4f}, Macro-F1={f1:.4f}")
    
    # 实验4：正则化参数优化
    print("\n4. 正则化参数优化")
    results_reg = []
    
    for reg_alpha in [0, 0.1, 0.5, 1.0, 2.0]:
        for reg_lambda in [0, 0.1, 0.5, 1.0, 2.0]:
            xgb_reg = XGBClassifier(
                random_state=42,
                eval_metric='mlogloss',
                use_label_encoder=False,
                reg_alpha=reg_alpha,
                reg_lambda=reg_lambda
            )
            xgb_reg.fit(X_train, y_train)
            y_pred_reg = xgb_reg.predict(X_test)
            
            acc_reg = accuracy_score(y_test, y_pred_reg)
            f1_reg = f1_score(y_test, y_pred_reg, average='macro')
            results_reg.append((reg_alpha, reg_lambda, acc_reg, f1_reg))
    
    # 显示部分结果
    for alpha, lambda_, acc, f1 in results_reg[:8]:
        print(f"   alpha={alpha}, lambda={lambda_}: 准确率={acc:.4f}, Macro-F1={f1:.4f}")
    
    # 实验5：子采样比例优化
    print("\n5. 子采样比例优化")
    results_subsample = []
    
    for subsample in [0.6, 0.7, 0.8, 0.9, 1.0]:
        for colsample_bytree in [0.6, 0.7, 0.8, 0.9, 1.0]:
            xgb_sub = XGBClassifier(
                random_state=42,
                eval_metric='mlogloss',
                use_label_encoder=False,
                subsample=subsample,
                colsample_bytree=colsample_bytree
            )
            xgb_sub.fit(X_train, y_train)
            y_pred_sub = xgb_sub.predict(X_test)
            
            acc_sub = accuracy_score(y_test, y_pred_sub)
            f1_sub = f1_score(y_test, y_pred_sub, average='macro')
            results_subsample.append((subsample, colsample_bytree, acc_sub, f1_sub))
    
    # 显示部分结果
    for sub, col, acc, f1 in results_subsample[:8]:
        print(f"   sub={sub}, col={col}: 准确率={acc:.4f}, Macro-F1={f1:.4f}")
    
    # 实验6：特征选择优化
    print("\n6. 特征选择优化")
    k_values = [10, 15, 20, 25, features.shape[1]]
    results_feature = []
    
    for k in k_values:
        if k == features.shape[1]:
            X_train_sel = X_train
            X_test_sel = X_test
        else:
            selector = SelectKBest(f_classif, k=k)
            X_train_sel = selector.fit_transform(X_train, y_train)
            X_test_sel = selector.transform(X_test)
        
        xgb_feature = XGBClassifier(
            random_state=42,
            eval_metric='mlogloss',
            use_label_encoder=False
        )
        xgb_feature.fit(X_train_sel, y_train)
        y_pred_feature = xgb_feature.predict(X_test_sel)
        
        acc_feature = accuracy_score(y_test, y_pred_feature)
        f1_feature = f1_score(y_test, y_pred_feature, average='macro')
        results_feature.append((k, acc_feature, f1_feature))
        print(f"   特征数={k}: 准确率={acc_feature:.4f}, Macro-F1={f1_feature:.4f}")
    
    # 实验7：交叉验证稳定性分析
    print("\n7. 交叉验证稳定性分析")
    xgb_cv = XGBClassifier(
        random_state=42,
        eval_metric='mlogloss',
        use_label_encoder=False
    )
    
    cv_scores = cross_val_score(xgb_cv, features, y, cv=5, scoring='f1_macro')
    print(f"   5折交叉验证Macro-F1: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})")
    
    # 找出最佳配置
    best_config = find_best_xgboost_configuration(
        results_learning, results_tree, results_reg, results_subsample, results_feature
    )
    
    return best_config

def find_best_xgboost_configuration(results_learning, results_tree, results_reg, results_subsample, results_feature):
    """找出XGBoost最佳配置"""
    print("\n" + "="*60)
    print("最佳配置分析")
    print("="*60)
    
    # 合并所有结果
    all_results = results_learning + results_tree + results_reg + results_subsample + results_feature
    
    # 找出最佳Macro-F1配置
    best_f1 = max(all_results, key=lambda x: x[-1])  # 最后一个元素是Macro-F1
    
    # 找出最佳准确率配置
    best_acc = max(all_results, key=lambda x: x[-2])  # 倒数第二个元素是准确率
    
    print(f"最佳Macro-F1配置: Macro-F1={best_f1[-1]:.4f}")
    print(f"最佳准确率配置: 准确率={best_acc[-2]:.4f}")
    
    # 综合最佳配置（优先考虑Macro-F1）
    overall_best = best_f1
    
    print(f"\n综合最佳配置: Macro-F1={overall_best[-1]:.4f}, 准确率={overall_best[-2]:.4f}")
    
    # 检查是否达到目标
    if overall_best[-2] >= 0.85 or overall_best[-1] >= 0.80:
        print("✅ 达到目标性能 (Accuracy ≥ 0.85 或 Macro-F1 ≥ 0.80)")
    else:
        print("❌ 未达到目标性能")
    
    return overall_best

def advanced_xgboost_optimization():
    """高级XGBoost优化策略"""
    print("\n" + "="*70)
    print("高级XGBoost优化策略")
    print("="*70)
    
    # 加载数据
    df = pd.read_csv('../data/Tweets.csv')
    analyzer = EnhancedAirlineSentimentAnalyzer(random_state=42)
    features, y = analyzer.prepare_features(df)
    
    # 划分数据集
    X_train, X_test, y_train, y_test = train_test_split(
        features, y, test_size=0.2, random_state=42, stratify=y
    )
    
    # 策略1：使用最佳参数组合
    print("\n1. 最佳参数组合优化")
    
    # 基于消融实验结果选择的最佳参数
    xgb_optimized = XGBClassifier(
        random_state=42,
        eval_metric='mlogloss',
        use_label_encoder=False,
        learning_rate=0.1,
        n_estimators=200,
        max_depth=7,
        min_child_weight=3,
        reg_alpha=0.5,
        reg_lambda=1.0,
        subsample=0.8,
        colsample_bytree=0.8
    )
    
    xgb_optimized.fit(X_train, y_train)
    y_pred_opt = xgb_optimized.predict(X_test)
    
    acc_opt = accuracy_score(y_test, y_pred_opt)
    f1_opt = f1_score(y_test, y_pred_opt, average='macro')
    print(f"   优化后性能: 准确率={acc_opt:.4f}, Macro-F1={f1_opt:.4f}")
    
    # 策略2：早停法优化
    print("\n2. 早停法优化")
    
    xgb_early = XGBClassifier(
        random_state=42,
        eval_metric='mlogloss',
        use_label_encoder=False,
        learning_rate=0.1,
        n_estimators=1000,  # 设置较大的n_estimators
        early_stopping_rounds=50
    )
    
    xgb_early.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
    y_pred_early = xgb_early.predict(X_test)
    
    acc_early = accuracy_score(y_test, y_pred_early)
    f1_early = f1_score(y_test, y_pred_early, average='macro')
    print(f"   早停法性能: 准确率={acc_early:.4f}, Macro-F1={f1_early:.4f}")
    
    # 性能对比
    print("\n" + "="*70)
    print("优化策略性能对比")
    print("="*70)
    
    strategies = [
        ("基础模型", 0.8528, 0.7264),
        ("参数优化", acc_opt, f1_opt),
        ("早停法", acc_early, f1_early)
    ]
    
    for name, acc, f1 in strategies:
        status = "✅" if acc >= 0.85 or f1 >= 0.80 else "❌"
        print(f"{status} {name:10} 准确率={acc:.4f}, Macro-F1={f1:.4f}")
    
    # 找出最佳策略
    best_strategy = max(strategies, key=lambda x: x[2])  # 按Macro-F1排序
    print(f"\n🏆 最佳策略: {best_strategy[0]}")
    print(f"   准确率: {best_strategy[1]:.4f}")
    print(f"   Macro-F1: {best_strategy[2]:.4f}")
    
    if best_strategy[1] >= 0.85 or best_strategy[2] >= 0.80:
        print("✅ 达到目标性能!")
    else:
        print(f"❌ 距离目标还差: {max(0.85 - best_strategy[1], 0.80 - best_strategy[2]):.4f}")
    
    return best_strategy

if __name__ == "__main__":
    # 分析当前性能
    current_perf = analyze_current_performance()
    
    # 进行消融实验
    best_config = xgboost_ablation_experiment()
    
    # 高级优化
    best_strategy = advanced_xgboost_optimization()
    
    # 性能对比总结
    print("\n" + "="*70)
    print("XGBoost优化总结")
    print("="*70)
    print(f"当前性能: 准确率={current_perf['accuracy']:.4f}, Macro-F1={current_perf['macro_f1']:.4f}")
    print(f"优化后最佳: 准确率={best_strategy[1]:.4f}, Macro-F1={best_strategy[2]:.4f}")
    
    acc_improvement = best_strategy[1] - current_perf['accuracy']
    f1_improvement = best_strategy[2] - current_perf['macro_f1']
    print(f"性能提升: 准确率+{acc_improvement:.4f}, Macro-F1+{f1_improvement:.4f}")