ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

银行数据分类与聚类Python源码:从预处理到建模的完整数据挖掘实战

银行数据分类与聚类Python源码:从预处理到建模的完整数据挖掘实战 简介这份资源是数据仓库与数据挖掘课程的期末大作业完整交付包面向计算机相关专业正在做课程设计或项目实战的学生尤其适合需要参考银行数据分类与聚类完整实现的学习者。包内共122个文件以Python源码、CSV数据集、Java文件、实验报告文档及图表为主另含SSAS多维数据集相关工程文件压缩包约11.36MB目录结构清晰便于按模块查阅。资源围绕银行客户数据展开涵盖数据预处理、分类建模与聚类分析等典型数据挖掘流程配套实验报告可帮助理解算法选型与结果解读。该作业经导师指导并获评审99分代码完整可运行对新手较为友好。目前已有280人学习下载可作为课程设计、期末大作业的参考范例帮助读者快速搭建实验框架、对照实现细节并完成自己的项目。1. 银行数据分类与聚类这套源码到底能帮你省下多少返工时间大三那会儿做数据仓库与数据挖掘的期末大作业最怕的不是算法不会而是数据对不上、环境跑不通、报告写不圆。这套 Python 实现的银行数据分类和数据聚类源码配了一份经导师认可的实验报告评审分 99核心价值不在于算法多高深而在于它把「数据预处理 → 分类建模 → 聚类分析 → 结果可视化」这条链路完整跑通了而且代码结构清晰到小白能直接照着复现。它适合正在做课程设计、期末大作业的计算机相关专业学生也适合想拿一个真实业务场景练手数据挖掘流程的入门者。银行客户数据本身带有典型的分类标签和聚类特征拿它来理解数据仓库的 ETL 思路和数据挖掘的建模套路比用鸢尾花数据集更有说服力。下面我按实际拆包和跑通的顺序把这份资源的技术细节、参数设置和踩坑点讲清楚。2. 拆开源码包文件结构与数据管线的真实面貌2.1 目录里每个文件在管线中的角色拿到压缩包解压后根目录下能看到这些文件AccoutAnalytic.asdatabase、AccoutAnalytic.configsettings、trans_new.csv、trans.csv、Frogs_MFCCs.csv、order_new.csv、order.csv、account_new.csv、account.csv、client_new.csv。注意AccoutAnalytic这个拼写原文就是如此不是笔误配置文件和数据库文件都沿用了这个命名改的时候要全局统一否则脚本读配置会报路径找不到。从数据管线的角度看这些文件分成三层。第一层是原始数据层account.csv、client_new.csv、order.csv、trans.csv分别对应银行账户信息、客户信息、订单流水和交易记录这是数据仓库里典型的ODS操作数据存储层素材。第二层是清洗后的数据层带_new后缀的account_new.csv、order_new.csv、trans_new.csv是经过缺失值处理、字段对齐、类型转换之后的中间结果。第三层是配置与元数据层AccoutAnalytic.configsettings存放数据库连接参数和文件路径映射AccoutAnalytic.asdatabase是项目自带的轻量级数据库文件用来模拟数据仓库的存储结构。Frogs_MFCCs.csv是一个额外的音频特征数据集通常用于聚类算法的对比实验说明这份作业在聚类部分做了多数据集验证不是只跑一个银行数据就交差。注意_new后缀的文件不要手动改名脚本里大概率是硬编码读取的改了就得同步改代码里的路径字符串。2.2 数据仓库建模思路与配置文件的参数含义这份作业的亮点在于它没有直接把 CSV 丢给 sklearn而是先走了一遍数据仓库的建模流程。AccoutAnalytic.configsettings这个配置文件是整条管线的入口里面通常包含数据库文件路径、表名映射、字段类型定义和缺失值填充策略。我一般会先打开这个文件确认三件事数据库文件的实际路径是否和当前解压目录一致、CSV 文件的编码格式是 UTF-8 还是 GBK、分类目标字段的名称是什么。配置文件的典型结构如下不同版本可能字段名有差异但逻辑一致[database] db_file AccoutAnalytic.asdatabase table_account account_new table_client client_new table_order order_new table_trans trans_new [preprocessing] missing_strategy mean encode_method label target_column credit_rating [model] classifier random_forest n_estimators 100 max_depth 8 test_size 0.3 random_state 42missing_strategy控制数值型缺失值的填充方式常见取值有mean、median、drop。银行数据里账户余额和交易金额的缺失值用均值填充是常规操作但如果缺失比例超过 30%建议改成drop否则填充出来的数据会引入偏差。encode_method决定分类变量的编码方式label是标签编码适合有序分类如果遇到客户职业、地区这类无序分类要改成onehot不然模型会误以为类别之间有大小关系。target_column是分类任务的目标字段这份作业里通常是信用评级或客户等级。n_estimators和max_depth是随机森林的核心超参数100 棵树配 8 层深度在几百到几千条银行数据上比较稳数据量再大就适当增加树的数量但别超过 300否则训练时间翻倍而精度提升有限。2.3 从 CSV 到建模数据加载与预处理的可复现步骤跑通这份源码的第一步不是急着python main.py而是先确认环境依赖。常见做法是建一个虚拟环境然后装 pandas、numpy、scikit-learn、matplotlib、seaborn 这几个库。Python 3.8 及以上都行但注意 scikit-learn 版本别低于 0.24否则RandomForestClassifier的某些参数名对不上。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pandas numpy scikit-learn matplotlib seaborn装完依赖后先单独跑一遍数据加载脚本确认 CSV 能正常读进来。下面这段代码是我从源码里提炼出来的核心预处理逻辑和原项目的实现思路一致import pandas as pd import numpy as np from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split # 读取清洗后的账户数据 account pd.read_csv(account_new.csv, encodingutf-8) client pd.read_csv(client_new.csv, encodingutf-8) # 合并账户与客户信息模拟数据仓库的宽表构建 df pd.merge(account, client, onclient_id, howleft) # 缺失值处理数值列用中位数填充分类列用众数填充 num_cols df.select_dtypes(include[np.number]).columns cat_cols df.select_dtypes(include[object]).columns for col in num_cols: df[col] df[col].fillna(df[col].median()) for col in cat_cols: df[col] df[col].fillna(df[col].mode()[0]) # 分类变量编码 le LabelEncoder() for col in cat_cols: if col ! credit_rating: # 目标列单独处理 df[col] le.fit_transform(df[col].astype(str)) # 划分特征与标签 X df.drop(columns[credit_rating, client_id]) y df[credit_rating] # 分层抽样划分训练集与测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy )这段代码的关键点有三个。第一pd.merge的howleft保证了账户表为主表客户信息缺失时不会丢记录这在银行场景里很重要因为账户是核心实体。第二数值列用中位数而不是均值填充是因为银行交易金额和余额往往有极端值均值会被拉偏中位数更稳健。第三stratifyy在划分数据集时保持了类别比例如果信用评级里好客户占 80%、差客户占 20%不分层的话测试集里可能一个差客户都没有评估结果就失真了。提示如果读 CSV 时报UnicodeDecodeError把encodingutf-8改成encodinggbk再试国内课程作业的数据文件用 GBK 编码的概率不低。3. 分类模型怎么选、怎么调、怎么验证3.1 随机森林与逻辑回归的选型对比源码里分类部分默认用的是随机森林这不是随便选的。银行数据分类任务通常有几个特点特征维度中等十几个到几十个字段、样本量不大几千条、存在非线性关系收入与信用评级不是简单线性、类别可能不平衡。随机森林对缺失值和非线性关系容忍度高不用做特征缩放还能输出特征重要性方便写实验报告时分析哪些字段对分类影响大。逻辑回归的优势在于可解释性强系数直接反映特征影响方向但需要先做标准化而且对非线性关系拟合能力弱。我一般会两个都跑一遍做对比实验报告里放一张对比表评审老师看到你有选型思考分数不会低。下面是两个模型的训练与评估代码from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.metrics import classification_report, confusion_matrix, accuracy_score # 随机森林不需要标准化直接训练 rf RandomForestClassifier( n_estimators100, max_depth8, min_samples_split5, min_samples_leaf2, random_state42, class_weightbalanced # 类别不平衡时自动调整权重 ) rf.fit(X_train, y_train) rf_pred rf.predict(X_test) # 逻辑回归先标准化再训练 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) lr LogisticRegression( C1.0, max_iter1000, random_state42, class_weightbalanced ) lr.fit(X_train_scaled, y_train) lr_pred lr.predict(X_test_scaled) # 输出评估结果 print(随机森林准确率:, accuracy_score(y_test, rf_pred)) print(classification_report(y_test, rf_pred)) print(逻辑回归准确率:, accuracy_score(y_test, lr_pred)) print(classification_report(y_test, lr_pred))class_weightbalanced这个参数在银行数据里很关键。如果好客户和差客户的比例是 9:1不加这个参数模型会把所有样本都预测成好客户准确率看起来有 90%但差客户一个都没识别出来混淆矩阵里召回率惨不忍睹。加上之后模型会自动给少数类更高的权重召回率能明显改善。min_samples_split5和min_samples_leaf2是防止过拟合的常规设置数据量小的时候别把树养得太深。3.2 聚类部分K-Means 与层次聚类的参数设置聚类部分源码里用的是 K-Means配合手肘法确定簇数量。银行客户分群是聚类最典型的应用场景比如把客户分成高价值、潜力、流失风险几类。K-Means 的优点是快、好解释缺点是必须提前指定 K 值而且对初始中心敏感。源码里应该用了n_init10来跑多次初始化取最优这个参数在 scikit-learn 0.24 之后默认就是 10但显式写出来更清楚。from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score import matplotlib.pyplot as plt # 手肘法确定最佳簇数 inertia [] silhouette [] K_range range(2, 11) for k in K_range: kmeans KMeans(n_clustersk, n_init10, random_state42) kmeans.fit(X_train_scaled) inertia.append(kmeans.inertia_) silhouette.append(silhouette_score(X_train_scaled, kmeans.labels_)) # 绘制手肘图与轮廓系数图 fig, ax1 plt.subplots(figsize(10, 5)) ax1.plot(K_range, inertia, bo-, labelInertia) ax1.set_xlabel(簇数量 K) ax1.set_ylabel(簇内平方和, colorb) ax2 ax1.twinx() ax2.plot(K_range, silhouette, rs-, labelSilhouette) ax2.set_ylabel(轮廓系数, colorr) plt.title(手肘法与轮廓系数确定最佳 K 值) plt.show()手肘法看的是inertia_下降曲线的拐点轮廓系数看的是峰值。两个指标有时候不一致我一般以轮廓系数为主手肘法为辅。银行客户数据如果分 3 到 5 类比较合理超过 5 类就不好给业务方解释了。n_init10表示用不同的随机中心跑 10 次取 SSE 最小的那次结果能有效避免陷入局部最优。3.3 分类与聚类的评估指标怎么看分类任务的评估不能只看准确率。银行数据里如果正负样本比例是 8:2一个把所有样本都预测为正类的模型准确率也有 80%但没有任何实用价值。要看classification_report里的 precision、recall 和 f1-score。precision 高说明预测为正的样本里真正为正的比例高recall 高说明真正的正样本被找出来的比例高。如果业务目标是找出潜在违约客户recall 比 precision 更重要因为漏掉一个违约客户的代价远大于误判一个正常客户。聚类任务的评估更玄学一些因为没有真实标签。轮廓系数越接近 1 越好但超过 0.7 在真实数据上很少见一般 0.4 到 0.6 就算不错了。另外可以看簇内平方和inertia但它的绝对值没有意义只能用来对比不同 K 值下的相对变化。实验报告里最好把每个簇的中心点列出来解释每个簇代表什么类型的客户这样才有业务含义。4. 跑通源码时最容易翻车的几个地方4.1 编码与路径问题导致 CSV 读不进来现象运行脚本时报FileNotFoundError或UnicodeDecodeError明明文件就在目录里。原因一是配置文件里的路径是相对路径但脚本的工作目录不是项目根目录二是 CSV 文件编码是 GBK代码里写死了 UTF-8。解决在脚本开头加import os; os.chdir(os.path.dirname(os.path.abspath(__file__)))强制切换工作目录。读 CSV 时用encodingutf-8先试报错就换encodinggbk或者用chardet库自动检测编码。4.2 字段名拼写不一致导致 merge 后数据为空现象pd.merge之后 DataFrame 行数变成 0或者大量字段变成 NaN。原因account_new.csv里的客户 ID 字段叫client_idclient_new.csv里叫clientid或者ClientID大小写和下划线不一致。解决merge 之前先打印两个表的columns列表确认关联字段名完全一致。不一致就用df.rename(columns{clientid: client_id})统一。另外检查关联字段的数据类型一个是 int 一个是 str 也会导致匹配失败。4.3 类别不平衡导致模型只预测多数类现象分类报告里多数类的 recall 接近 1少数类 recall 接近 0整体准确率看着还行。原因没有设置class_weightbalanced或者用了准确率作为唯一评估指标。解决训练时加上class_weightbalanced评估时重点看少数类的 recall 和 f1-score。如果少数类样本实在太少少于 50 条考虑用 SMOTE 过采样但要注意只在训练集上做测试集保持原始分布。4.4 聚类前没做标准化导致某个字段主导距离计算现象聚类结果里某个簇的客户全部是收入极高的其他特征完全看不出差异。原因K-Means 基于欧氏距离如果收入字段的范围是 0 到 100000而年龄字段是 18 到 65收入对距离的贡献远大于年龄聚类结果自然被收入主导。解决聚类前必须做标准化用StandardScaler或MinMaxScaler。标准化之后所有字段的均值为 0、方差为 1距离计算才公平。注意标准化参数只能从训练集 fit然后 transform 测试集不能全量数据一起 fit否则会引入数据泄露。4.5 随机种子没固定导致每次跑的结果不一样现象同样的代码跑两次准确率差了 3 到 5 个百分点实验报告里的数字对不上。原因train_test_split、RandomForestClassifier、KMeans都有随机性没设random_state每次结果都不同。解决所有涉及随机的函数都加上random_state42包括数据划分、模型初始化、聚类初始化。这样别人复现你的结果时数字能对上写报告也省心。5. 把实验报告写扎实的两个进阶技巧5.1 用特征重要性反推业务解释随机森林训练完之后rf.feature_importances_能直接给出每个特征的重要性排序。把这个结果和字段名对应起来画一张水平条形图实验报告里就有了「哪些因素最影响信用评级」的量化依据。我一般会取前 10 个重要特征在报告里逐个解释业务含义比如交易频率高但账户余额低可能意味着资金快进快出风险较高。这一步能把纯技术作业拉高到有业务洞察的层次评审老师很吃这一套。import pandas as pd import matplotlib.pyplot as plt # 提取特征重要性并排序 importance pd.Series(rf.feature_importances_, indexX.columns) importance importance.sort_values(ascendingTrue).tail(10) plt.figure(figsize(8, 6)) importance.plot(kindbarh, colorsteelblue) plt.xlabel(重要性得分) plt.title(随机森林特征重要性 Top 10) plt.tight_layout() plt.savefig(feature_importance.png, dpi150) plt.show()保存图片时dpi150足够报告打印用再高文件太大没必要。tight_layout()防止标签被截断这个细节很多人忽略结果图里字段名显示不全。5.2 用轮廓系数曲线验证聚类稳定性除了手肘法我习惯再跑一条轮廓系数随 K 值变化的曲线两条曲线叠在一起看。如果某个 K 值下轮廓系数明显高于相邻值而且手肘法的拐点也在这个位置附近那这个 K 就比较可信。另外可以跑几次不同随机种子下的 K-Means看聚类标签的稳定性如果每次分出来的簇结构差异很大说明数据本身没有明显的聚类结构强行分群意义不大。from sklearn.metrics import silhouette_samples import numpy as np # 选定 K4 后查看每个样本的轮廓系数分布 kmeans_final KMeans(n_clusters4, n_init10, random_state42) labels kmeans_final.fit_predict(X_train_scaled) sil_vals silhouette_samples(X_train_scaled, labels) # 按簇绘制轮廓系数分布 y_lower 10 for i in range(4): cluster_sil np.sort(sil_vals[labels i]) size_cluster cluster_sil.shape[0] y_upper y_lower size_cluster plt.fill_betweenx(np.arange(y_lower, y_upper), 0, cluster_sil, alpha0.7) plt.text(-0.05, y_lower 0.5 * size_cluster, str(i)) y_lower y_upper 10 plt.axvline(xsil_vals.mean(), colorred, linestyle--, label平均轮廓系数) plt.xlabel(轮廓系数) plt.ylabel(簇标签) plt.title(各簇轮廓系数分布) plt.legend() plt.show()如果某个簇的轮廓系数大量为负说明这个簇的样本更适合归到别的簇K 值可能偏大。银行客户分群一般 3 到 4 类比较稳分到 6 类以上就会出现大量负轮廓系数报告里不好解释。从那以后我每次跑完分类或聚类都会先把random_state固定、把标准化流程检查一遍、把评估指标从准确率扩展到 recall 和 f1这三步走完再写报告返工次数少了很多。希望这套源码和上面的参数说明能帮你顺利交上一份不心虚的期末大作业。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进