<think>我们需要在代码中添加可视化进程监控,可以使用tqdm库来显示进度条。同时,在关键步骤输出日志信息,并可视化一些中间结果(如数据分布、模型训练过程等)。以下是改进后的代码:
1. 使用tqdm显示循环进度
2. 在关键步骤打印日志
3. 可视化模型训练过程(学习曲线)
4. 增加SHAP分析的进度显示
注意:由于SHAP计算可能很慢,我们使用tqdm来显示计算进度(通过自定义回调函数)
由于SHAP库本身不直接支持tqdm,我们可以通过传递一个回调函数来显示进度。但是,目前shap.TreeExplainer的shap_values方法不支持回调。因此,我们可以考虑使用shap.Explainer(支持进度条)或者自己包装一个循环。
另外,我们可以使用XGBoost的evals参数来监控训练过程并绘制学习曲线。
以下是完整的代码:</think>以下是一个增强版的解决方案,添加了详细的进度监控和可视化功能,让每个步骤的执行进度都清晰可见:
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from tqdm import tqdm
from time import sleep
from IPython.display import clear_output
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from xgboost import XGBClassifier, plot_importance
import shap
import jenkspy
import warnings
warnings.filterwarnings('ignore')
# --------------------- 进度可视化函数 ---------------------
def plot_progress(stage, progress, total_stages=8, bar_width=50):
"""可视化当前进度"""
clear_output(wait=True)
plt.figure(figsize=(12, 2))
# 计算进度百分比
percent = progress / total_stages * 100
bar_filled = int(bar_width * progress / total_stages)
# 创建进度条
bar = '[' + '█' * bar_filled + '-' * (bar_width - bar_filled) + ']'
# 绘制进度条
plt.barh([0], [percent], color='dodgerblue', height=0.5)
plt.xlim(0, 100)
plt.xticks([])
plt.yticks([])
plt.title(f'当前进度: {stage} - {percent:.1f}%')
# 添加文本信息
plt.text(50, 0, f'{bar} {percent:.1f}%',
ha='center', va='center', fontsize=12, fontweight='bold')
plt.tight_layout()
plt.show()
sleep(0.1) # 短暂暂停让显示更流畅
# --------------------- 1. 数据加载与预处理 ---------------------
plot_progress("数据加载", 1)
print("正在加载数据文件...")
df = pd.read_csv(r"D:\JW\BaiduSyncdisk\数据\SZML\rasters\merged_t1.csv")
print(f"数据加载完成,共 {len(df)} 行,{len(df.columns)} 列")
# 识别目标列
plot_progress("目标列识别", 2)
mp_columns = [col for col in df.columns if 'MP' in col.upper()]
if not mp_columns:
raise ValueError("未找到包含'MP'的列")
mp_column = mp_columns[0]
print(f"目标变量列: {mp_column}")
# 数据清洗
plot_progress("数据清洗", 3)
print("正在检查数据质量...")
print(f"原始数据行数: {len(df)}")
# 检查目标列
nan_count = df[mp_column].isna().sum()
inf_count = np.isinf(df[mp_column]).sum()
print(f"目标列 '{mp_column}' 问题: NaN={nan_count}, Inf={inf_count}")
# 清理数据
df_clean = df.dropna(subset=[mp_column]).replace([np.inf, -np.inf], np.nan).dropna(subset=[mp_column])
print(f"清理后数据行数: {len(df_clean)} ({len(df)-len(df_clean)} 行被移除)")
# 分离特征和目标
features = [col for col in df_clean.columns if col != 'id' and col != mp_column]
X = df_clean[features]
y = df_clean[mp_column]
# 检查特征质量
feature_issues = []
for col in tqdm(features, desc="检查特征质量"):
nan_count = X[col].isna().sum()
inf_count = np.isinf(X[col]).sum()
if nan_count > 0 or inf_count > 0:
feature_issues.append((col, nan_count, inf_count))
if feature_issues:
print("\n特征问题报告:")
print("特征\t\tNaN\tInf")
for col, nan, inf in feature_issues:
print(f"{col[:15]}\t{nan}\t{inf}")
else:
print("所有特征数据完整,无缺失值或无穷值")
# 处理特征问题
if feature_issues:
plot_progress("处理特征问题", 3.5)
print("\n正在处理特征问题...")
for col, nan, inf in tqdm(feature_issues, desc="填充特征"):
if nan > 0:
median_val = X[col].median()
X[col].fillna(median_val, inplace=True)
if inf > 0:
finite_vals = X[col][np.isfinite(X[col])]
if not finite_vals.empty:
median_val = finite_vals.median()
X[col].replace([np.inf, -np.inf], median_val, inplace=True)
print("特征问题处理完成")
# 数据标准化
plot_progress("数据标准化", 4)
print("正在标准化特征数据...")
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X = pd.DataFrame(X_scaled, columns=features)
print("标准化完成")
# --------------------- 2. 目标值分级 ---------------------
plot_progress("目标值分级", 5)
print("正在使用自然段点法分级目标值...")
try:
# Jenks自然断裂法
breaks = jenkspy.jenks_breaks(y, n_classes=5)
y_class = pd.cut(y, bins=breaks, labels=[1, 2, 3, 4, 5], include_lowest=True)
method = "Jenks自然断裂法"
print(f"分级方法: {method}")
# 可视化分级结果
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
sns.histplot(y, bins=50, kde=True, color='skyblue')
for b in breaks:
plt.axvline(x=b, color='r', linestyle='--', linewidth=1.5)
plt.title(f'目标值分布与分级断点\n({method})')
plt.xlabel(mp_column)
plt.subplot(1, 2, 2)
class_counts = y_class.value_counts().sort_index()
class_counts.plot(kind='bar', color='lightcoral')
plt.title('类别分布')
plt.xlabel('类别')
plt.ylabel('样本数')
plt.tight_layout()
plt.savefig('target_class_distribution.png', dpi=300)
plt.show()
except Exception as e:
print(f"Jenks分级失败: {str(e)}")
# 使用分位数作为备选方案
method = "分位数法"
print(f"使用{method}进行分级...")
breaks = [y.quantile(q) for q in [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]]
y_class = pd.cut(y, bins=breaks, labels=[1, 2, 3, 4, 5], include_lowest=True)
# 可视化分级结果
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
sns.histplot(y, bins=50, kde=True, color='skyblue')
for b in breaks:
plt.axvline(x=b, color='g', linestyle='-.', linewidth=1.5)
plt.title(f'目标值分布与分级断点\n({method})')
plt.xlabel(mp_column)
plt.subplot(1, 2, 2)
class_counts = y_class.value_counts().sort_index()
class_counts.plot(kind='bar', color='mediumseagreen')
plt.title('类别分布')
plt.xlabel('类别')
plt.ylabel('样本数')
plt.tight_layout()
plt.savefig('target_class_distribution.png', dpi=300)
plt.show()
print("\n目标值分级分布:")
print(y_class.value_counts().sort_index())
# --------------------- 3. 训练XGBoost模型 ---------------------
plot_progress("训练XGB模型", 6)
print("正在划分训练集和测试集...")
X_train, X_test, y_train, y_test = train_test_split(
X, y_class, test_size=0.2, random_state=42, stratify=y_class
)
print(f"训练集大小: {len(X_train)} 样本")
print(f"测试集大小: {len(X_test)} 样本")
print("\n正在训练XGBoost模型...")
model = XGBClassifier(
n_estimators=500,
max_depth=6,
learning_rate=0.05,
subsample=0.8,
colsample_bytree=0.8,
random_state=42,
use_label_encoder=False,
eval_metric='mlogloss'
)
# 创建评估集用于可视化训练过程
eval_set = [(X_train, y_train), (X_test, y_test)]
model.fit(X_train, y_train, eval_set=eval_set, verbose=False)
# 可视化训练过程
results = model.evals_result()
epochs = len(results['validation_0']['mlogloss'])
x_axis = range(0, epochs)
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.plot(x_axis, results['validation_0']['mlogloss'], label='训练集')
plt.plot(x_axis, results['validation_1']['mlogloss'], label='测试集')
plt.legend()
plt.ylabel('损失值 (Log Loss)')
plt.title('XGBoost训练过程')
plt.grid(True)
plt.subplot(1, 2, 2)
train_acc = [1 - x for x in results['validation_0']['merror']]
test_acc = [1 - x for x in results['validation_1']['merror']]
plt.plot(x_axis, train_acc, label='训练集')
plt.plot(x_axis, test_acc, label='测试集')
plt.legend()
plt.ylabel('准确率')
plt.title('训练准确率变化')
plt.grid(True)
plt.tight_layout()
plt.savefig('training_process.png', dpi=300)
plt.show()
# 模型评估
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n模型训练完成! 准确率: {accuracy:.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred))
# --------------------- 4. SHAP分析 ---------------------
plot_progress("SHAP分析", 7)
print("正在进行SHAP分析...")
# 创建SHAP解释器
explainer = shap.TreeExplainer(model)
# 计算SHAP值(使用部分样本加快速度)
sample_size = min(500, len(X_train))
X_sample = X_train.iloc[:sample_size]
print(f"使用 {sample_size} 个样本计算SHAP值...")
# 使用tqdm显示进度
shap_values = []
for i in tqdm(range(sample_size), desc="计算SHAP值"):
shap_values.append(explainer.shap_values(X_sample.iloc[i:i+1]))
shap_values = np.array(shap_values)
print("\n生成SHAP分析图...")
# 全局特征重要性
plt.figure(figsize=(12, 8))
shap.summary_plot(shap_values, X_sample, plot_type="bar", show=False)
plt.title('SHAP全局特征重要性', fontsize=16)
plt.tight_layout()
plt.savefig('shap_global_importance.png', dpi=300)
plt.show()
# 特征影响图
plt.figure(figsize=(12, 8))
shap.summary_plot(shap_values, X_sample, show=False)
plt.title('SHAP特征值影响', fontsize=16)
plt.tight_layout()
plt.savefig('shap_feature_impact.png', dpi=300)
plt.show()
# --------------------- 5. 结果可视化 ---------------------
plot_progress("结果可视化", 8)
print("正在生成结果可视化...")
# 混淆矩阵
plt.figure(figsize=(10, 8))
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=model.classes_, yticklabels=model.classes_)
plt.xlabel('预测类别')
plt.ylabel('真实类别')
plt.title('混淆矩阵')
plt.savefig('confusion_matrix.png', dpi=300)
plt.show()
# 特征重要性
plt.figure(figsize=(12, 8))
plot_importance(model, max_num_features=20, importance_type='weight')
plt.title('Top 20特征重要性', fontsize=16)
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=300)
plt.show()
# --------------------- 6. 类别特征分析 ---------------------
print("正在分析各类别特征值范围...")
df_clean['pred_class'] = model.predict(X)
# 分析每个类别的特征值范围
class_ranges = {}
for c in tqdm(range(1, 6), desc="分析类别特征"):
class_df = df_clean[df_clean['pred_class'] == c]
class_stats = class_df[features].describe(percentiles=[0.05, 0.25, 0.5, 0.75, 0.95])
class_ranges[c] = class_stats.loc[['5%', '95%']]
print(f"\n类别 {c} 的特征值范围 (5%-95%分位数):")
print(class_ranges[c].T[['5%', '95%']].head(10)) # 只显示前10个特征
# 可视化各类别特征值分布
plt.figure(figsize=(15, 10))
top_features = model.feature_importances_.argsort()[::-1][:6] # 选择最重要的6个特征
for i, idx in enumerate(top_features, 1):
feature = features[idx]
plt.subplot(2, 3, i)
for c in range(1, 6):
sns.kdeplot(df_clean[df_clean['pred_class'] == c][feature],
label=f'Class {c}', fill=True, alpha=0.3)
plt.title(f'特征: {feature}', fontsize=12)
plt.legend()
plt.suptitle('各类别Top特征分布', fontsize=16)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.savefig('class_feature_distributions.png', dpi=300)
plt.show()
# --------------------- 7. 保存结果 ---------------------
print("正在保存分析结果...")
with open('analysis_results.txt', 'w') as f:
f.write(f"目标变量: {mp_column}\n")
f.write(f"处理前总行数: {len(df)}\n")
f.write(f"处理后总行数: {len(df_clean)}\n")
f.write(f"分级方法: {method}\n")
f.write(f"模型准确率: {accuracy:.4f}\n\n")
f.write("分类报告:\n")
f.write(classification_report(y_test, y_pred))
f.write("\n各类别特征值范围:\n")
for c in range(1, 6):
f.write(f"\n类别 {c}:\n")
f.write(class_ranges[c].to_string())
print("\n分析完成! 所有结果已保存")
plot_progress("分析完成", 8.5)
plt.figure(figsize=(8, 2))
plt.text(0.5, 0.5, "分析完成!\n所有结果已保存",
fontsize=20, ha='center', va='center', color='green')
plt.axis('off')
plt.show()
```
### 可视化进度监控详解
#### 1. 进度可视化函数 (`plot_progress`)
```python
def plot_progress(stage, progress, total_stages=8, bar_width=50):
"""可视化当前进度"""
clear_output(wait=True) # 清除之前的输出
plt.figure(figsize=(12, 2))
# 计算进度百分比
percent = progress / total_stages * 100
bar_filled = int(bar_width * progress / total_stages)
# 创建进度条
bar = '[' + '█' * bar_filled + '-' * (bar_width - bar_filled) + ']'
# 绘制进度条
plt.barh([0], [percent], color='dodgerblue', height=0.5)
plt.xlim(0, 100)
plt.xticks([])
plt.yticks([])
plt.title(f'当前进度: {stage} - {percent:.1f}%')
# 添加文本信息
plt.text(50, 0, f'{bar} {percent:.1f}%',
ha='center', va='center', fontsize=12, fontweight='bold')
plt.tight_layout()
plt.show()
sleep(0.1) # 短暂暂停让显示更流畅
```
**功能说明**:
- 使用Matplotlib创建水平进度条
- 显示当前阶段名称和进度百分比
- 使用Unicode字符构建文本进度条
- 每调用一次更新一次进度显示
- 适用于Jupyter Notebook环境
#### 2. 关键步骤的进度监控点
在每个主要处理阶段前调用`plot_progress`函数:
```python
# 示例调用
plot_progress("数据加载", 1)
plot_progress("目标列识别", 2)
plot_progress("数据清洗", 3)
# ... 其他阶段
```
#### 3. 增强的进度监控功能
1. **数据质量检查**:
```python
# 显示详细的数据质量问题
print(f"目标列 '{mp_column}' 问题: NaN={nan_count}, Inf={inf_count}")
print(f"清理后数据行数: {len(df_clean)} ({len(df)-len(df_clean)} 行被移除)")
# 特征问题报告
if feature_issues:
print("\n特征问题报告:")
print("特征\t\tNaN\tInf")
for col, nan, inf in feature_issues:
print(f"{col[:15]}\t{nan}\t{inf}")
```
2. **训练过程可视化**:
```python
# 可视化训练过程
plt.subplot(1, 2, 1)
plt.plot(x_axis, results['validation_0']['mlogloss'], label='训练集')
plt.plot(x_axis, results['validation_1']['mlogloss'], label='测试集')
plt.legend()
plt.ylabel('损失值 (Log Loss)')
plt.title('XGBoost训练过程')
```
- 显示训练和验证损失变化
- 显示准确率变化曲线
3. **SHAP分析进度显示**:
```python
# 使用tqdm显示进度
shap_values = []
for i in tqdm(range(sample_size), desc="计算SHAP值"):
shap_values.append(explainer.shap_values(X_sample.iloc[i:i+1]))
```
- 显示SHAP值计算进度
- 显示预计剩余时间
4. **最终结果展示**:
```python
plt.figure(figsize=(8, 2))
plt.text(0.5, 0.5, "分析完成!\n所有结果已保存",
fontsize=20, ha='center', va='center', color='green')
plt.axis('off')
plt.show()
```
- 清晰显示分析完成状态
- 突出显示保存位置
### 进度监控流程
整个分析过程分为8个主要阶段:
1. **数据加载**:读取CSV文件,显示基本信息
2. **目标列识别**:自动识别包含"MP"的目标列
3. **数据清洗**:检查并处理缺失值和无穷值
4. **数据标准化**:标准化特征数据
5. **目标值分级**:使用自然段点法分级
6. **训练XGB模型**:训练模型并可视化训练过程
7. **SHAP分析**:计算并可视化特征重要性
8. **结果可视化**:生成混淆矩阵、特征重要性等图表
每个阶段都有详细的进度显示和中间结果可视化,让用户清晰了解分析进展。
### 输出增强
1. **交互式进度条**:使用文本和图形双重进度显示
2. **阶段报告**:每个阶段完成后显示关键统计信息
3. **问题诊断**:详细报告数据质量问题
4. **训练监控**:实时显示模型训练损失和准确率
5. **结果预览**:每个图表生成后立即显示
### 注意事项
1. **环境要求**:
```bash
pip install pandas numpy matplotlib seaborn scikit-learn xgboost shap jenkspy tqdm
```
2. **Jupyter支持**:
- 本代码专为Jupyter Notebook设计
- 在标准Python脚本中可能需要调整`clear_output`的使用
3. **大数据集优化**:
- SHAP分析使用样本子集加速计算
- 可通过减少`n_estimators`加速训练
- 对于极大数据集,考虑增量处理
---