大家好,我是CSDN的一名技术博主。最近在辅导一些非计算机专业(如会计、金融)的同学完成他们的“数据科学与人工智能导论”课程实践时,发现一个普遍痛点:大家虽然对概念有所了解,但面对一个具体的、需要从数据到模型再到分析报告的完整项目时,往往无从下手,代码、流程、报告撰写都是割裂的。
本文将以一份面向会计专业的期末实践报告为蓝本,系统拆解如何完成一个数据科学项目。我们将从一个真实的财务数据集出发,完整走过数据获取、清洗、探索性分析、机器学习建模、结果可视化与商业解读的全流程,并提供所有可复现的Python代码。无论你是零基础的会计专业学生,还是想了解如何将AI应用于业务分析的开发者,都能从这篇实战指南中获得一套可直接套用的方法论。
1. 项目背景与核心目标
本次实践报告的核心是:利用数据科学与人工智能技术,对上市公司财务数据进行分析与预测,并给出商业洞察。对于会计专业的同学而言,这不仅是完成课程作业,更是将所学的会计原理、财务分析与前沿的数据工具相结合的一次宝贵实践。
1.1 为什么会计专业需要学习数据科学?在现代商业环境中,财务数据已不再是简单的报表数字。海量的交易数据、市场数据和运营数据中蕴藏着关于企业健康度、风险预警和未来趋势的关键信息。传统手工分析难以处理这种规模与复杂度的数据。数据科学提供了强大的工具(如Python, Pandas, Scikit-learn)来自动化数据处理、发现深层模式、甚至构建预测模型(如破产预测、股价趋势分析),从而提升财务分析的效率、深度与前瞻性。
1.2 项目核心目标拆解我们的项目将围绕以下几个可量化、可验证的目标展开:
- 目标一:数据理解与清洗。获取一份真实的上市公司财务数据集,理解每个字段的财务含义,并处理缺失值、异常值,使数据可用于分析。
- 目标二:探索性数据分析。通过统计描述与可视化,初步揭示数据特征,如不同行业公司的盈利能力分布、资产与负债的关系等。
- 目标三:构建预测模型。选择一个具体的预测任务,例如,根据一系列财务指标(如资产负债率、净资产收益率)来预测公司是否会被特殊处理(ST)。我们将使用经典的机器学习算法来完成此任务。
- 目标四:模型评估与解释。评估模型的预测性能,并尝试解释哪些财务指标对预测结果影响最大,将机器学习结果转化为可理解的商业语言。
- 目标五:形成综合报告。将以上所有步骤、代码、结果和分析逻辑,整合成一份结构清晰、图文并茂的实践报告。
2. 环境准备与工具说明
工欲善其事,必先利其器。我们选择Python作为主要工具,因为它拥有极其丰富且易用的数据科学库生态系统。
2.1 基础环境配置
- 操作系统:Windows 10/11, macOS 或 Linux 均可。本文示例在Windows 11下完成。
- Python版本:推荐使用 Python 3.8 至 3.10。版本过高可能导致某些库兼容性问题。
- 包管理工具:使用
pip或更推荐的conda(如果你安装了Anaconda)。
2.2 核心Python库安装我们将使用以下库,请通过命令行(CMD或终端)安装:
# 使用 pip 安装 pip install pandas numpy matplotlib seaborn scikit-learn jupyter # 或者使用 conda 安装 conda install pandas numpy matplotlib seaborn scikit-learn jupyter- pandas:数据操作的基石,用于数据读取、清洗、转换和分析。
- numpy:提供高性能的数组计算,是许多科学计算库的基础。
- matplotlib&seaborn:数据可视化库,用于绘制各种统计图表。
- scikit-learn:机器学习库,提供了分类、回归、聚类等大量算法和评估工具。
- jupyter:交互式笔记本环境,非常适合分步执行代码和展示结果,是撰写数据分析报告的绝佳工具。
2.3 项目结构与数据集
- 项目结构:建议创建一个清晰的文件夹。
your_project/ ├── data/ │ └── listed_companies_financial.csv # 数据集 ├── images/ # 存放生成的图表 ├── 财务数据分析与预测.ipynb # Jupyter Notebook主文件 └── 期末实践报告.pdf # 最终生成的报告- 数据集:我们将使用一个模拟的上市公司财务数据集。为了便于复现,你可以从Kaggle、UCI或国内一些公开数据平台寻找类似数据集(如“上市公司财务指标”)。本文为了演示,将使用代码生成一个包含关键财务指标的模拟数据集。
3. 核心概念与流程拆解
在动手编码前,我们需要理解一个标准的数据科学项目流程,即CRISP-DM(跨行业数据挖掘标准流程) 的简化版。
3.1 业务理解对应我们的项目目标:利用财务数据预测公司风险(ST状态),为投资或风控提供参考。
3.2 数据理解与准备这是最耗时但也最关键的一步。涉及:
- 数据收集:获取包含
股票代码、行业、净利润、资产负债率、流动比率、净资产收益率(ROE)、总资产周转率等字段的数据。 - 数据清洗:
- 处理缺失值:删除或填充(如用中位数填充)。
- 处理异常值:识别并处理远超正常范围的数值。
- 格式统一:确保数字字段为数值型,日期字段为日期型。
- 特征工程:从原始字段中衍生出更有预测力的新特征。例如,计算“净利润增长率”。
3.3 建模选择合适的算法。对于“预测是否ST”这样的二分类问题,我们可以选择:
- 逻辑回归:模型简单,可解释性强,适合作为基线模型。
- 决策树/随机森林:能捕捉非线性关系,通常有不错的性能。
- 支持向量机:在高维空间表现良好。 我们将以逻辑回归和随机森林为例进行对比。
3.4 评估使用未参与模型训练的数据(测试集)来评估模型性能。常用指标包括:
- 准确率:预测正确的样本比例。
- 精确率、召回率、F1-score:尤其适用于类别不平衡的数据(ST公司通常远少于非ST公司)。
- ROC曲线与AUC值:综合评价模型分类能力的指标。
3.5 部署与报告将分析过程、代码、结果可视化,并提炼核心发现,形成最终报告。
4. 完整实战:上市公司财务风险预测
接下来,我们将在Jupyter Notebook中一步步实现整个流程。
4.1 数据加载与初步探索
首先,我们生成一个模拟数据集并进行初步查看。
# 导入必要的库 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, roc_auc_score, roc_curve # 设置中文显示和图表样式 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 sns.set_style("whitegrid") # 生成模拟数据 np.random.seed(42) # 确保每次运行结果一致 n_samples = 1000 data = { 'stock_code': [f'STK{str(i).zfill(6)}' for i in range(n_samples)], 'industry': np.random.choice(['制造业', '信息技术', '金融业', '零售业', '房地产业'], n_samples), 'net_profit': np.random.normal(50, 200, n_samples), # 净利润(百万) 'asset_liability_ratio': np.random.uniform(0.1, 0.9, n_samples), # 资产负债率 'current_ratio': np.random.uniform(0.5, 3.0, n_samples), # 流动比率 'roe': np.random.normal(0.08, 0.15, n_samples), # 净资产收益率 'total_asset_turnover': np.random.uniform(0.2, 1.5, n_samples), # 总资产周转率 } df = pd.DataFrame(data) # 模拟生成目标变量 `is_st` (1表示ST,0表示非ST) # 规则:资产负债率过高、ROE为负、净利润为负的公司更可能被ST def simulate_st(row): risk_score = 0 if row['asset_liability_ratio'] > 0.7: risk_score += 2 if row['roe'] < 0: risk_score += 2 if row['net_profit'] < -10: # 净亏损较大 risk_score += 1 # 引入随机性 return 1 if (risk_score >= 3 and np.random.rand() > 0.3) else 0 df['is_st'] = df.apply(simulate_st, axis=1) print("数据集形状(行数,列数):", df.shape) print("\n数据前5行:") print(df.head()) print("\n数据基本信息:") print(df.info()) print("\n数值型字段描述性统计:") print(df.describe()) print("\n目标变量分布(ST vs 非ST):") print(df['is_st'].value_counts()) print("ST公司占比:{:.2%}".format(df['is_st'].mean()))运行以上代码,你会看到数据的基本情况:1000条记录,8个字段,其中is_st是我们的目标变量。可以看到ST公司占比大约在10%左右,这是一个典型的类别不平衡数据集。
4.2 数据清洗与预处理
现实数据往往不完美,我们需要进行处理。
# 1. 检查缺失值 print("缺失值统计:") print(df.isnull().sum()) # 本例中模拟数据无缺失,若有缺失,常用处理方式: # df.fillna(df.median(), inplace=True) # 用中位数填充数值列 # df.dropna(inplace=True) # 或直接删除缺失行 # 2. 检查并处理异常值(以净资产收益率ROE为例) plt.figure(figsize=(10, 4)) plt.subplot(1,2,1) sns.boxplot(y=df['roe']) plt.title('ROE箱线图(处理前)') # 使用IQR方法识别异常值 Q1 = df['roe'].quantile(0.25) Q3 = df['roe'].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR outliers = df[(df['roe'] < lower_bound) | (df['roe'] > upper_bound)] print(f"\nROE异常值数量:{len(outliers)}") # 处理异常值:这里采用盖帽法,将极端值拉回到边界 df['roe_capped'] = df['roe'].clip(lower_bound, upper_bound) plt.subplot(1,2,2) sns.boxplot(y=df['roe_capped']) plt.title('ROE箱线图(盖帽法处理后)') plt.tight_layout() plt.show() # 3. 特征工程:创建衍生特征 df['profit_margin'] = df['net_profit'].apply(lambda x: 1 if x > 0 else 0) # 是否盈利 # 可以创建更多特征,如行业平均ROE等,此处简化 # 4. 对分类特征(行业)进行编码 df = pd.get_dummies(df, columns=['industry'], prefix='ind') print("\n进行独热编码后的数据列:") print(df.columns.tolist())4.3 探索性数据分析
通过可视化深入理解数据。
# 1. 目标变量分布 plt.figure(figsize=(12, 10)) plt.subplot(2, 2, 1) df['is_st'].value_counts().plot(kind='bar', color=['skyblue', 'salmon']) plt.title('ST与非ST公司数量对比') plt.xlabel('是否ST (1=是)') plt.ylabel('公司数量') for i, v in enumerate(df['is_st'].value_counts().sort_index()): plt.text(i, v+10, str(v), ha='center') # 2. 关键财务指标分布 plt.subplot(2, 2, 2) sns.histplot(df['asset_liability_ratio'], kde=True, bins=30) plt.title('资产负债率分布') plt.xlabel('资产负债率') plt.subplot(2, 2, 3) sns.scatterplot(x='asset_liability_ratio', y='roe_capped', hue='is_st', data=df, alpha=0.6) plt.title('资产负债率 vs ROE (按ST状态着色)') plt.xlabel('资产负债率') plt.ylabel('ROE (盖帽后)') # 3. 按行业分析ST比例 plt.subplot(2, 2, 4) # 计算各行业ST比例 industry_st_rate = {} for col in df.columns: if col.startswith('ind_'): industry_name = col.replace('ind_', '') st_rate = df[df[col]==1]['is_st'].mean() industry_st_rate[industry_name] = st_rate st_rate_series = pd.Series(industry_st_rate).sort_values(ascending=False) st_rate_series.plot(kind='barh', color='lightgreen') plt.title('各行业ST公司比例') plt.xlabel('ST比例') plt.tight_layout() plt.show() # 4. 相关性热图(数值特征) numeric_features = ['net_profit', 'asset_liability_ratio', 'current_ratio', 'roe_capped', 'total_asset_turnover', 'profit_margin'] corr_matrix = df[numeric_features + ['is_st']].corr() plt.figure(figsize=(10, 8)) sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', center=0) plt.title('数值特征与目标变量相关性热图') plt.show()通过图表,我们可以直观看到:ST公司占少数;资产负债率与ROE似乎存在一定关系;不同行业的ST风险比例不同;资产负债率与is_st呈现正相关(符合常识),而ROE、总资产周转率与is_st呈负相关。
4.4 构建与评估预测模型
现在,我们进入机器学习建模环节。
# 1. 准备特征(X)和目标变量(y) # 选择用于建模的特征列 feature_columns = ['asset_liability_ratio', 'current_ratio', 'roe_capped', 'total_asset_turnover', 'profit_margin'] feature_columns.extend([col for col in df.columns if col.startswith('ind_')]) # 加入行业哑变量 X = df[feature_columns] y = df['is_st'] print(f"特征矩阵X的形状:{X.shape}") print(f"目标变量y的形状:{y.shape}") # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) print(f"训练集大小:{X_train.shape}, 测试集大小:{X_test.shape}") print(f"训练集ST比例:{y_train.mean():.3f}, 测试集ST比例:{y_test.mean():.3f}") # 3. 特征标准化(对逻辑回归等基于距离的模型很重要) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 4. 训练逻辑回归模型 print("\n" + "="*50) print("逻辑回归模型") print("="*50) lr_model = LogisticRegression(random_state=42, max_iter=1000, class_weight='balanced') # 使用class_weight处理不平衡 lr_model.fit(X_train_scaled, y_train) y_pred_lr = lr_model.predict(X_test_scaled) y_pred_proba_lr = lr_model.predict_proba(X_test_scaled)[:, 1] # 预测为ST的概率 print("准确率:", accuracy_score(y_test, y_pred_lr)) print("\n分类报告:") print(classification_report(y_test, y_pred_lr, target_names=['非ST', 'ST'])) print("AUC分数:", roc_auc_score(y_test, y_pred_proba_lr)) # 5. 训练随机森林模型 print("\n" + "="*50) print("随机森林模型") print("="*50) rf_model = RandomForestClassifier(n_estimators=100, random_state=42, class_weight='balanced') rf_model.fit(X_train, y_train) # 树模型通常不需要标准化 y_pred_rf = rf_model.predict(X_test) y_pred_proba_rf = rf_model.predict_proba(X_test)[:, 1] print("准确率:", accuracy_score(y_test, y_pred_rf)) print("\n分类报告:") print(classification_report(y_test, y_pred_rf, target_names=['非ST', 'ST'])) print("AUC分数:", roc_auc_score(y_test, y_pred_proba_rf)) # 6. 模型对比:ROC曲线 fpr_lr, tpr_lr, _ = roc_curve(y_test, y_pred_proba_lr) fpr_rf, tpr_rf, _ = roc_curve(y_test, y_pred_proba_rf) plt.figure(figsize=(8,6)) plt.plot(fpr_lr, tpr_lr, label=f'Logistic Regression (AUC={roc_auc_score(y_test, y_pred_proba_lr):.3f})') plt.plot(fpr_rf, tpr_rf, label=f'Random Forest (AUC={roc_auc_score(y_test, y_pred_proba_rf):.3f})') plt.plot([0, 1], [0, 1], 'k--', label='Random Guess') plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate (Recall)') plt.title('ROC曲线对比') plt.legend() plt.grid(True) plt.show() # 7. 特征重要性分析(随机森林) feature_importance = pd.DataFrame({ 'feature': feature_columns, 'importance': rf_model.feature_importances_ }).sort_values('importance', ascending=False) plt.figure(figsize=(10, 6)) sns.barplot(x='importance', y='feature', data=feature_importance.head(10), palette='viridis') plt.title('随机森林模型特征重要性 Top 10') plt.xlabel('重要性得分') plt.tight_layout() plt.show() print("特征重要性排序:") print(feature_importance)4.5 结果解读与商业洞察
运行完模型后,我们需要解读结果:
- 模型性能:从分类报告和ROC曲线看,随机森林模型在AUC和召回率(对ST类的识别能力)上可能略优于逻辑回归。但逻辑回归的模型更简单,可解释性更强。
- 关键指标解读:
- 精确率:在所有被模型预测为ST的公司中,真正是ST的比例。这个值高,说明模型的“误伤”少。
- 召回率:在所有真实的ST公司中,被模型成功找出来的比例。这个值高,说明模型的“漏网之鱼”少。
- F1-score:精确率和召回率的调和平均数,是综合衡量指标。在我们的不平衡数据集中,关注ST类的F1-score更重要。
- 特征重要性:随机森林显示,
asset_liability_ratio(资产负债率)和roe_capped(净资产收益率)是最重要的两个预测因子。这完全符合财务常识——高负债、低盈利的公司风险更高。profit_margin(是否盈利)也是一个强信号。 - 商业建议:基于模型,可以构建一个初步的财务风险预警系统。对于资产负债率超过70%、ROE连续为负的公司,应予以重点关注。模型给出的预测概率可以作为风险评分,辅助投资决策或内部审计。
5. 常见问题与排查思路
在实践过程中,你可能会遇到以下问题:
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
ImportError: No module named ‘pandas’ | Python环境未安装所需库,或不在正确的环境中。 | 1. 确认已使用pip install pandas安装。2. 如果你使用Anaconda,确认激活了正确的环境 ( conda activate your_env)。3. 在Jupyter中,尝试 !pip install pandas。 |
| 数据读取失败,编码错误 | CSV文件包含中文或特殊字符,默认编码不对。 | 使用pd.read_csv(‘file.csv’, encoding=‘gbk’或’utf-8-sig’)指定编码。 |
| 模型准确率很高(如99%),但召回率为0 | 数据泄露或类别极度不平衡导致模型只会预测多数类。 | 1. 检查特征中是否包含了未来信息或目标变量的直接映射。 2. 使用 class_weight=‘balanced’参数。3. 使用过采样(如SMOTE)或欠采样技术。 |
| 逻辑回归模型不收敛(警告) | 特征尺度差异大,或迭代次数不足。 | 1.务必进行特征标准化(使用StandardScaler)。2. 增加 max_iter参数(如1000或更大)。 |
| 可视化图表中文显示为方框 | matplotlib默认字体不支持中文。 | 在代码开头添加:plt.rcParams[‘font.sans-serif’] = [‘SimHei’]plt.rcParams[‘axes.unicode_minus’] = False |
| 独热编码后特征维度爆炸 | 某个分类特征类别过多(如城市)。 | 1. 考虑将不重要的类别归为“其他”。 2. 使用目标编码等其它编码方式。 |
ValueError: Input contains NaN | 训练数据中存在缺失值。 | 在训练前使用X_train.isnull().sum()检查并处理缺失值。 |
6. 最佳实践与报告撰写建议
完成代码分析只是第一步,将工作整理成一份专业的报告同样重要。
6.1 数据分析最佳实践
- 版本控制:使用Git管理你的代码和Notebook,特别是数据处理步骤,确保结果可复现。
- 函数化与模块化:将数据清洗、特征工程等步骤封装成函数,提高代码可读性和复用性。
- 交叉验证:在最终评估前,使用
cross_val_score进行交叉验证,以获得更稳健的性能估计。 - 处理不平衡数据:除了
class_weight,可以深入研究SMOTE、ADASYN等过采样算法。 - 模型解释:对于逻辑回归,查看系数;对于树模型,使用SHAP或LIME库进行更细致的局部解释。
6.2 期末实践报告撰写结构建议一份好的报告不仅是代码的堆砌,更是逻辑的展现。
- 封面与摘要:标题、姓名、学号、课程、日期。摘要用200-300字概括项目目标、方法、主要发现和结论。
- 引言:阐述研究背景(数据科学在财务领域的应用)、项目意义及核心目标。
- 数据说明:描述数据来源、字段含义、数据规模、初步的质量评估(缺失、异常情况)。
- 方法论:清晰说明采用的数据清洗步骤、特征工程方法、选择的机器学习模型及其原理简介、模型评估指标。
- 实验过程与结果分析:这是核心。
- 数据分析部分:配上关键图表(分布图、散点图、热图),并解释你观察到了什么现象。
- 建模部分:展示模型训练代码(关键部分)、模型在测试集上的性能指标(准确率、精确率、召回率、F1、AUC),最好用表格对比不同模型。
- 结果解释:分析特征重要性,说明哪些财务指标对预测影响最大,并与财务理论相印证。
- 讨论:分析模型的优缺点(如过拟合风险、可解释性)、项目局限性(数据模拟、特征有限)、未来改进方向(引入更多数据、尝试深度学习模型)。
- 结论:总结项目是否达成了最初的目标,并给出基于分析结果的一到两条核心商业建议。
- 参考文献:列出引用的数据来源、算法库文档、相关学术或实践文章。
- 附录:附上完整的、可运行的Jupyter Notebook代码(或提供GitHub链接)。
6.3 代码与报告整合技巧
- 在Jupyter Notebook中,使用Markdown单元格撰写详细的文字分析,将代码、输出结果和文字叙述无缝衔接。
- 将生成的图表保存为高分辨率图片(
plt.savefig(‘images/roe_dist.png’, dpi=300, bbox_inches=‘tight’)),便于插入到最终的Word或PDF报告中。 - 可以使用
nbconvert工具将Notebook直接转换为HTML或PDF报告。
通过这个完整的项目,你不仅掌握了使用Python进行数据分析与机器学习建模的实战技能,更关键的是理解了从商业问题出发,到数据、模型,最终回归商业洞察的完整闭环思维。这套方法论可以迁移到任何你感兴趣的领域,无论是客户流失预测、销售 forecasting 还是风险控制。