
Data Exploration Visualization
- 4 installs
- 3 repo stars
- Updated December 23, 2025
- liangdabiao/claude-data-analysis-ultra
Helps with ai & agent building tasks.
About
data-exploration-visualization is a Claude Code skill in the AI & Agent Building category.
- data-exploration-visualization
- AI & Agent Building
- AI-coding skill
Data Exploration Visualization by the numbers
- 4 all-time installs (skills.sh)
- Ranked #13,358 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/liangdabiao/claude-data-analysis-ultra --skill data-exploration-visualizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 3 |
| Last updated | December 23, 2025 |
| Repository | liangdabiao/claude-data-analysis-ultra ↗ |
What it does
Helps with ai & agent building tasks.
Files
数据探索可视化技能
技能概述
数据探索可视化技能是一个基于《数据分析咖哥十话》第2课理论的自动化EDA工具包,提供从数据加载到专业分析报告生成的完整解决方案。该技能集成了最先进的数据探索、可视化和机器学习技术,帮助用户快速深入理解数据特征和规律。
核心功能
🔍 智能数据探索
- 自动数据诊断: 检测数据质量问题、异常值和缺失值模式
- 统计描述分析: 生成全面的统计摘要和分布特征
- 相关性分析: 识别特征间关系和依赖模式
- 数据质量报告: 专业级数据质量评估和建议
📊 专业可视化生成
- 分布可视化: 直方图、密度图、小提琴图、QQ图
- 统计可视化: 箱线图、误差条图、置信区间图
- 关系可视化: 散点图、热图、配对图、3D散点图
- 专门图表: ROC曲线、混淆矩阵、特征重要性图
- 交互式图表: Plotly驱动的动态可视化
🏥 医疗数据专精
- 医疗编码支持: ICD-10、SNOMED CT等医疗标准
- 生物标记物分析: 专门的医学指标处理
- 诊断模型构建: 医疗预测模型和评估
- 医学可解释性: 符合医学实践的解释框架
🤖 自动化建模评估
- 多算法支持: 逻辑回归、随机森林、XGBoost、神经网络
- 自动特征工程: 特征选择、转换和优化
- 超参数调优: 网格搜索和贝叶斯优化
- 模型可解释性: SHAP值、特征重要性、部分依赖图
📋 专业报告生成
- HTML报告: 可发表级交互式分析报告
- PDF导出: 高质量文档格式输出
- Markdown支持: 轻量级报告格式
- 自定义模板: 可配置的报告模板系统
使用场景
🏥 医疗健康领域
- 疾病预测: 基于临床数据的疾病风险预测
- 诊断辅助: 医学影像和检验结果分析
- 流行病学研究: 疫情数据分析和趋势预测
- 临床试验: 试验数据统计分析和可视化
💰 金融风控领域
- 信用评估: 个人和企业信用风险建模
- 欺诈检测: 异常交易模式识别
- 投资分析: 市场趋势和风险评估
- 合规报告: 监管要求的分析报告
🛒 电商零售领域
- 用户分析: 客户行为和偏好分析
- 销售预测: 销量预测和库存优化
- 推荐系统: 个性化推荐算法评估
- 市场细分: 客户群体分析和画像
🎓 科研教育领域
- 学术研究: 数据驱动的学术研究支持
- 教学案例: 数据分析教学和实践
- 论文写作: 研究数据分析和图表制作
- 技能培训: 数据科学技能培训工具
工具使用指南
快速开始
1. 基础数据探索
from scripts.eda_analyzer import EDAAnalyzer
# 初始化分析器
analyzer = EDAAnalyzer()
# 加载数据并自动分析
data = analyzer.load_data('data.csv')
report = analyzer.auto_eda(data)2. 可视化生成
from scripts.visualizer import DataVisualizer
# 初始化可视化器
visualizer = DataVisualizer()
# 自动生成所有图表
charts = visualizer.auto_visualize(data)
# 生成特定类型图表
dist_plot = visualizer.plot_distribution(data, 'column_name')
corr_heatmap = visualizer.plot_correlation(data)3. 建模评估
from scripts.modeling_evaluator import ModelingEvaluator
# 初始化建模器
modeler = ModelingEvaluator()
# 自动建模和评估
results = modeler.auto_modeling(
data=data,
target_col='target',
algorithms=['logistic', 'rf', 'xgboost']
)4. 报告生成
from scripts.report_generator import ReportGenerator
# 生成完整报告
generator = ReportGenerator()
report = generator.generate_comprehensive_report(
data=data,
model_results=model_results,
output_path='analysis_report.html'
)高级功能
1. 医疗数据分析
# 医疗数据特殊处理
from scripts.medical_analyzer import MedicalDataAnalyzer
medical_analyzer = MedicalDataAnalyzer()
medical_report = medical_analyzer.analyze_medical_data(
data=medical_df,
diagnosis_col='diagnosis',
biomarker_cols=['biomarker1', 'biomarker2']
)2. 交互式仪表板
# 生成交互式仪表板
dashboard = visualizer.create_dashboard(
data=data,
charts=['distribution', 'correlation', 'model_performance']
)3. 批量数据处理
# 批量分析多个数据集
batch_results = analyzer.batch_analyze(
data_files=['data1.csv', 'data2.csv'],
analysis_types=['eda', 'modeling', 'visualization']
)技术依赖
核心库
- pandas (>=1.3.0): 数据处理和分析
- numpy (>=1.20.0): 数值计算
- scikit-learn (>=1.0.0): 机器学习算法
- xgboost (>=1.5.0): 梯度提升算法
可视化库
- matplotlib (>=3.4.0): 基础绘图
- seaborn (>=0.11.0): 统计可视化
- plotly (>=5.0.0): 交互式图表
统计分析库
- scipy (>=1.7.0): 科学计算
- statsmodels (>=0.13.0): 统计建模
报告生成
- jinja2 (>=3.0.0): 模板引擎
- weasyprint: PDF生成
最佳实践
数据准备
- 确保数据格式规范(CSV、Excel等)
- 检查数据编码,避免中文乱码
- 处理缺失值和异常值
- 验证数据类型和格式
分析流程
1. 数据加载和检查: 确认数据质量和完整性 2. 探索性分析: 了解数据基本特征和分布 3. 可视化探索: 通过图表发现数据模式 4. 预处理: 数据清洗和特征工程 5. 建模分析: 构建和评估预测模型 6. 结果解释: 提取洞察和业务建议 7. 报告生成: 创建专业分析报告
可视化选择
- 单变量分析: 直方图、箱线图、小提琴图
- 双变量分析: 散点图、分组箱线图
- 多变量分析: 热图、配对图、3D图
- 时间序列: 时间线图、趋势图
- 地理数据: 地图可视化
示例数据
医疗数据示例
# 乳腺检查数据示例
medical_data = {
'patient_id': ['P001', 'P002', ...],
'diagnosis': ['Malignant', 'Benign', ...],
'radius_mean': [17.99, 20.57, ...],
'texture_mean': [10.38, 17.77, ...],
'perimeter_mean': [122.8, 132.9, ...]
}金融数据示例
# 信用评分数据示例
financial_data = {
'customer_id': ['C001', 'C002', ...],
'credit_score': [720, 680, ...],
'income': [85000, 62000, ...],
'debt_ratio': [0.15, 0.32, ...],
'default': [0, 1, ...]
}常见问题
Q: 如何处理中文数据?
A: 技能自动检测和处理中文编码,支持UTF-8、GBK等多种编码格式。
Q: 支持哪些数据格式?
A: 支持CSV、Excel、JSON、Parquet等常见格式,也支持数据库连接。
Q: 如何自定义可视化样式?
A: 可以通过配置文件自定义颜色、字体、图表布局等样式参数。
Q: 模型准确性如何保证?
A: 技能采用交叉验证、多种评估指标和集成方法来确保模型的可靠性和泛化能力。
技能特色
✅ 智能化程度高 - 90%的EDA工作自动化 ✅ 专业性突出 - 医疗数据专精处理 ✅ 可视化丰富 - 20+种专业图表类型 ✅ 建模能力强 - 多算法集成和自动调优 ✅ 报告质量高 - 可发表级分析报告 ✅ 易用性好 - 简单API,复杂流程自动化 ✅ 扩展性强 - 模块化设计,易于定制扩展
更新日志
v1.0.0 (2025-01-19)
- 初始版本发布
- 完整的EDA功能
- 基础可视化支持
- 逻辑回归建模
- HTML报告生成
未来计划
- 支持更多机器学习算法
- 增加深度学习模型支持
- 扩展医疗数据分析功能
- 云端部署支持
- 实时数据分析能力
通过这个技能,您可以大幅提升数据分析效率,从重复性工作中解放出来,专注于洞察发现和决策支持。
#!/usr/bin/env python3
"""
金融数据分析示例
演示如何使用数据探索可视化技能进行金融数据分析
"""
import sys
import os
import pandas as pd
import numpy as np
from pathlib import Path
# 添加技能路径
skill_path = Path(__file__).parent.parent
sys.path.append(str(skill_path / "scripts"))
def create_financial_sample_data():
"""创建金融数据样本"""
print("💰 创建金融数据样本...")
np.random.seed(123)
n_customers = 1000
# 基础客户信息
data = {
'customer_id': [f'C{i:06d}' for i in range(1, n_customers + 1)],
'age': np.random.randint(18, 80, n_customers),
'gender': np.random.choice(['男', '女'], n_customers, p=[0.52, 0.48]),
'income': np.random.lognormal(10.5, 0.5, n_customers), # 收入分布
'credit_score': np.random.normal(650, 100, n_customers),
'employment_years': np.random.exponential(5, n_customers),
'home_ownership': np.random.choice(['租房', '按揭', '自有'], n_customers, p=[0.35, 0.45, 0.20]),
'marital_status': np.random.choice(['单身', '已婚', '离异'], n_customers, p=[0.3, 0.6, 0.1]),
'education_level': np.random.choice(['高中', '本科', '硕士', '博士'], n_customers, p=[0.3, 0.4, 0.25, 0.05]),
'debt_to_income_ratio': np.random.beta(2, 5, n_customers), # 负债收入比
'savings_amount': np.random.exponential(10000, n_customers),
'credit_cards_count': np.random.poisson(2, n_customers),
'late_payments_last_year': np.random.poisson(1, n_customers),
'bankruptcy_history': np.random.choice([0, 1], n_customers, p=[0.95, 0.05]),
'loan_amount': np.random.lognormal(9, 1, n_customers),
'loan_purpose': np.random.choice(
['购房', '购车', '教育', '装修', '债务整合', '其他'],
n_customers, p=[0.25, 0.2, 0.15, 0.15, 0.15, 0.1]
),
'loan_term_months': np.random.choice([12, 24, 36, 48, 60], n_customers, p=[0.1, 0.2, 0.3, 0.25, 0.15]),
'interest_rate': np.random.uniform(3.5, 15.0, n_customers),
}
# 创建相关性
df = pd.DataFrame(data)
# 收入与信用分数的相关性
df['credit_score'] = np.clip(
df['credit_score'] + (df['income'] - df['income'].mean()) / df['income'].std() * 20,
300, 850
)
# 年龄与工作年限的相关性
df['employment_years'] = np.minimum(df['employment_years'], df['age'] - 18)
# 收入与贷款金额的相关性
df['loan_amount'] = df['loan_amount'] * (0.5 + 0.5 * df['income'] / df['income'].mean())
# 负债收入比与利率的相关性
df['interest_rate'] = df['interest_rate'] + df['debt_to_income_ratio'] * 5
# 信用评分与利率的相关性(负相关)
df['interest_rate'] = df['interest_rate'] - (df['credit_score'] - 650) / 100
# 计算违约概率(目标变量)
default_probability = (
(df['credit_score'] < 600) * 0.4 +
(df['debt_to_income_ratio'] > 0.4) * 0.3 +
(df['late_payments_last_year'] > 3) * 0.2 +
(df['bankruptcy_history'] == 1) * 0.3 +
(df['employment_years'] < 1) * 0.2 +
(df['income'] < 30000) * 0.15 +
np.random.normal(0, 0.1, n_customers)
)
# 转换为二分类
df['loan_default'] = (default_probability > 0.3).astype(int)
# 风险等级
risk_conditions = [
df['credit_score'] >= 750,
(df['credit_score'] >= 700) & (df['credit_score'] < 750),
(df['credit_score'] >= 650) & (df['credit_score'] < 700),
(df['credit_score'] >= 600) & (df['credit_score'] < 650),
df['credit_score'] < 600
]
risk_labels = ['AAA', 'AA', 'A', 'BBB', 'BB']
df['risk_rating'] = np.select(risk_conditions, risk_labels, default='BB')
# 添加一些缺失值
missing_indices = np.random.choice(df.index, size=int(0.08 * len(df)), replace=False)
df.loc[missing_indices, 'savings_amount'] = np.nan
missing_indices = np.random.choice(df.index, size=int(0.05 * len(df)), replace=False)
df.loc[missing_indices, 'employment_years'] = np.nan
# 保存数据
output_dir = Path(__file__).parent / "data"
output_dir.mkdir(exist_ok=True)
data_path = output_dir / "financial_data_sample.csv"
df.to_csv(data_path, index=False, encoding='utf-8-sig')
print(f" ✓ 金融数据样本已保存: {data_path}")
print(f" ✓ 数据形状: {df.shape}")
print(f" ✓ 违约率: {df['loan_default'].mean():.2%}")
print(f" ✓ 平均信用分数: {df['credit_score'].mean():.1f}")
return df, data_path
def run_financial_eda_analysis(data_path):
"""运行金融数据EDA分析"""
print("\n🔍 运行金融数据探索性分析...")
try:
from eda_analyzer import EDAAnalyzer
analyzer = EDAAnalyzer()
# 加载数据
print(" 加载数据...")
data = analyzer.load_data(data_path)
# 自动化EDA分析
print(" 执行自动化EDA分析...")
eda_results = analyzer.auto_eda(data)
# 保存EDA结果
output_dir = Path(__file__).parent / "results"
output_dir.mkdir(exist_ok=True)
eda_path = output_dir / "financial_eda_results.json"
analyzer.export_results(eda_results, eda_path)
print(f" ✓ EDA分析完成,结果已保存: {eda_path}")
# 显示关键发现
print("\n📊 关键发现:")
if 'insights' in eda_results:
for insight in eda_results['insights'][:3]:
print(f" - {insight}")
return eda_results, data
except Exception as e:
print(f" ❌ EDA分析失败: {str(e)}")
return None, None
def run_financial_visualization(data):
"""运行金融数据可视化"""
print("\n📈 生成金融数据可视化图表...")
try:
from visualizer import DataVisualizer
visualizer = DataVisualizer()
# 自动可视化
charts = visualizer.auto_visualize(
data,
target_col='loan_default',
save_charts=True,
output_dir=str(Path(__file__).parent / "results" / "charts")
)
print(f" ✓ 可视化完成,生成了 {charts['charts_generated']} 个图表")
# 生成金融专项图表
financial_charts = {}
# 1. 信用分数分布
fig = visualizer.plot_distribution(
data, 'credit_score',
interactive=True
)
financial_charts['credit_score_distribution'] = fig
# 2. 收入 vs 贷款金额
fig = visualizer.plot_scatter(
data, 'income', 'loan_amount',
color_col='loan_default',
interactive=True
)
financial_charts['income_loan_scatter'] = fig
# 3. 风险等级分布
fig = visualizer.plot_categorical(
data, 'risk_rating',
interactive=True
)
financial_charts['risk_rating_distribution'] = fig
# 4. 违约率 vs 特征分析
default_by_purpose = data.groupby('loan_purpose')['loan_default'].mean().sort_values()
fig = visualizer.plot_categorical(
data, 'loan_purpose',
interactive=True
)
financial_charts['default_by_purpose'] = fig
print(f" ✓ 金融专项图表生成完成: {len(financial_charts)} 个")
return financial_charts
except Exception as e:
print(f" ❌ 可视化生成失败: {str(e)}")
return None
def run_financial_modeling(data, data_path):
"""运行金融数据建模"""
print("\n🤖 运行金融数据建模...")
try:
from data_preprocessor import DataPreprocessor
from modeling_evaluator import ModelingEvaluator
# 数据预处理
print(" 数据预处理...")
preprocessor = DataPreprocessor({
'missing_threshold': 0.2,
'feature_selection': True,
'k_features': 15,
'balance_data': True, # 平衡违约样本
'balance_method': 'smote'
})
# 预处理数据
preprocessing_results = preprocessor.auto_preprocess(
data,
target_col='loan_default',
save_report=True
)
# 模型训练
print(" 模型训练...")
modeler = ModelingEvaluator({
'cv_folds': 5,
'enable_hyperparameter_tuning': True,
'n_iter_search': 15, # 减少搜索次数加快演示
'scoring_metric': 'roc_auc' # 使用ROC AUC作为评估指标
})
# 自动建模
model_results = modeler.auto_modeling(
data,
target_col='loan_default',
model_names=['logistic_regression', 'random_forest', 'xgboost', 'lightgbm']
)
print(f" ✓ 模型训练完成,最佳模型: {model_results['best_model']['name']}")
# 保存模型
output_dir = Path(__file__).parent / "results" / "models"
modeler.save_models(str(output_dir))
return preprocessing_results, model_results
except Exception as e:
print(f" ❌ 建模失败: {str(e)}")
return None, None
def calculate_credit_risk_score(data, model_results):
"""计算综合信用风险评分"""
print("\n📊 计算综合信用风险评分...")
try:
# 基于模型结果计算风险评分
if model_results and 'best_model' in model_results:
best_model_name = model_results['best_model']['name']
print(f" 使用模型: {best_model_name}")
# 创建风险评分表
risk_scores = []
for _, row in data.iterrows():
# 基础信用分数
base_score = row['credit_score']
# 调整因子
adjustments = 0
# 收入调整
if row['income'] > 100000:
adjustments += 20
elif row['income'] < 30000:
adjustments -= 30
# 负债收入比调整
if row['debt_to_income_ratio'] > 0.4:
adjustments -= 40
elif row['debt_to_income_ratio'] < 0.2:
adjustments += 15
# 逾期记录调整
if row['late_payments_last_year'] > 2:
adjustments -= 25
# 破产历史调整
if row['bankruptcy_history'] == 1:
adjustments -= 100
# 就业稳定性调整
if row['employment_years'] > 5:
adjustments += 10
elif row['employment_years'] < 1:
adjustments -= 20
final_score = base_score + adjustments
final_score = np.clip(final_score, 300, 850)
risk_scores.append(final_score)
# 添加到数据中
data = data.copy()
data['comprehensive_risk_score'] = risk_scores
# 风险等级
score_conditions = [
data['comprehensive_risk_score'] >= 780,
(data['comprehensive_risk_score'] >= 740) & (data['comprehensive_risk_score'] < 780),
(data['comprehensive_risk_score'] >= 700) & (data['comprehensive_risk_score'] < 740),
(data['comprehensive_risk_score'] >= 660) & (data['comprehensive_risk_score'] < 700),
(data['comprehensive_risk_score'] >= 620) & (data['comprehensive_risk_score'] < 660),
data['comprehensive_risk_score'] < 620
]
risk_labels = ['AA+', 'AA', 'A', 'BBB', 'BB', 'B']
data['final_risk_rating'] = np.select(score_conditions, risk_labels, default='B')
print(f" ✓ 风险评分计算完成")
print(f" ✓ 平均风险评分: {data['comprehensive_risk_score'].mean():.1f}")
# 保存风险评分结果
output_dir = Path(__file__).parent / "results"
data.to_csv(output_dir / "credit_risk_scores.csv", index=False, encoding='utf-8-sig')
return data
else:
print(" ⚠️ 无法计算风险评分,缺少模型结果")
return data
except Exception as e:
print(f" ❌ 风险评分计算失败: {str(e)}")
return data
def generate_financial_report(data, eda_results, model_results):
"""生成金融数据分析报告"""
print("\n📋 生成金融数据分析报告...")
try:
from report_generator import ReportGenerator
# 配置金融特化报告
generator = ReportGenerator({
'report_title': '金融信贷风险分析报告',
'author': '金融风险分析助手',
'company': '金融机构',
'include_recommendations': True
})
# 生成报告
output_dir = Path(__file__).parent / "results"
output_path = output_dir / "financial_analysis_report.html"
report_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path=str(output_path),
format="html"
)
print(f" ✓ 金融分析报告已生成: {report_path}")
# 生成快速报告
quick_report_path = output_dir / "financial_quick_report.html"
generator.generate_quick_report(
data=data,
target_col='loan_default',
output_path=str(quick_report_path)
)
print(f" ✓ 快速报告已生成: {quick_report_path}")
return report_path
except Exception as e:
print(f" ❌ 报告生成失败: {str(e)}")
return None
def main():
"""主函数"""
print("💰 金融数据分析示例")
print("=" * 50)
# 创建输出目录
output_dir = Path(__file__).parent / "results"
output_dir.mkdir(exist_ok=True)
# 1. 创建样本数据
data, data_path = create_financial_sample_data()
# 2. EDA分析
eda_results, processed_data = run_financial_eda_analysis(data_path)
if processed_data is None:
processed_data = data
# 3. 可视化
charts = run_financial_visualization(processed_data)
# 4. 建模
preprocessing_results, model_results = run_financial_modeling(processed_data, data_path)
# 5. 计算风险评分
scored_data = calculate_credit_risk_score(processed_data, model_results)
# 6. 生成报告
report_path = generate_financial_report(scored_data, eda_results, model_results)
# 7. 总结
print("\n🎉 金融数据分析完成!")
print("\n📁 生成的文件:")
results_dir = Path(__file__).parent / "results"
if results_dir.exists():
for file_path in results_dir.rglob("*"):
if file_path.is_file():
relative_path = file_path.relative_to(results_dir)
print(f" 📄 {relative_path}")
print(f"\n📊 主要发现:")
if eda_results and 'data_quality' in eda_results:
print(f" - 数据质量分数: {eda_results['data_quality'].get('overall_score', 'N/A')}")
if model_results and 'best_model' in model_results:
best_model = model_results['best_model']
if best_model and 'metrics' in best_model:
auc = best_model['metrics'].get('auc', 0)
print(f" - 最佳模型AUC: {auc:.3f}")
default_rate = processed_data['loan_default'].mean()
print(f" - 整体违约率: {default_rate:.2%}")
avg_credit_score = processed_data['credit_score'].mean()
print(f" - 平均信用分数: {avg_credit_score:.1f}")
if 'comprehensive_risk_score' in scored_data.columns:
avg_risk_score = scored_data['comprehensive_risk_score'].mean()
print(f" - 综合风险评分: {avg_risk_score:.1f}")
if report_path:
print(f"\n📋 详细分析报告: {report_path}")
print(" 请在浏览器中打开HTML文件查看完整的交互式报告。")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
医疗数据分析示例
演示如何使用数据探索可视化技能进行医疗数据分析
"""
import sys
import os
import pandas as pd
import numpy as np
from pathlib import Path
# 添加技能路径
skill_path = Path(__file__).parent.parent
sys.path.append(str(skill_path / "scripts"))
def create_medical_sample_data():
"""创建医疗数据样本"""
print("🏥 创建医疗数据样本...")
np.random.seed(42)
n_patients = 500
# 基础患者信息
data = {
'patient_id': [f'P{i:04d}' for i in range(1, n_patients + 1)],
'age': np.random.randint(18, 85, n_patients),
'gender': np.random.choice(['男', '女'], n_patients, p=[0.48, 0.52]),
'blood_type': np.random.choice(['A', 'B', 'AB', 'O'], n_patients, p=[0.3, 0.25, 0.1, 0.35]),
'blood_pressure_systolic': np.random.normal(120, 15, n_patients),
'blood_pressure_diastolic': np.random.normal(80, 10, n_patients),
'heart_rate': np.random.normal(75, 10, n_patients),
'cholesterol': np.random.normal(200, 40, n_patients),
'glucose': np.random.normal(100, 25, n_patients),
'bmi': np.random.normal(25, 5, n_patients),
'smoking_status': np.random.choice(['从不', '曾经', '现在'], n_patients, p=[0.4, 0.3, 0.3]),
'alcohol_consumption': np.random.choice(['无', '偶尔', '经常'], n_patients, p=[0.3, 0.5, 0.2]),
'exercise_frequency': np.random.choice(['从不', '偶尔', '经常'], n_patients, p=[0.2, 0.4, 0.4]),
'family_history': np.random.choice([0, 1], n_patients, p=[0.7, 0.3]),
'medications_count': np.random.randint(0, 8, n_patients),
'doctor_visits_last_year': np.random.randint(0, 15, n_patients),
}
# 创建相关性:年龄和某些健康指标的关系
data['cholesterol'] += np.random.normal(0, data['age'] * 0.5, n_patients)
data['blood_pressure_systolic'] += np.random.normal(0, data['age'] * 0.3, n_patients)
# BMI计算
data['bmi'] = np.maximum(15, data['bmi']) # 确保BMI合理
# 诊断结果(二分类:0=健康,1=有疾病风险)
risk_score = (
(data['age'] > 60) * 0.3 +
(data['cholesterol'] > 240) * 0.2 +
(data['blood_pressure_systolic'] > 140) * 0.2 +
(data['bmi'] > 30) * 0.15 +
(data['family_history']) * 0.1 +
(data['smoking_status'] == '现在') * 0.15 +
(data['alcohol_consumption'] == '经常') * 0.1
)
# 添加噪声并转换为二分类
risk_score += np.random.normal(0, 0.1, n_patients)
data['disease_risk'] = (risk_score > 0.4).astype(int)
# 疾病类型(针对有风险的患者)
disease_types = ['无', '高血压', '糖尿病', '心脏病', '综合风险']
data['disease_type'] = '无'
risk_mask = data['disease_risk'] == 1
data.loc[risk_mask, 'disease_type'] = np.random.choice(
['高血压', '糖尿病', '心脏病', '综合风险'],
risk_mask.sum(),
p=[0.35, 0.25, 0.25, 0.15]
)
# 创建DataFrame
df = pd.DataFrame(data)
# 添加一些缺失值模拟真实数据
missing_indices = np.random.choice(df.index, size=int(0.05 * len(df)), replace=False)
df.loc[missing_indices, 'cholesterol'] = np.nan
missing_indices = np.random.choice(df.index, size=int(0.03 * len(df)), replace=False)
df.loc[missing_indices, 'glucose'] = np.nan
# 保存数据
output_dir = Path(__file__).parent / "data"
output_dir.mkdir(exist_ok=True)
data_path = output_dir / "medical_data_sample.csv"
df.to_csv(data_path, index=False, encoding='utf-8-sig')
print(f" ✓ 医疗数据样本已保存: {data_path}")
print(f" ✓ 数据形状: {df.shape}")
print(f" ✓ 疾病风险分布: {df['disease_risk'].value_counts().to_dict()}")
return df, data_path
def run_medical_eda_analysis(data_path):
"""运行医疗数据EDA分析"""
print("\n🔍 运行医疗数据探索性分析...")
try:
from eda_analyzer import EDAAnalyzer
analyzer = EDAAnalyzer()
# 加载数据
print(" 加载数据...")
data = analyzer.load_data(data_path)
# 自动化EDA分析
print(" 执行自动化EDA分析...")
eda_results = analyzer.auto_eda(data)
# 保存EDA结果
output_dir = Path(__file__).parent / "results"
output_dir.mkdir(exist_ok=True)
eda_path = output_dir / "medical_eda_results.json"
analyzer.export_results(eda_results, eda_path)
print(f" ✓ EDA分析完成,结果已保存: {eda_path}")
# 显示关键发现
print("\n📊 关键发现:")
if 'insights' in eda_results:
for insight in eda_results['insights'][:3]:
print(f" - {insight}")
return eda_results, data
except Exception as e:
print(f" ❌ EDA分析失败: {str(e)}")
return None, None
def run_medical_visualization(data):
"""运行医疗数据可视化"""
print("\n📈 生成医疗数据可视化图表...")
try:
from visualizer import DataVisualizer
visualizer = DataVisualizer()
# 自动可视化
charts = visualizer.auto_visualize(
data,
target_col='disease_risk',
save_charts=True,
output_dir=str(Path(__file__).parent / "results" / "charts")
)
print(f" ✓ 可视化完成,生成了 {charts['charts_generated']} 个图表")
# 生成医疗专项图表
medical_charts = {}
# 1. 年龄分布 vs 疾病风险
fig = visualizer.plot_distribution(
data[data['disease_risk'] == 1],
'age',
interactive=True
)
medical_charts['high_risk_age_distribution'] = fig
# 2. BMI vs 疾病风险散点图
fig = visualizer.plot_scatter(
data, 'age', 'bmi',
color_col='disease_risk',
interactive=True
)
medical_charts['age_bmi_risk_scatter'] = fig
# 3. 疾病类型分布
disease_counts = data['disease_type'].value_counts()
fig = visualizer.plot_categorical(
data, 'disease_type',
interactive=True
)
medical_charts['disease_type_distribution'] = fig
print(f" ✓ 医疗专项图表生成完成: {len(medical_charts)} 个")
return medical_charts
except Exception as e:
print(f" ❌ 可视化生成失败: {str(e)}")
return None
def run_medical_modeling(data, data_path):
"""运行医疗数据建模"""
print("\n🤖 运行医疗数据建模...")
try:
from data_preprocessor import DataPreprocessor
from modeling_evaluator import ModelingEvaluator
# 数据预处理
print(" 数据预处理...")
preprocessor = DataPreprocessor({
'missing_threshold': 0.3,
'feature_selection': True,
'k_features': 10
})
# 预处理数据
preprocessing_results = preprocessor.auto_preprocess(
data,
target_col='disease_risk',
save_report=True
)
# 模型训练
print(" 模型训练...")
modeler = ModelingEvaluator({
'cv_folds': 5,
'enable_hyperparameter_tuning': True,
'n_iter_search': 20 # 减少搜索次数加快演示
})
# 自动建模
model_results = modeler.auto_modeling(
data,
target_col='disease_risk',
model_names=['logistic_regression', 'random_forest', 'xgboost']
)
print(f" ✓ 模型训练完成,最佳模型: {model_results['best_model']['name']}")
# 保存模型
output_dir = Path(__file__).parent / "results" / "models"
modeler.save_models(str(output_dir))
return preprocessing_results, model_results
except Exception as e:
print(f" ❌ 建模失败: {str(e)}")
return None, None
def generate_medical_report(data, eda_results, model_results):
"""生成医疗数据分析报告"""
print("\n📋 生成医疗数据分析报告...")
try:
from report_generator import ReportGenerator
# 配置医疗特化报告
generator = ReportGenerator({
'report_title': '医疗数据分析报告',
'author': '医疗数据分析助手',
'company': '医疗机构',
'medical_specialization': True
})
# 生成报告
output_dir = Path(__file__).parent / "results"
output_path = output_dir / "medical_analysis_report.html"
report_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path=str(output_path),
format="html"
)
print(f" ✓ 医疗分析报告已生成: {report_path}")
# 生成快速报告
quick_report_path = output_dir / "medical_quick_report.html"
generator.generate_quick_report(
data=data,
target_col='disease_risk',
output_path=str(quick_report_path)
)
print(f" ✓ 快速报告已生成: {quick_report_path}")
return report_path
except Exception as e:
print(f" ❌ 报告生成失败: {str(e)}")
return None
def main():
"""主函数"""
print("🏥 医疗数据分析示例")
print("=" * 50)
# 创建输出目录
output_dir = Path(__file__).parent / "results"
output_dir.mkdir(exist_ok=True)
# 1. 创建样本数据
data, data_path = create_medical_sample_data()
# 2. EDA分析
eda_results, processed_data = run_medical_eda_analysis(data_path)
if processed_data is None:
processed_data = data
# 3. 可视化
charts = run_medical_visualization(processed_data)
# 4. 建模
preprocessing_results, model_results = run_medical_modeling(processed_data, data_path)
# 5. 生成报告
report_path = generate_medical_report(processed_data, eda_results, model_results)
# 6. 总结
print("\n🎉 医疗数据分析完成!")
print("\n📁 生成的文件:")
results_dir = Path(__file__).parent / "results"
if results_dir.exists():
for file_path in results_dir.rglob("*"):
if file_path.is_file():
relative_path = file_path.relative_to(results_dir)
print(f" 📄 {relative_path}")
print(f"\n📊 主要发现:")
if eda_results and 'data_quality' in eda_results:
print(f" - 数据质量分数: {eda_results['data_quality'].get('overall_score', 'N/A')}")
if model_results and 'best_model' in model_results:
best_model = model_results['best_model']
if best_model and 'metrics' in best_model:
accuracy = best_model['metrics'].get('accuracy', 0)
print(f" - 最佳模型准确率: {accuracy:.3f}")
disease_risk_counts = processed_data['disease_risk'].value_counts()
print(f" - 高风险患者比例: {disease_risk_counts.get(1, 0) / len(processed_data) * 100:.1f}%")
if report_path:
print(f"\n📋 详细分析报告: {report_path}")
print(" 请在浏览器中打开HTML文件查看完整的交互式报告。")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
快速开始示例
演示如何快速使用数据探索可视化技能进行数据分析
"""
import sys
import os
import pandas as pd
import numpy as np
from pathlib import Path
# 添加技能路径
skill_path = Path(__file__).parent.parent
sys.path.append(str(skill_path / "scripts"))
def create_sample_data():
"""创建示例数据集"""
print("📊 创建示例数据集...")
np.random.seed(42)
n_samples = 800
data = {
'id': range(1, n_samples + 1),
'age': np.random.randint(18, 75, n_samples),
'gender': np.random.choice(['Male', 'Female'], n_samples, p=[0.52, 0.48]),
'income': np.random.lognormal(10.5, 0.6, n_samples),
'education': np.random.choice(['High School', 'Bachelor', 'Master', 'PhD'],
n_samples, p=[0.3, 0.4, 0.25, 0.05]),
'experience_years': np.random.exponential(8, n_samples),
'satisfaction': np.random.randint(1, 6, n_samples),
'performance_score': np.random.normal(75, 15, n_samples),
'team_size': np.random.randint(2, 15, n_samples),
'hours_per_week': np.random.normal(40, 5, n_samples),
'projects_completed': np.random.poisson(8, n_samples),
'training_hours': np.random.randint(0, 100, n_samples),
'salary': np.random.lognormal(10.8, 0.4, n_samples),
}
# 创建相关性
df = pd.DataFrame(data)
# 经验与薪资的相关性
df['salary'] = df['salary'] * (0.7 + 0.3 * df['experience_years'] / df['experience_years'].max())
# 绩效与满意度相关性
df['performance_score'] = df['performance_score'] + df['satisfaction'] * 3
# 项目完成数量与经验相关性
df['projects_completed'] = df['projects_completed'] + (df['experience_years'] / 2).astype(int)
# 创建目标变量:高绩效员工(绩效分数 > 85)
df['high_performer'] = (df['performance_score'] > 85).astype(int)
# 添加一些缺失值
missing_indices = np.random.choice(df.index, size=int(0.05 * len(df)), replace=False)
df.loc[missing_indices, 'training_hours'] = np.nan
print(f" ✓ 数据集创建完成: {df.shape}")
print(f" ✓ 高绩效员工比例: {df['high_performer'].mean():.2%}")
return df
def quick_eda_example():
"""快速EDA示例"""
print("\n🔍 快速EDA分析示例...")
# 创建数据
data = create_sample_data()
try:
from eda_analyzer import EDAAnalyzer
# 初始化分析器
analyzer = EDAAnalyzer()
# 自动化EDA分析
print(" 执行自动化EDA...")
results = analyzer.auto_eda(data)
print(f" ✓ EDA分析完成")
print(f" - 数据质量分数: {results.get('data_quality', {}).get('overall_score', 'N/A')}")
print(f" - 发现的洞察: {len(results.get('insights', []))}")
# 显示前3个洞察
insights = results.get('insights', [])[:3]
for i, insight in enumerate(insights, 1):
print(f" {i}. {insight}")
return data, results
except Exception as e:
print(f" ❌ EDA分析失败: {str(e)}")
return data, None
def quick_visualization_example(data):
"""快速可视化示例"""
print("\n📈 快速可视化示例...")
try:
from visualizer import DataVisualizer
# 初始化可视化器
visualizer = DataVisualizer()
# 自动生成图表
print(" 自动生成可视化图表...")
charts = visualizer.auto_visualize(
data,
target_col='high_performer',
save_charts=True,
output_dir='quick_start_charts'
)
print(f" ✓ 生成了 {charts['charts_generated']} 个图表")
# 生成特定图表
print(" 生成特定图表...")
# 1. 年龄分布
age_chart = visualizer.plot_distribution(data, 'age', interactive=False)
print(" ✓ 年龄分布图")
# 2. 薪资 vs 经验散点图
scatter_chart = visualizer.plot_scatter(
data, 'experience_years', 'salary',
color_col='high_performer',
interactive=False
)
print(" ✓ 薪资-经验散点图")
# 3. 教育水平分布
education_chart = visualizer.plot_categorical(data, 'education', interactive=False)
print(" ✓ 教育水平分布图")
return charts
except Exception as e:
print(f" ❌ 可视化失败: {str(e)}")
return None
def quick_preprocessing_example(data):
"""快速数据预处理示例"""
print("\n🧹 快速数据预处理示例...")
try:
from data_preprocessor import DataPreprocessor
# 初始化预处理器
preprocessor = DataPreprocessor({
'missing_threshold': 0.3,
'feature_selection': False, # 关闭特征选择以加快演示
'test_size': 0.2
})
# 自动预处理
print(" 执行自动预处理...")
results = preprocessor.auto_preprocess(
data,
target_col='high_performer',
save_report=True
)
print(f" ✓ 预处理完成")
print(f" - 原始数据: {results['original_data'].shape}")
print(f" - 预处理后: {results['preprocessed_data'].shape}")
print(f" - 预处理步骤: {len(results['preprocessing_steps'])}")
# 显示预处理步骤
for step in results['preprocessing_steps'][:5]:
print(f" - {step}")
return results
except Exception as e:
print(f" ❌ 预处理失败: {str(e)}")
return None
def quick_modeling_example(data):
"""快速建模示例"""
print("\n🤖 快速建模示例...")
try:
from modeling_evaluator import ModelingEvaluator
# 初始化建模器
modeler = ModelingEvaluator({
'cv_folds': 3, # 减少折数加快演示
'enable_hyperparameter_tuning': False, # 关闭调参加快演示
'n_iter_search': 5
})
# 自动建模
print(" 执行自动建模...")
results = modeler.auto_modeling(
data,
target_col='high_performer',
model_names=['logistic_regression', 'random_forest'] # 使用较少的模型
)
print(f" ✓ 建模完成")
print(f" - 训练模型数: {len(results['model_results'])}")
print(f" - 最佳模型: {results['best_model']['name']}")
best_metrics = results['best_model']['metrics']
print(f" - 最佳准确率: {best_metrics.get('accuracy', 0):.3f}")
return results
except Exception as e:
print(f" ❌ 建模失败: {str(e)}")
return None
def quick_report_example(data, eda_results=None, model_results=None):
"""快速报告生成示例"""
print("\n📋 快速报告生成示例...")
try:
from report_generator import ReportGenerator
# 初始化报告生成器
generator = ReportGenerator({
'report_title': '员工绩效分析报告',
'author': '数据分析助手',
'include_toc': True,
'include_summary': True
})
# 生成快速报告
print(" 生成快速分析报告...")
report_path = generator.generate_quick_report(
data=data,
target_col='high_performer',
output_path='quick_analysis_report.html'
)
print(f" ✓ 报告已生成: {report_path}")
# 如果有完整结果,生成综合报告
if eda_results or model_results:
print(" 生成综合分析报告...")
comprehensive_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path='comprehensive_analysis_report.html',
format='html'
)
print(f" ✓ 综合报告已生成: {comprehensive_path}")
return report_path
except Exception as e:
print(f" ❌ 报告生成失败: {str(e)}")
return None
def run_complete_pipeline():
"""运行完整分析流程"""
print("🚀 运行完整数据分析流程...")
# 创建输出目录
output_dir = Path('quick_start_output')
output_dir.mkdir(exist_ok=True)
# 1. 数据创建和EDA
data, eda_results = quick_eda_example()
# 2. 可视化
charts = quick_visualization_example(data)
# 3. 预处理
preprocessing_results = quick_preprocessing_example(data)
# 4. 建模
model_results = quick_modeling_example(data)
# 5. 报告生成
report_path = quick_report_example(data, eda_results, model_results)
# 6. 总结
print("\n🎉 快速开始示例完成!")
# 显示统计信息
print(f"\n📊 数据摘要:")
print(f" - 样本数量: {len(data):,}")
print(f" - 特征数量: {len(data.columns)}")
print(f" - 高绩效员工: {data['high_performer'].sum()} ({data['high_performer'].mean():.1%})")
print(f"\n📈 分析结果:")
if eda_results:
quality_score = eda_results.get('data_quality', {}).get('overall_score', 0)
print(f" - 数据质量分数: {quality_score:.1f}")
if model_results:
best_accuracy = model_results['best_model']['metrics'].get('accuracy', 0)
print(f" - 最佳模型准确率: {best_accuracy:.3f}")
if charts:
print(f" - 生成图表数: {charts['charts_generated']}")
# 显示生成的文件
print(f"\n📁 生成的文件:")
for file_path in Path('.').glob('quick_start_*'):
if file_path.is_file():
print(f" 📄 {file_path}")
if report_path:
print(f"\n📋 分析报告: {report_path}")
print(" 请在浏览器中打开HTML文件查看完整报告。")
def demonstrate_specific_features():
"""演示特定功能"""
print("\n🔧 演示特定功能...")
try:
# 1. 数据质量检查
from eda_analyzer import EDAAnalyzer
data = create_sample_data()
analyzer = EDAAnalyzer()
print(" 1. 数据质量检查...")
quality_report = analyzer.data_quality_check(data)
print(f" - 数据行数: {quality_report['total_rows']}")
print(f" - 数据列数: {quality_report['total_columns']}")
print(f" - 缺失值: {quality_report['missing_values']}")
# 2. 异常值检测
print("\n 2. 异常值检测...")
outliers = analyzer.detect_outliers(data, 'salary')
print(f" - 薪资异常值: {outliers.sum()} 个")
# 3. 相关性分析
print("\n 3. 相关性分析...")
correlation_matrix = analyzer.correlation_analysis(data)
strong_corr = []
for i in range(len(correlation_matrix.columns)):
for j in range(i+1, len(correlation_matrix.columns)):
corr_val = correlation_matrix.iloc[i, j]
if abs(corr_val) > 0.5:
strong_corr.append(
f"{correlation_matrix.columns[i]} - {correlation_matrix.columns[j]}: {corr_val:.2f}"
)
print(f" - 强相关性特征对: {len(strong_corr)}")
for corr in strong_corr[:3]:
print(f" • {corr}")
# 4. 特征重要性
if model_results := quick_modeling_example(data):
print("\n 4. 特征重要性分析...")
if 'feature_importance' in model_results:
top_features = list(model_results['feature_importance'].keys())[:5]
print(f" - 最重要的5个特征:")
for i, feature in enumerate(top_features, 1):
print(f" {i}. {feature}")
except Exception as e:
print(f" ❌ 功能演示失败: {str(e)}")
def main():
"""主函数"""
print("🎯 数据探索可视化技能 - 快速开始示例")
print("=" * 60)
try:
# 检查依赖
print("🔍 检查依赖包...")
required_packages = ['pandas', 'numpy', 'matplotlib', 'seaborn', 'scikit-learn']
missing_packages = []
for package in required_packages:
try:
__import__(package)
except ImportError:
missing_packages.append(package)
if missing_packages:
print(f" ❌ 缺少依赖包: {', '.join(missing_packages)}")
print(f" 请安装: pip install {' '.join(missing_packages)}")
return
print(" ✓ 所有依赖包已安装")
# 运行完整流程
run_complete_pipeline()
# 演示特定功能
demonstrate_specific_features()
# 使用建议
print("\n💡 使用建议:")
print(" 1. 将您自己的CSV数据替换示例数据")
print(" 2. 调整配置参数以适应您的需求")
print(" 3. 查看生成的HTML报告获取详细分析结果")
print(" 4. 尝试不同的模型和预处理方法")
print(" 5. 使用图表功能创建自定义可视化")
print("\n📚 更多示例:")
print(" - medical_data_analysis.py: 医疗数据分析示例")
print(" - financial_data_analysis.py: 金融数据分析示例")
except Exception as e:
print(f"\n❌ 示例运行失败: {str(e)}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
数据探索可视化技能快速测试
快速验证所有核心功能是否正常工作
"""
import sys
import os
import pandas as pd
import numpy as np
from pathlib import Path
import time
import traceback
# 添加技能路径
skill_path = Path(__file__).parent
sys.path.append(str(skill_path / "scripts"))
def create_test_data():
"""创建测试数据"""
print("📊 创建测试数据...")
np.random.seed(42)
n_samples = 200
data = {
'id': range(1, n_samples + 1),
'age': np.random.randint(18, 70, n_samples),
'gender': np.random.choice(['Male', 'Female'], n_samples),
'income': np.random.lognormal(10, 0.5, n_samples),
'score': np.random.normal(75, 15, n_samples),
'category': np.random.choice(['A', 'B', 'C'], n_samples, p=[0.5, 0.3, 0.2]),
'target': np.random.choice([0, 1], n_samples, p=[0.7, 0.3])
}
df = pd.DataFrame(data)
# 添加一些缺失值
missing_indices = np.random.choice(df.index, size=10, replace=False)
df.loc[missing_indices, 'income'] = np.nan
print(f" ✓ 测试数据创建完成: {df.shape}")
return df
def check_dependencies():
"""检查依赖包"""
print("🔍 检查依赖包...")
required_packages = {
'pandas': 'pandas',
'numpy': 'numpy',
'matplotlib': 'matplotlib',
'seaborn': 'seaborn',
'scipy': 'scipy',
'sklearn': 'scikit-learn',
'xgboost': 'xgboost',
'plotly': 'plotly',
'jinja2': 'jinja2'
}
optional_packages = {
'shap': 'shap',
'lightgbm': 'lightgbm',
'imblearn': 'imbalanced-learn',
'weasyprint': 'weasyprint'
}
missing_required = []
missing_optional = []
# 检查必需包
for module_name, package_name in required_packages.items():
try:
__import__(module_name)
except ImportError:
missing_required.append(package_name)
# 检查可选包
for module_name, package_name in optional_packages.items():
try:
__import__(module_name)
except ImportError:
missing_optional.append(package_name)
if missing_required:
print(" ❌ 缺少必需依赖包:")
for package in missing_required:
print(f" - {package}")
print(f"\n 请安装: pip install {' '.join(missing_required)}")
return False
if missing_optional:
print(" ⚠️ 缺少可选依赖包 (某些功能可能不可用):")
for package in missing_optional:
print(f" - {package}")
print(" ✓ 所有必要依赖包已安装")
return True
def test_eda_analyzer():
"""测试EDA分析器"""
print("\n🔍 测试EDA分析器...")
try:
from eda_analyzer import EDAAnalyzer
# 创建分析器
analyzer = EDAAnalyzer()
# 创建测试数据
data = create_test_data()
# 测试基本功能
print(" 测试数据质量检查...")
quality_report = analyzer.data_quality_check(data)
assert quality_report is not None, "数据质量检查失败"
print(" ✓ 数据质量检查")
print(" 测试统计摘要...")
stats_summary = analyzer.generate_statistical_summary(data)
assert stats_summary is not None, "统计摘要生成失败"
print(" ✓ 统计摘要生成")
print(" 测试相关性分析...")
corr_matrix = analyzer.correlation_analysis(data)
assert corr_matrix is not None, "相关性分析失败"
print(" ✓ 相关性分析")
print(" 测试自动EDA...")
eda_results = analyzer.auto_eda(data)
assert eda_results is not None, "自动EDA失败"
print(" ✓ 自动EDA分析")
print(" ✓ EDA分析器测试通过")
return True, eda_results
except Exception as e:
print(f" ❌ EDA分析器测试失败: {str(e)}")
traceback.print_exc()
return False, None
def test_visualizer():
"""测试可视化器"""
print("\n📈 测试可视化器...")
try:
from visualizer import DataVisualizer
# 创建可视化器
visualizer = DataVisualizer()
# 创建测试数据
data = create_test_data()
# 测试分布图
print(" 测试分布图...")
fig = visualizer.plot_distribution(data, 'age', interactive=False)
assert fig is not None, "分布图生成失败"
print(" ✓ 分布图生成")
# 测试相关性热图
print(" 测试相关性热图...")
numeric_cols = data.select_dtypes(include=[np.number]).columns.tolist()
if len(numeric_cols) > 1:
fig = visualizer.plot_correlation(data, numeric_cols, interactive=False)
assert fig is not None, "相关性热图生成失败"
print(" ✓ 相关性热图生成")
# 测试散点图
print(" 测试散点图...")
if len(numeric_cols) >= 2:
fig = visualizer.plot_scatter(data, numeric_cols[0], numeric_cols[1], interactive=False)
assert fig is not None, "散点图生成失败"
print(" ✓ 散点图生成")
# 测试自动可视化
print(" 测试自动可视化...")
charts = visualizer.auto_visualize(
data,
target_col='target',
save_charts=False
)
assert charts is not None, "自动可视化失败"
print(" ✓ 自动可视化")
print(" ✓ 可视化器测试通过")
return True
except Exception as e:
print(f" ❌ 可视化器测试失败: {str(e)}")
traceback.print_exc()
return False
def test_preprocessor():
"""测试数据预处理器"""
print("\n🧹 测试数据预处理器...")
try:
from data_preprocessor import DataPreprocessor
# 创建预处理器
preprocessor = DataPreprocessor({
'missing_threshold': 0.5,
'feature_selection': False, # 关闭特征选择加快测试
'test_size': 0.2
})
# 创建测试数据
data = create_test_data()
# 测试数据质量分析
print(" 测试数据质量分析...")
quality_report = preprocessor.analyze_data_quality(data)
assert quality_report is not None, "数据质量分析失败"
print(" ✓ 数据质量分析")
# 测试数据清洗
print(" 测试数据清洗...")
cleaned_data = preprocessor.clean_data(data)
assert cleaned_data is not None, "数据清洗失败"
print(" ✓ 数据清洗")
# 测试类型转换
print(" 测试类型转换...")
transformed_data = preprocessor.transform_data_types(cleaned_data)
assert transformed_data is not None, "类型转换失败"
print(" ✓ 类型转换")
# 测试自动预处理
print(" 测试自动预处理...")
results = preprocessor.auto_preprocess(data, target_col='target', save_report=False)
assert results is not None, "自动预处理失败"
assert 'preprocessed_data' in results, "预处理数据缺失"
print(" ✓ 自动预处理")
print(" ✓ 数据预处理器测试通过")
return True, results
except Exception as e:
print(f" ❌ 数据预处理器测试失败: {str(e)}")
traceback.print_exc()
return False, None
def test_modeling_evaluator():
"""测试建模评估器"""
print("\n🤖 测试建模评估器...")
try:
from modeling_evaluator import ModelingEvaluator
# 创建建模器
modeler = ModelingEvaluator({
'cv_folds': 3, # 减少折数加快测试
'enable_hyperparameter_tuning': False, # 关闭调加快测试
'n_iter_search': 5
})
# 创建测试数据
data = create_test_data()
# 测试单个模型训练
print(" 测试单个模型训练...")
# 准备数据
X = data[['age', 'income', 'score']]
y = data['target']
# 分割数据
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
result = modeler.train_single_model(
X_train, y_train, X_test, y_test,
'logistic_regression', tune_hyperparameters=False
)
assert result is not None, "单个模型训练失败"
print(" ✓ 单个模型训练")
# 测试多模型训练
print(" 测试多模型训练...")
results = modeler.train_multiple_models(
X_train, y_train, X_test, y_test,
model_names=['logistic_regression', 'random_forest']
)
assert results is not None, "多模型训练失败"
print(" ✓ 多模型训练")
# 测试自动建模
print(" 测试自动建模...")
modeling_results = modeler.auto_modeling(
data,
target_col='target',
model_names=['logistic_regression', 'random_forest']
)
assert modeling_results is not None, "自动建模失败"
print(" ✓ 自动建模")
print(" ✓ 建模评估器测试通过")
return True, modeling_results
except Exception as e:
print(f" ❌ 建模评估器测试失败: {str(e)}")
traceback.print_exc()
return False, None
def test_report_generator():
"""测试报告生成器"""
print("\n📋 测试报告生成器...")
try:
from report_generator import ReportGenerator
# 创建报告生成器
generator = ReportGenerator({
'report_title': '测试报告',
'author': '测试用户'
})
# 创建测试数据
data = create_test_data()
# 测试快速报告生成
print(" 测试快速报告生成...")
report_path = generator.generate_quick_report(
data=data,
target_col='target',
output_path='test_quick_report.html'
)
assert report_path is not None, "快速报告生成失败"
assert os.path.exists(report_path), "报告文件不存在"
print(" ✓ 快速报告生成")
# 测试综合报告生成
print(" 测试综合报告生成...")
# 创建模拟的EDA和建模结果
eda_results = {
'data_quality': {'overall_score': 85.5},
'insights': ['测试洞察1', '测试洞察2']
}
model_results = {
'best_model': {
'name': 'logistic_regression',
'metrics': {'accuracy': 0.85, 'precision': 0.82, 'recall': 0.88, 'f1': 0.85}
}
}
comprehensive_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path='test_comprehensive_report.html',
format='html'
)
assert comprehensive_path is not None, "综合报告生成失败"
assert os.path.exists(comprehensive_path), "综合报告文件不存在"
print(" ✓ 综合报告生成")
print(" ✓ 报告生成器测试通过")
return True
except Exception as e:
print(f" ❌ 报告生成器测试失败: {str(e)}")
traceback.print_exc()
return False
def test_integration():
"""集成测试"""
print("\n🔗 测试模块集成...")
try:
# 创建测试数据
data = create_test_data()
# 1. EDA分析
print(" 1. 执行EDA分析...")
from eda_analyzer import EDAAnalyzer
analyzer = EDAAnalyzer()
eda_results = analyzer.auto_eda(data)
# 2. 数据预处理
print(" 2. 执行数据预处理...")
from data_preprocessor import DataPreprocessor
preprocessor = DataPreprocessor()
preprocessing_results = preprocessor.auto_preprocess(data, target_col='target')
# 3. 可视化
print(" 3. 生成可视化...")
from visualizer import DataVisualizer
visualizer = DataVisualizer()
charts = visualizer.auto_visualize(data, target_col='target', save_charts=False)
# 4. 建模
print(" 4. 执行建模...")
from modeling_evaluator import ModelingEvaluator
modeler = ModelingEvaluator({'enable_hyperparameter_tuning': False})
model_results = modeler.auto_modeling(data, target_col='target', model_names=['logistic_regression'])
# 5. 报告生成
print(" 5. 生成报告...")
from report_generator import ReportGenerator
generator = ReportGenerator()
report_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path='test_integration_report.html'
)
# 验证所有步骤都成功
assert eda_results is not None, "EDA分析失败"
assert preprocessing_results is not None, "数据预处理失败"
assert charts is not None, "可视化失败"
assert model_results is not None, "建模失败"
assert report_path is not None and os.path.exists(report_path), "报告生成失败"
print(" ✓ 集成测试通过")
return True
except Exception as e:
print(f" ❌ 集成测试失败: {str(e)}")
traceback.print_exc()
return False
def test_performance():
"""性能测试"""
print("\n⚡ 性能测试...")
try:
import time
# 创建较大的测试数据
print(" 创建性能测试数据...")
n_samples = 1000
data = pd.DataFrame({
'feature_1': np.random.randn(n_samples),
'feature_2': np.random.randn(n_samples),
'feature_3': np.random.randn(n_samples),
'target': np.random.choice([0, 1], n_samples)
})
# 测试EDA性能
print(" 测试EDA性能...")
start_time = time.time()
from eda_analyzer import EDAAnalyzer
analyzer = EDAAnalyzer()
analyzer.auto_eda(data)
eda_time = time.time() - start_time
print(f" ✓ EDA耗时: {eda_time:.2f}秒")
# 测试建模性能
print(" 测试建模性能...")
start_time = time.time()
from modeling_evaluator import ModelingEvaluator
modeler = ModelingEvaluator({'enable_hyperparameter_tuning': False})
modeler.auto_modeling(data, target_col='target', model_names=['logistic_regression'])
modeling_time = time.time() - start_time
print(f" ✓ 建模耗时: {modeling_time:.2f}秒")
# 性能断言
assert eda_time < 30, f"EDA耗时过长: {eda_time}秒"
assert modeling_time < 60, f"建模耗时过长: {modeling_time}秒"
print(" ✓ 性能测试通过")
return True
except Exception as e:
print(f" ❌ 性能测试失败: {str(e)}")
return False
def cleanup_test_files():
"""清理测试文件"""
print("\n🧹 清理测试文件...")
test_files = [
'test_quick_report.html',
'test_comprehensive_report.html',
'test_integration_report.html',
'quick_start_charts',
'quick_start_output'
]
cleaned = 0
for file_path in test_files:
path = Path(file_path)
try:
if path.is_file():
path.unlink()
cleaned += 1
elif path.is_dir():
import shutil
shutil.rmtree(path)
cleaned += 1
except:
pass
print(f" ✓ 清理了 {cleaned} 个测试文件")
def main():
"""主测试函数"""
print("🧪 数据探索可视化技能 - 快速测试")
print("=" * 60)
start_time = time.time()
# 测试结果记录
test_results = {
'dependencies': False,
'eda_analyzer': False,
'visualizer': False,
'preprocessor': False,
'modeling_evaluator': False,
'report_generator': False,
'integration': False,
'performance': False
}
try:
# 1. 检查依赖
test_results['dependencies'] = check_dependencies()
if not test_results['dependencies']:
print("\n❌ 依赖检查失败,无法继续测试")
return
# 2. 测试各个模块
test_results['eda_analyzer'], eda_results = test_eda_analyzer()
test_results['visualizer'] = test_visualizer()
test_results['preprocessor'], preprocessing_results = test_preprocessor()
test_results['modeling_evaluator'], modeling_results = test_modeling_evaluator()
test_results['report_generator'] = test_report_generator()
# 3. 集成测试
test_results['integration'] = test_integration()
# 4. 性能测试
test_results['performance'] = test_performance()
# 5. 生成测试报告
total_time = time.time() - start_time
print("\n" + "=" * 60)
print("📋 测试结果摘要")
print("=" * 60)
passed_tests = sum(test_results.values())
total_tests = len(test_results)
for test_name, result in test_results.items():
status = "✅ 通过" if result else "❌ 失败"
print(f"{test_name:20} : {status}")
print(f"\n总体结果: {passed_tests}/{total_tests} 测试通过")
print(f"测试耗时: {total_time:.2f}秒")
if passed_tests == total_tests:
print("\n🎉 所有测试通过!数据探索可视化技能已就绪。")
print("\n💡 下一步:")
print(" 1. 运行 examples/quick_start_example.py 体验完整功能")
print(" 2. 运行 examples/medical_data_analysis.py 查看医疗数据示例")
print(" 3. 运行 examples/financial_data_analysis.py 查看金融数据示例")
else:
failed_tests = [name for name, result in test_results.items() if not result]
print(f"\n⚠️ {len(failed_tests)} 个测试失败: {', '.join(failed_tests)}")
print(" 请检查错误信息并修复问题后重新测试。")
except KeyboardInterrupt:
print("\n\n⏹️ 测试被用户中断")
except Exception as e:
print(f"\n\n💥 测试过程中发生异常: {str(e)}")
traceback.print_exc()
finally:
# 清理测试文件
cleanup_test_files()
if __name__ == "__main__":
main()数据探索可视化技能
一个基于《数据分析咖哥十话》第2课理论的自动化数据探索和可视化工具,提供从数据加载到专业分析报告生成的完整EDA解决方案。
✨ 核心功能
🔍 智能数据探索
- 自动数据诊断: 检测数据质量问题、异常值和缺失值模式
- 统计描述分析: 生成全面的统计摘要和分布特征
- 相关性分析: 识别特征间关系和依赖模式
- 数据质量报告: 专业级数据质量评估和建议
📊 专业可视化生成
- 分布可视化: 直方图、密度图、小提琴图、QQ图
- 统计可视化: 箱线图、误差条图、置信区间图
- 关系可视化: 散点图、热图、配对图、3D散点图
- 专门图表: ROC曲线、混淆矩阵、特征重要性图
- 交互式图表: Plotly驱动的动态可视化
🏥 医疗数据专精
- 医疗编码支持: ICD-10、SNOMED CT等医疗标准
- 生物标记物分析: 专门的医学指标处理
- 诊断模型构建: 医疗预测模型和评估
- 医学可解释性: 符合医学实践的解释框架
🤖 自动化建模评估
- 多算法支持: 逻辑回归、随机森林、XGBoost、神经网络
- 自动特征工程: 特征选择、转换和优化
- 超参数调优: 网格搜索和贝叶斯优化
- 模型可解释性: SHAP值、特征重要性、部分依赖图
📋 专业报告生成
- HTML报告: 可发表级交互式分析报告
- PDF导出: 高质量文档格式输出
- Markdown支持: 轻量级报告格式
- 自定义模板: 可配置的报告模板系统
🚀 快速开始
1. 环境安装
# 安装基础依赖
pip install pandas numpy matplotlib seaborn scipy scikit-learn plotly jinja2
# 安装可选依赖(用于高级功能)
pip install xgboost lightgbm shap imbalanced-learn weasyprint2. 快速测试
# 运行快速测试验证功能
python quick_test.py3. 基础使用
from scripts.eda_analyzer import EDAAnalyzer
from scripts.visualizer import DataVisualizer
from scripts.modeling_evaluator import ModelingEvaluator
from scripts.report_generator import ReportGenerator
# 1. 加载和分析数据
analyzer = EDAAnalyzer()
data = analyzer.load_data('your_data.csv')
eda_results = analyzer.auto_eda(data)
# 2. 生成可视化
visualizer = DataVisualizer()
charts = visualizer.auto_visualize(data, target_col='your_target')
# 3. 建模分析
modeler = ModelingEvaluator()
model_results = modeler.auto_modeling(data, target_col='your_target')
# 4. 生成报告
generator = ReportGenerator()
report_path = generator.generate_comprehensive_report(
data=data,
eda_results=eda_results,
model_results=model_results,
output_path='analysis_report.html'
)📁 项目结构
data-exploration-visualization/
├── scripts/ # 核心功能模块
│ ├── eda_analyzer.py # EDA分析器
│ ├── visualizer.py # 可视化生成器
│ ├── data_preprocessor.py # 数据预处理器
│ ├── modeling_evaluator.py # 建模评估器
│ └── report_generator.py # 报告生成器
├── examples/ # 示例脚本
│ ├── quick_start_example.py # 快速开始示例
│ ├── medical_data_analysis.py # 医疗数据分析
│ └── financial_data_analysis.py # 金融数据分析
├── SKILL.md # 技能说明文档
├── quick_test.py # 快速测试脚本
└── README.md # 项目说明🎯 使用场景
🏥 医疗健康领域
- 疾病预测: 基于临床数据的疾病风险预测
- 诊断辅助: 医学影像和检验结果分析
- 流行病学研究: 疫情数据分析和趋势预测
- 临床试验: 试验数据统计分析和可视化
💰 金融风控领域
- 信用评估: 个人和企业信用风险建模
- 欺诈检测: 异常交易模式识别
- 投资分析: 市场趋势和风险评估
- 合规报告: 监管要求的分析报告
🛒 电商零售领域
- 用户分析: 客户行为和偏好分析
- 销售预测: 销量预测和库存优化
- 推荐系统: 个性化推荐算法评估
- 市场细分: 客户群体分析和画像
🎓 科研教育领域
- 学术研究: 数据驱动的学术研究支持
- 教学案例: 数据分析教学和实践
- 论文写作: 研究数据分析和图表制作
- 技能培训: 数据科学技能培训工具
🔧 配置选项
EDA分析器配置
config = {
'max_categories': 20, # 分类变量最大显示类别数
'correlation_threshold': 0.5, # 相关性阈值
'outlier_detection': True, # 是否检测异常值
'statistical_tests': True # 是否进行统计检验
}可视化器配置
config = {
'figure_size': (12, 8), # 默认图表尺寸
'style': 'seaborn-v0_8', # 图表样式
'color_palette': 'husl', # 颜色调色板
'interactive_charts': True, # 是否生成交互式图表
'save_format': 'png' # 保存格式
}建模评估器配置
config = {
'cv_folds': 5, # 交叉验证折数
'scoring_metric': 'accuracy', # 评估指标
'enable_hyperparameter_tuning': True, # 是否调参
'n_iter_search': 50, # 搜索迭代次数
'ensemble_models': True # 是否使用集成方法
}报告生成器配置
config = {
'report_title': '数据分析报告', # 报告标题
'author': '数据分析助手', # 作者
'theme': 'modern', # 主题样式
'include_toc': True, # 是否包含目录
'medical_specialization': False # 是否医疗专化
}📊 示例数据
医疗数据示例
# 模拟医疗数据
medical_data = {
'patient_id': ['P001', 'P002', ...],
'diagnosis': ['Malignant', 'Benign', ...],
'radius_mean': [17.99, 20.57, ...],
'texture_mean': [10.38, 17.77, ...],
'perimeter_mean': [122.8, 132.9, ...]
}金融数据示例
# 模拟金融数据
financial_data = {
'customer_id': ['C001', 'C002', ...],
'credit_score': [720, 680, ...],
'income': [85000, 62000, ...],
'debt_ratio': [0.15, 0.32, ...],
'default': [0, 1, ...]
}🧪 运行示例
快速开始示例
python examples/quick_start_example.py医疗数据分析示例
python examples/medical_data_analysis.py金融数据分析示例
python examples/financial_data_analysis.py📋 常见问题
Q: 如何处理中文数据?
A: 技能自动检测和处理中文编码,支持UTF-8、GBK等多种编码格式。
Q: 支持哪些数据格式?
A: 支持CSV、Excel、JSON、Parquet等常见格式,也支持数据库连接。
Q: 如何自定义可视化样式?
A: 可以通过配置文件自定义颜色、字体、图表布局等样式参数。
Q: 模型准确性如何保证?
A: 技能采用交叉验证、多种评估指标和集成方法来确保模型的可靠性和泛化能力。
Q: 如何处理大数据集?
A: 技能自动采样大数据集,并提供内存优化建议。对于超大数据集,建议使用分布式处理框架。
⚡ 性能优化
内存优化
- 自动数据采样减少内存占用
- 智能分块处理大文件
- 垃圾回收优化
计算优化
- 并行处理提升计算速度
- 缓存机制避免重复计算
- 增量更新支持
可视化优化
- 大数据集采样显示
- 图表渲染优化
- 交互式图表懒加载
🔄 更新日志
v1.0.0 (2025-01-19)
- 初始版本发布
- 完整的EDA功能
- 基础可视化支持
- 逻辑回归建模
- HTML报告生成
未来计划
- 支持更多机器学习算法
- 增加深度学习模型支持
- 扩展医疗数据分析功能
- 云端部署支持
- 实时数据分析能力
🤝 贡献指南
欢迎贡献代码、报告问题或提出改进建议:
1. Fork 项目 2. 创建功能分支 3. 提交更改 4. 发起 Pull Request
📄 许可证
本项目采用 MIT 许可证。详见 LICENSE 文件。
🙏 致谢
- 《数据分析咖哥十话》提供的理论指导
- Scikit-learn、Pandas、Plotly 等优秀开源库
- 数据科学社区的支持和反馈
---
通过这个技能,您可以大幅提升数据分析效率,从重复性工作中解放出来,专注于洞察发现和决策支持。
#!/usr/bin/env python3
"""
数据预处理器 (Data Preprocessor) - 智能数据清洗和转换模块
提供全面的数据预处理功能,包括:
- 数据清洗(缺失值处理、异常值检测和处理)
- 数据类型转换和标准化
- 特征工程(特征选择、创建、转换)
- 数据编码(标签编码、独热编码)
- 数据分割和平衡
- 数据质量评估和改进建议
"""
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple, Optional, Union, Any
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler, LabelEncoder, OneHotEncoder
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.feature_selection import SelectKBest, f_classif, f_regression, RFE
from sklearn.ensemble import IsolationForest
from sklearn.model_selection import train_test_split
from imblearn.over_sampling import SMOTE, RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
import warnings
from pathlib import Path
import json
warnings.filterwarnings('ignore')
class DataPreprocessor:
"""数据预处理器 - 智能数据清洗和特征工程引擎"""
def __init__(self, config: Optional[Dict] = None):
"""
初始化数据预处理器
Parameters:
- config: 配置参数字典
"""
self.config = config or {}
self.preprocessing_steps = []
self.scalers = {}
self.encoders = {}
self.imputers = {}
self.feature_selectors = {}
self.preprocessing_report = {}
# 默认配置
self.default_config = {
'missing_threshold': 0.5, # 缺失值阈值
'outlier_method': 'isolation_forest', # 异常值检测方法
'outlier_contamination': 0.1, # 异常值比例
'scaling_method': 'standard', # 标准化方法
'encoding_method': 'auto', # 编码方法
'feature_selection': False, # 是否进行特征选择
'k_features': 10, # 选择的特征数量
'test_size': 0.2, # 测试集比例
'random_state': 42, # 随机种子
'balance_data': False, # 是否平衡数据
'balance_method': 'smote' # 数据平衡方法
}
# 合并配置
self.config = {**self.default_config, **self.config}
def analyze_data_quality(self, data: pd.DataFrame) -> Dict:
"""
分析数据质量
Parameters:
- data: 数据DataFrame
Returns:
- 数据质量报告
"""
print("🔍 分析数据质量...")
quality_report = {
'shape': data.shape,
'memory_usage': data.memory_usage(deep=True).sum() / 1024**2, # MB
'columns': {},
'overall_score': 0,
'issues': [],
'recommendations': []
}
total_issues = 0
total_checks = 0
for col in data.columns:
col_info = {
'dtype': str(data[col].dtype),
'non_null_count': data[col].count(),
'null_count': data[col].isnull().sum(),
'null_percentage': data[col].isnull().sum() / len(data) * 100,
'unique_count': data[col].nunique(),
'duplicate_count': data[col].duplicated().sum(),
'issues': []
}
# 检查缺失值
total_checks += 1
if col_info['null_percentage'] > 0:
total_issues += 1
col_info['issues'].append(f"缺失值: {col_info['null_percentage']:.1f}%")
if col_info['null_percentage'] > self.config['missing_threshold'] * 100:
quality_report['issues'].append(
f"列 '{col}' 缺失值过高 ({col_info['null_percentage']:.1f}%)"
)
# 检查重复值
if col_info['duplicate_count'] > 0:
col_info['issues'].append(f"重复值: {col_info['duplicate_count']}")
# 检查数据类型
if data[col].dtype == 'object':
# 检查可能的数值型分类变量
try:
pd.to_numeric(data[col], errors='raise')
col_info['issues'].append("可能是数值型但存储为字符串")
quality_report['recommendations'].append(
f"考虑将列 '{col}' 转换为数值类型"
)
except:
pass
elif pd.api.types.is_numeric_dtype(data[col]):
# 检查异常值
Q1 = data[col].quantile(0.25)
Q3 = data[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = ((data[col] < lower_bound) | (data[col] > upper_bound)).sum()
if outliers > 0:
outlier_percentage = outliers / len(data) * 100
col_info['issues'].append(f"异常值: {outliers} ({outlier_percentage:.1f}%)")
quality_report['columns'][col] = col_info
# 计算整体质量分数
quality_report['overall_score'] = max(0, 100 - (total_issues / total_checks) * 100)
# 生成建议
if quality_report['overall_score'] < 80:
quality_report['recommendations'].append("数据质量较低,建议进行数据清洗")
print(f" ✓ 数据质量分析完成,质量分数: {quality_report['overall_score']:.1f}")
return quality_report
def clean_data(self, data: pd.DataFrame,
handle_missing: str = 'auto',
handle_outliers: str = 'auto',
handle_duplicates: bool = True) -> pd.DataFrame:
"""
数据清洗
Parameters:
- data: 原始数据
- handle_missing: 缺失值处理方法
- handle_outliers: 异常值处理方法
- handle_duplicates: 是否处理重复值
Returns:
- 清洗后的数据
"""
print("🧹 开始数据清洗...")
cleaned_data = data.copy()
original_shape = cleaned_data.shape
# 1. 处理重复值
if handle_duplicates:
before_count = len(cleaned_data)
cleaned_data = cleaned_data.drop_duplicates()
removed_duplicates = before_count - len(cleaned_data)
if removed_duplicates > 0:
print(f" ✓ 移除了 {removed_duplicates} 个重复行")
self.preprocessing_steps.append(f"移除重复值: {removed_duplicates} 行")
# 2. 处理缺失值
if handle_missing != 'none':
cleaned_data = self._handle_missing_values(cleaned_data, handle_missing)
# 3. 处理异常值
if handle_outliers != 'none':
cleaned_data = self._handle_outliers(cleaned_data, handle_outliers)
final_shape = cleaned_data.shape
print(f" ✓ 数据清洗完成: {original_shape} -> {final_shape}")
return cleaned_data
def _handle_missing_values(self, data: pd.DataFrame, method: str) -> pd.DataFrame:
"""处理缺失值"""
print(" 处理缺失值...")
cleaned_data = data.copy()
for col in data.columns:
missing_percentage = data[col].isnull().sum() / len(data) * 100
if missing_percentage > 0:
if missing_percentage > self.config['missing_threshold'] * 100:
# 删除缺失值过多的列
cleaned_data = cleaned_data.drop(columns=[col])
print(f" - 删除列 '{col}' (缺失值 {missing_percentage:.1f}%)")
self.preprocessing_steps.append(f"删除列: {col} (缺失值过多)")
continue
# 根据数据类型选择填充方法
if method == 'auto':
if pd.api.types.is_numeric_dtype(data[col]):
fill_method = 'median'
else:
fill_method = 'mode'
else:
fill_method = method
if fill_method == 'mean' and pd.api.types.is_numeric_dtype(data[col]):
cleaned_data[col] = cleaned_data[col].fillna(cleaned_data[col].mean())
elif fill_method == 'median' and pd.api.types.is_numeric_dtype(data[col]):
cleaned_data[col] = cleaned_data[col].fillna(cleaned_data[col].median())
elif fill_method == 'mode':
mode_value = cleaned_data[col].mode()
if len(mode_value) > 0:
cleaned_data[col] = cleaned_data[col].fillna(mode_value[0])
elif fill_method == 'knn' and pd.api.types.is_numeric_dtype(data[col]):
# 使用KNN填充
imputer = KNNImputer(n_neighbors=5)
cleaned_data[[col]] = imputer.fit_transform(cleaned_data[[col]])
self.imputers[col] = imputer
elif fill_method == 'forward':
cleaned_data[col] = cleaned_data[col].fillna(method='ffill')
elif fill_method == 'backward':
cleaned_data[col] = cleaned_data[col].fillna(method='bfill')
print(f" - 填充列 '{col}' 缺失值 (方法: {fill_method})")
self.preprocessing_steps.append(f"处理缺失值: {method}")
return cleaned_data
def _handle_outliers(self, data: pd.DataFrame, method: str) -> pd.DataFrame:
"""处理异常值"""
print(" 处理异常值...")
cleaned_data = data.copy()
outlier_count = 0
numeric_cols = data.select_dtypes(include=[np.number]).columns
if method == 'auto':
method = self.config['outlier_method']
if method == 'iqr':
for col in numeric_cols:
Q1 = data[col].quantile(0.25)
Q3 = data[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outlier_mask = ((data[col] < lower_bound) | (data[col] > upper_bound))
col_outliers = outlier_mask.sum()
if col_outliers > 0:
outlier_count += col_outliers
# 用边界值替换异常值
cleaned_data[col] = np.where(data[col] < lower_bound, lower_bound, data[col])
cleaned_data[col] = np.where(data[col] > upper_bound, upper_bound, cleaned_data[col])
elif method == 'isolation_forest':
# 使用Isolation Forest检测异常值
iso_forest = IsolationForest(contamination=self.config['outlier_contamination'],
random_state=self.config['random_state'])
# 只使用数值列进行检测
numeric_data = data[numeric_cols].dropna()
if len(numeric_data) > 0:
outlier_labels = iso_forest.fit_predict(numeric_data)
outlier_mask = outlier_labels == -1
# 移除异常值行
outlier_indices = numeric_data.index[outlier_mask]
outlier_count = len(outlier_indices)
cleaned_data = cleaned_data.drop(outlier_indices)
print(f" - 处理了 {outlier_count} 个异常值")
self.preprocessing_steps.append(f"处理异常值: {method}")
return cleaned_data
def transform_data_types(self, data: pd.DataFrame, auto_detect: bool = True) -> pd.DataFrame:
"""
转换数据类型
Parameters:
- data: 数据DataFrame
- auto_detect: 是否自动检测数据类型
Returns:
- 类型转换后的数据
"""
print("🔄 转换数据类型...")
transformed_data = data.copy()
type_conversions = []
for col in data.columns:
original_type = str(data[col].dtype)
if auto_detect:
# 尝试自动检测最佳类型
if data[col].dtype == 'object':
# 尝试转换为数值类型
try:
numeric_data = pd.to_numeric(data[col], errors='raise')
if (numeric_data % 1 == 0).all():
transformed_data[col] = numeric_data.astype('int64')
type_conversions.append(f"{col}: {original_type} -> int64")
else:
transformed_data[col] = numeric_data.astype('float64')
type_conversions.append(f"{col}: {original_type} -> float64")
except:
# 尝试转换为日期时间
try:
transformed_data[col] = pd.to_datetime(data[col], errors='raise')
type_conversions.append(f"{col}: {original_type} -> datetime64")
except:
# 尝试转换为分类类型
unique_ratio = data[col].nunique() / len(data)
if unique_ratio < 0.5: # 如果唯一值比例小于50%
transformed_data[col] = data[col].astype('category')
type_conversions.append(f"{col}: {original_type} -> category")
if type_conversions:
print(" 数据类型转换:")
for conversion in type_conversions:
print(f" ✓ {conversion}")
self.preprocessing_steps.append("数据类型自动转换")
return transformed_data
def encode_categorical(self, data: pd.DataFrame, columns: Optional[List[str]] = None,
method: str = 'auto') -> pd.DataFrame:
"""
编码分类变量
Parameters:
- data: 数据DataFrame
- columns: 要编码的列名列表
- method: 编码方法
Returns:
- 编码后的数据
"""
print("🏷️ 编码分类变量...")
encoded_data = data.copy()
if columns is None:
columns = data.select_dtypes(include=['object', 'category']).columns.tolist()
if not columns:
print(" ✓ 没有需要编码的分类变量")
return encoded_data
if method == 'auto':
# 自动选择编码方法
for col in columns:
unique_count = data[col].nunique()
if unique_count == 2:
# 二分类变量使用标签编码
encoder = LabelEncoder()
encoded_data[col] = encoder.fit_transform(data[col].astype(str))
self.encoders[col] = encoder
print(f" ✓ 标签编码: {col} ({unique_count} 类别)")
elif unique_count <= 10:
# 少量类别使用独热编码
dummies = pd.get_dummies(data[col], prefix=col)
encoded_data = pd.concat([encoded_data.drop(columns=[col]), dummies], axis=1)
print(f" ✓ 独热编码: {col} ({unique_count} 类别)")
else:
# 多类别使用标签编码
encoder = LabelEncoder()
encoded_data[col] = encoder.fit_transform(data[col].astype(str))
self.encoders[col] = encoder
print(f" ✓ 标签编码: {col} ({unique_count} 类别)")
else:
# 使用指定的编码方法
if method == 'label':
for col in columns:
encoder = LabelEncoder()
encoded_data[col] = encoder.fit_transform(data[col].astype(str))
self.encoders[col] = encoder
print(f" ✓ 标签编码: {col}")
elif method == 'onehot':
for col in columns:
dummies = pd.get_dummies(data[col], prefix=col)
encoded_data = pd.concat([encoded_data.drop(columns=[col]), dummies], axis=1)
print(f" ✓ 独热编码: {col}")
self.preprocessing_steps.append(f"分类变量编码: {method}")
return encoded_data
def scale_features(self, data: pd.DataFrame, columns: Optional[List[str]] = None,
method: str = None) -> pd.DataFrame:
"""
特征缩放
Parameters:
- data: 数据DataFrame
- columns: 要缩放的列名列表
- method: 缩放方法
Returns:
- 缩放后的数据
"""
print("📏 特征缩放...")
scaled_data = data.copy()
if columns is None:
columns = data.select_dtypes(include=[np.number]).columns.tolist()
if not columns:
print(" ✓ 没有需要缩放的数值变量")
return scaled_data
if method is None:
method = self.config['scaling_method']
# 选择缩放器
if method == 'standard':
scaler = StandardScaler()
elif method == 'minmax':
scaler = MinMaxScaler()
elif method == 'robust':
scaler = RobustScaler()
else:
raise ValueError(f"不支持的缩放方法: {method}")
# 应用缩放
scaled_data[columns] = scaler.fit_transform(data[columns])
self.scalers['feature_scaler'] = scaler
print(f" ✓ 使用 {method} 方法缩放了 {len(columns)} 个特征")
self.preprocessing_steps.append(f"特征缩放: {method}")
return scaled_data
def select_features(self, data: pd.DataFrame, target_col: str,
method: str = 'univariate', k: int = None) -> Tuple[pd.DataFrame, List[str]]:
"""
特征选择
Parameters:
- data: 数据DataFrame
- target_col: 目标列名
- method: 选择方法
- k: 选择的特征数量
Returns:
- 选择后的数据和特征列表
"""
print("🎯 特征选择...")
if target_col not in data.columns:
print(f" ⚠️ 目标列 '{target_col}' 不存在,跳过特征选择")
return data, data.columns.tolist()
if k is None:
k = self.config['k_features']
# 准备数据
X = data.drop(columns=[target_col])
y = data[target_col]
# 只使用数值列进行选择
numeric_cols = X.select_dtypes(include=[np.number]).columns.tolist()
X_numeric = X[numeric_cols]
if len(numeric_cols) == 0:
print(" ⚠️ 没有数值特征,跳过特征选择")
return data, data.columns.tolist()
if method == 'univariate':
# 单变量统计选择
if y.dtype == 'object' or len(y.unique()) < 10:
# 分类问题
selector = SelectKBest(score_func=f_classif, k=min(k, len(numeric_cols)))
else:
# 回归问题
selector = SelectKBest(score_func=f_regression, k=min(k, len(numeric_cols)))
X_selected = selector.fit_transform(X_numeric, y)
selected_features = X_numeric.columns[selector.get_support()].tolist()
elif method == 'rfe':
# 递归特征消除
from sklearn.linear_model import LogisticRegression, LinearRegression
if y.dtype == 'object' or len(y.unique()) < 10:
estimator = LogisticRegression(max_iter=1000)
else:
estimator = LinearRegression()
selector = RFE(estimator=estimator, n_features_to_select=min(k, len(numeric_cols)))
X_selected = selector.fit_transform(X_numeric, y)
selected_features = X_numeric.columns[selector.get_support()].tolist()
else:
raise ValueError(f"不支持的特征选择方法: {method}")
# 构建选择后的数据
other_cols = [col for col in data.columns if col not in numeric_cols and col != target_col]
selected_data = pd.concat([
data[other_cols],
pd.DataFrame(X_selected, columns=selected_features, index=data.index),
data[[target_col]]
], axis=1)
print(f" ✓ 从 {len(numeric_cols)} 个特征中选择了 {len(selected_features)} 个")
self.feature_selectors['feature_selector'] = selector
self.preprocessing_steps.append(f"特征选择: {method} (选择了 {len(selected_features)} 个特征)")
return selected_data, selected_features
def split_data(self, data: pd.DataFrame, target_col: str,
test_size: float = None, stratify: bool = True) -> Dict:
"""
数据分割
Parameters:
- data: 数据DataFrame
- target_col: 目标列名
- test_size: 测试集比例
- stratify: 是否分层抽样
Returns:
- 分割后的数据字典
"""
print("✂️ 分割数据...")
if test_size is None:
test_size = self.config['test_size']
X = data.drop(columns=[target_col])
y = data[target_col]
# 分层抽样参数
stratify_param = y if stratify and (y.dtype == 'object' or len(y.unique()) < 100) else None
# 分割数据
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=test_size, random_state=self.config['random_state'],
stratify=stratify_param
)
split_info = {
'X_train': X_train,
'X_test': X_test,
'y_train': y_train,
'y_test': y_test,
'train_size': len(X_train),
'test_size': len(X_test),
'train_ratio': len(X_train) / len(data),
'test_ratio': len(X_test) / len(data),
'feature_count': X.shape[1],
'target_classes': y.nunique() if y.dtype == 'object' else 'continuous'
}
print(f" ✓ 训练集: {len(X_train)} 样本 ({len(X_train)/len(data):.1%})")
print(f" ✓ 测试集: {len(X_test)} 样本 ({len(X_test)/len(data):.1%})")
self.preprocessing_steps.append(f"数据分割: 测试集比例 {test_size}")
return split_info
def balance_data(self, X_train: pd.DataFrame, y_train: pd.DataFrame,
method: str = None) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""
平衡数据
Parameters:
- X_train: 训练特征
- y_train: 训练标签
- method: 平衡方法
Returns:
- 平衡后的数据
"""
if method is None:
method = self.config['balance_method']
# 检查是否需要平衡
if y_train.dtype == 'object' or len(y_train.unique()) < 100:
class_counts = y_train.value_counts()
min_count = class_counts.min()
max_count = class_counts.max()
if max_count / min_count <= 2: # 如果类别比例小于2:1,认为已经平衡
print(" ✓ 数据已经平衡,无需处理")
return X_train, y_train
print(f"⚖️ 平衡数据 (方法: {method})...")
if method == 'smote':
# SMOTE过采样
smote = SMOTE(random_state=self.config['random_state'])
X_balanced, y_balanced = smote.fit_resample(X_train, y_train)
elif method == 'oversample':
# 随机过采样
ros = RandomOverSampler(random_state=self.config['random_state'])
X_balanced, y_balanced = ros.fit_resample(X_train, y_train)
elif method == 'undersample':
# 随机欠采样
rus = RandomUnderSampler(random_state=self.config['random_state'])
X_balanced, y_balanced = rus.fit_resample(X_train, y_train)
else:
raise ValueError(f"不支持的平衡方法: {method}")
print(f" ✓ 平衡前: {X_train.shape[0]} 样本")
print(f" ✓ 平衡后: {X_balanced.shape[0]} 样本")
# 转换回DataFrame
if hasattr(X_balanced, 'toarray'):
X_balanced = pd.DataFrame(X_balanced.toarray(), columns=X_train.columns)
else:
X_balanced = pd.DataFrame(X_balanced, columns=X_train.columns)
y_balanced = pd.Series(y_balanced, name=y_train.name)
self.preprocessing_steps.append(f"数据平衡: {method}")
return X_balanced, y_balanced
def auto_preprocess(self, data: pd.DataFrame, target_col: str,
save_report: bool = True) -> Dict:
"""
自动化预处理流程
Parameters:
- data: 原始数据
- target_col: 目标列名
- save_report: 是否保存报告
Returns:
- 预处理结果字典
"""
print("🚀 开始自动化数据预处理...")
results = {
'original_data': data,
'preprocessed_data': None,
'X_train': None,
'X_test': None,
'y_train': None,
'y_test': None,
'quality_report': None,
'preprocessing_steps': [],
'feature_info': {}
}
# 1. 数据质量分析
quality_report = self.analyze_data_quality(data)
results['quality_report'] = quality_report
# 2. 数据清洗
cleaned_data = self.clean_data(data)
results['preprocessing_steps'].extend(self.preprocessing_steps)
# 3. 数据类型转换
transformed_data = self.transform_data_types(cleaned_data)
# 4. 特征工程
# 这里可以添加更多的特征工程步骤
engineered_data = self._feature_engineering(transformed_data, target_col)
# 5. 编码分类变量
encoded_data = self.encode_categorical(engineered_data)
# 6. 特征缩放
numeric_cols = encoded_data.select_dtypes(include=[np.number]).columns.tolist()
if target_col in numeric_cols:
numeric_cols.remove(target_col)
if numeric_cols:
scaled_data = self.scale_features(encoded_data, numeric_cols)
else:
scaled_data = encoded_data
results['preprocessed_data'] = scaled_data
# 7. 特征选择(可选)
if self.config['feature_selection'] and target_col in scaled_data.columns:
selected_data, selected_features = self.select_features(
scaled_data, target_col, k=self.config['k_features']
)
results['feature_info']['selected_features'] = selected_features
final_data = selected_data
else:
final_data = scaled_data
results['feature_info']['all_features'] = [
col for col in final_data.columns if col != target_col
]
# 8. 数据分割
if target_col in final_data.columns:
split_result = self.split_data(final_data, target_col)
results.update(split_result)
# 9. 数据平衡(可选,仅对分类问题)
if (self.config['balance_data'] and
target_col in final_data.columns and
(results['y_train'].dtype == 'object' or len(results['y_train'].unique()) < 100)):
X_balanced, y_balanced = self.balance_data(
results['X_train'], results['y_train'], method=self.config['balance_method']
)
results['X_train'] = X_balanced
results['y_train'] = y_balanced
# 保存预处理报告
if save_report:
self.preprocessing_report = {
'timestamp': pd.Timestamp.now().isoformat(),
'original_shape': data.shape,
'final_shape': results['preprocessed_data'].shape,
'preprocessing_steps': self.preprocessing_steps,
'quality_score': quality_report['overall_score'],
'feature_count': len(results['feature_info'].get('selected_features',
results['feature_info'].get('all_features', [])))
}
print(f"\n🎉 自动化预处理完成!")
print(f" 原始数据: {data.shape}")
print(f" 预处理后: {results['preprocessed_data'].shape}")
print(f" 预处理步骤: {len(self.preprocessing_steps)}")
return results
def _feature_engineering(self, data: pd.DataFrame, target_col: str) -> pd.DataFrame:
"""基础特征工程"""
engineered_data = data.copy()
numeric_cols = data.select_dtypes(include=[np.number]).columns.tolist()
# 创建交互特征(对于数值变量)
if len(numeric_cols) >= 2:
# 选择前几个重要变量创建交互项
important_cols = numeric_cols[:min(3, len(numeric_cols))]
for i, col1 in enumerate(important_cols):
for col2 in important_cols[i+1:]:
# 乘积特征
engineered_data[f'{col1}_x_{col2}'] = data[col1] * data[col2]
# 比值特征(避免除零)
engineered_data[f'{col1}_div_{col2}'] = np.where(
data[col2] != 0, data[col1] / data[col2], 0
)
# 创建多项式特征(对于重要变量)
if len(important_cols) > 0:
for col in important_cols[:2]: # 只为前两个变量创建
engineered_data[f'{col}_squared'] = data[col] ** 2
engineered_data[f'{col}_sqrt'] = np.sqrt(np.abs(data[col]))
print(f" ✓ 创建了 {engineered_data.shape[1] - data.shape[1]} 个新特征")
return engineered_data
def get_preprocessing_summary(self) -> Dict:
"""
获取预处理摘要
Returns:
- 预处理摘要信息
"""
return {
'preprocessing_steps': self.preprocessing_steps,
'scalers': list(self.scalers.keys()),
'encoders': list(self.encoders.keys()),
'imputers': list(self.imputers.keys()),
'feature_selectors': list(self.feature_selectors.keys()),
'preprocessing_report': getattr(self, 'preprocessing_report', {}),
'config': self.config
}
def save_preprocessing_objects(self, output_dir: str):
"""
保存预处理对象
Parameters:
- output_dir: 输出目录
"""
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
# 保存scalers
if self.scalers:
import joblib
for name, scaler in self.scalers.items():
joblib.dump(scaler, output_path / f"{name}.pkl")
# 保存encoders
if self.encoders:
import joblib
for name, encoder in self.encoders.items():
joblib.dump(encoder, output_path / f"{name}_encoder.pkl")
# 保存预处理报告
if hasattr(self, 'preprocessing_report'):
with open(output_path / 'preprocessing_report.json', 'w', encoding='utf-8') as f:
json.dump(self.preprocessing_report, f, ensure_ascii=False, indent=2)
print(f"✅ 预处理对象已保存到 {output_dir}")
def load_preprocessing_objects(self, input_dir: str):
"""
加载预处理对象
Parameters:
- input_dir: 输入目录
"""
input_path = Path(input_dir)
# 加载scalers
import joblib
for scaler_file in input_path.glob("*.pkl"):
if not str(scaler_file).endswith('_encoder.pkl'):
name = scaler_file.stem
self.scalers[name] = joblib.load(scaler_file)
# 加载encoders
for encoder_file in input_path.glob("*_encoder.pkl"):
name = encoder_file.stem.replace('_encoder', '')
self.encoders[name] = joblib.load(encoder_file)
print(f"✅ 预处理对象已从 {input_dir} 加载")
def transform_new_data(self, new_data: pd.DataFrame) -> pd.DataFrame:
"""
对新数据应用相同的预处理
Parameters:
- new_data: 新数据
Returns:
- 预处理后的新数据
"""
transformed_data = new_data.copy()
# 应用缺失值处理
for col, imputer in self.imputers.items():
if col in transformed_data.columns:
if hasattr(imputer, 'transform'):
transformed_data[[col]] = imputer.transform(transformed_data[[col]])
# 应用编码
for col, encoder in self.encoders.items():
if col in transformed_data.columns:
transformed_data[col] = encoder.transform(transformed_data[col].astype(str))
# 应用缩放
if 'feature_scaler' in self.scalers:
numeric_cols = transformed_data.select_dtypes(include=[np.number]).columns.tolist()
if numeric_cols:
transformed_data[numeric_cols] = self.scalers['feature_scaler'].transform(
transformed_data[numeric_cols]
)
return transformed_data