hscredit.core.eda.report 源代码

"""综合报告模块.

提供EDA综合报告生成和导出功能.
整合所有模块的分析结果.
"""

import logging
import numpy as np
import pandas as pd
from typing import List, Dict, Optional, Union
from datetime import datetime

from .utils import validate_dataframe
from .overview import data_info, missing_analysis, feature_summary, data_quality_report
from .target import target_distribution, bad_rate_overall, bad_rate_trend
from .relationship import batch_iv_analysis
from .correlation import high_correlation_pairs

from ...excel import ExcelWriter, dataframe2excel

logger = logging.getLogger(__name__)


[文档] def eda_summary(df: pd.DataFrame, target: str = None, features: List[str] = None, date_col: str = None, n_jobs=-1, parallel_backend=None, parallel_config=None) -> Dict[str, pd.DataFrame]: """EDA分析摘要. 快速生成数据集的关键分析结果 :param df: 输入数据 :param target: 目标变量名(可选) :param features: 特征列表(可选) :param date_col: 日期列名(可选) :return: EDA摘要字典 **参考样例** >>> summary = eda_summary(df, target='fpd15', date_col='apply_date') >>> for key, value in summary.items(): ... print(f"\n=== {key} ===") ... print(value) """ validate_dataframe(df) if features is None: features = [c for c in df.columns if c != target] summary = {} # 1. 数据基础信息 summary['数据基础信息'] = data_info(df) # 2. 缺失值分析 summary['缺失值分析'] = missing_analysis(df, threshold=0.0) # 3. 特征描述统计 summary['特征描述统计'] = feature_summary( df, features, n_jobs=n_jobs, parallel_backend=parallel_backend, parallel_config=parallel_config, ) # 4. 数据质量问题 summary['数据质量问题'] = data_quality_report(df) # 5. 目标变量分析 if target and target in df.columns: summary['目标变量分布'] = target_distribution(df, target) summary['整体逾期率'] = pd.DataFrame([bad_rate_overall(df, target)]) # 时间趋势 if date_col and date_col in df.columns: try: summary['逾期率趋势'] = bad_rate_trend(df, target, date_col) except Exception: pass return summary
[文档] def generate_report(df: pd.DataFrame, target: str = None, features: List[str] = None, date_col: str = None, config: Dict = None, n_jobs=-1, parallel_backend=None, parallel_config=None) -> Dict[str, pd.DataFrame]: """生成完整EDA报告. :param df: 输入数据 :param target: 目标变量名 :param features: 特征列表 :param date_col: 日期列名 :param config: 配置参数 :return: 完整报告字典 **参考样例** >>> report = generate_report(df, target='fpd15', date_col='apply_date', ... config={'iv_threshold': 0.02}) >>> export_report_to_excel(report, 'eda_report.xlsx') """ validate_dataframe(df) if features is None: features = [c for c in df.columns if c != target and c != date_col] if config is None: config = {} iv_threshold = config.get('iv_threshold', 0.02) corr_threshold = config.get('corr_threshold', 0.8) report = {} # 1. 数据概览 report['1.数据基础信息'] = data_info(df) report['2.缺失值分析'] = missing_analysis(df) report['3.特征描述统计'] = feature_summary( df, features, n_jobs=n_jobs, parallel_backend=parallel_backend, parallel_config=parallel_config, ) report['4.数据质量问题'] = data_quality_report(df) # 2. 目标变量分析 if target and target in df.columns: report['5.目标变量分布'] = target_distribution(df, target) report['6.整体逾期率'] = pd.DataFrame([bad_rate_overall(df, target)]) if date_col and date_col in df.columns: try: report['7.逾期率趋势'] = bad_rate_trend(df, target, date_col) except Exception: pass # 3. IV分析 try: iv_result = batch_iv_analysis( df, features, target, n_jobs=n_jobs, parallel_backend=parallel_backend, parallel_config=parallel_config, ) report['8.IV分析'] = iv_result[iv_result['IV值'] >= iv_threshold] except Exception: pass # 4. 相关性分析 try: corr_pairs = high_correlation_pairs(df, features, threshold=corr_threshold) if '信息' not in corr_pairs.columns: report['9.高相关性特征对'] = corr_pairs except Exception: pass return report
[文档] def export_report_to_excel(report: Dict[str, pd.DataFrame], filepath: str, sheet_name_mapping: Dict[str, str] = None, theme_color: str = '2639E9', auto_width: bool = True) -> None: """导出报告到Excel. 使用 hscredit 的 ExcelWriter 生成专业格式的 Excel 报告。 :param report: 报告字典 :param filepath: 导出文件路径 :param sheet_name_mapping: 工作表名称映射 :param theme_color: 主题颜色,默认 '2639E9'(蓝色) :param auto_width: 是否自动调整列宽,默认 True **参考样例** >>> export_report_to_excel(report, 'eda_report.xlsx') >>> export_report_to_excel(report, 'eda_report.xlsx', theme_color='00A651') """ # 处理sheet名称(Excel限制:最多31个字符,不能包含特殊字符) def clean_sheet_name(name: str) -> str: # 移除特殊字符 name = name.replace('/', '_').replace('\\', '_').replace(':', '_') name = name.replace('?', '').replace('*', '').replace('[', '').replace(']', '') # 截取前31个字符 return name[:31] with ExcelWriter(theme_color=theme_color) as writer: for section_name, df in report.items(): if df is None or df.empty: continue # 处理工作表名称 if sheet_name_mapping and section_name in sheet_name_mapping: sheet_name = clean_sheet_name(sheet_name_mapping[section_name]) else: sheet_name = clean_sheet_name(section_name) # 获取或创建工作表 worksheet = writer.get_sheet_by_name(sheet_name) # 写入标题 writer.insert_value2sheet( worksheet, 'B2', value=section_name, style='header' ) # 写入DataFrame writer.insert_df2sheet( worksheet, df, 'B4', header=True, index=False, auto_width=auto_width, fill=False ) # 保存文件 writer.save(filepath) logger.info("报告已导出至: %s", filepath)
def generate_html_report(report: Dict[str, pd.DataFrame], filepath: str, title: str = "EDA分析报告") -> None: """生成HTML报告. :param report: 报告字典 :param filepath: 导出文件路径 :param title: 报告标题 **参考样例** >>> generate_html_report(report, 'eda_report.html', title='信贷数据EDA报告') """ html_parts = [] # HTML头部 html_parts.append(f""" <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{title}</title> <style> body {{ font-family: Arial, sans-serif; margin: 40px; }} h1 {{ color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }} h2 {{ color: #555; margin-top: 30px; }} table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }} th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }} th {{ background-color: #007bff; color: white; }} tr:nth-child(even) {{ background-color: #f2f2f2; }} .timestamp {{ color: #666; font-size: 12px; margin-top: 40px; }} </style> </head> <body> <h1>{title}</h1> """) # 各章节 for section_name, df in report.items(): html_parts.append(f"<h2>{section_name}</h2>") if not df.empty: html_parts.append(df.to_html(index=False, classes='data-table')) else: html_parts.append("<p>无数据</p>") # HTML尾部 html_parts.append(f""" <p class="timestamp">生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p> </body> </html> """) # 写入文件 with open(filepath, 'w', encoding='utf-8') as f: f.write('\n'.join(html_parts)) logger.info("HTML报告已导出至: %s", filepath)