
简介面向计算机专业学生的数据仓库与数据挖掘课程作业提供Python实现的银行数据分类与聚类完整源码及实验报告。项目源自大三期末大作业经导师指导并认可评审分99分代码完整可确保运行适合正在完成课程设计或期末大作业的本科生也适合希望练习数据挖掘项目实战的学习者。压缩包共122个文件约11.36MB包含Python脚本、CSV数据表、Word/PDF实验报告、PNG结果图表以及若干Java工程辅助配置其中CSV数据涵盖账户、客户、交易等多维银行数据脚本则覆盖数据预处理、分类与聚类建模、结果可视化等完整环节。已有280人学习下载目录结构清晰便于按模块查阅。实验报告详细记录了数据理解、特征处理、模型选择与评估等设计思路源码注释完整可快速复现运行并调整参数帮助读者系统掌握银行数据分类与聚类的完整流程也可作为课程报告撰写的参考模板。1. 银行数据集上分类与聚类到底在回答什么问题数据仓库与数据挖掘课程作业里Python实现银行数据分类和数据聚类是出现频率最高的组合题之一。它把数据仓库里面向主题、集成、稳定的数据组织方式直接落到一个可跑通的分析流程上从客户表里取数、清洗、编码、标准化再用有监督的分类预测这个客户会不会违约用无监督的聚类回答客户到底能分成哪几类人群。这两件事看着都是sklearn里几行代码的事但作业分数拉开差距的地方从来不在调包而在数据预处理是否规范、评估指标是否选对、实验报告有没有把结论讲清楚。这篇笔记按完整落地路径来写每一步给可复现代码和参数说明哪些地方新手最容易翻车也会单独拉出来讲。适合正在赶这门作业的学生也适合想把sklearn分类聚类全流程走一遍的入门者。2. 数据仓库视角下的银行数据字段选择与预处理方案2.1 从数据仓库到分析数据集为什么不是直接读原表数据仓库和业务库的核心区别在于业务库按事务组织一张订单表、一张账户表更新频繁数据仓库按主题组织把分散在多个业务系统的数据整合成面向分析的结构。课程作业里给的银行数据通常已经是仓库里某个主题的导出结果比如客户主题或者营销活动主题。常见做法是先做一次探索性检查确认数据能不能直接进模型。我会先跑这样一段代码看全貌import pandas as pd df pd.read_csv(bank_data.csv, encodingutf-8) print(df.shape) print(df.dtypes) print(df.head()) print(df.isnull().sum())这段代码四个动作分别回答四个问题shape确认行数列数dtypes看字段类型head看前几行内容isnull().sum()列出每个字段的缺失数量。银行数据里最容易出现的情况是某个字段整列都是空值或者未知这类占位符被读成了字符串这两类问题都要在清洗阶段处理掉而不是留给模型去猜。缺失值占比超过30%的字段我一般直接删掉留着只会给编码和训练添乱。2.2 兴趣字段怎么选分类和聚类各需要什么银行数据的典型字段包括年龄、职业、婚姻状况、教育水平、是否违约、账户余额、是否有住房贷款、是否有个人贷款、联系次数、上次联系间隔天数等。做分类任务时目标字段是明确的比如是否违约或者是否认购定期存款特征就是其余字段做聚类时没有目标字段所有特征都参与距离计算。这里有个新手常犯的错误把唯一标识字段客户ID、日期、电话号码直接送进模型。客户ID是随机编号模型从里面学不到任何规律日期字段如果不转换数值大小会扭曲距离计算。我通常的做法是drop_cols [customer_id, phone, contact_date] df df.drop(columns[c for c in drop_cols if c in df.columns])这个处理对分类和聚类同样适用。数据仓库里字段命名往往冗长先统一改成小写、去空格也是预处理的好习惯后面写代码能少很多低级报错。2.3 缺失值、编码与归一化让树模型和距离模型都不打架文本型字段在银行数据里很常见job、marital、education这些不进模型前必须先转数值。职业这类无序类别用one-hot编码合理教育水平这类有高低之分的字段按程度映射成0、1、2、3比one-hot更好既保留序关系又减少维度爆炸。两种混用是我见过最多的问题。数值字段里年龄和余额的取值范围差异极大。年龄30上下余额可能是几万几十万如果不做标准化聚类时的距离几乎完全被余额主导分类模型里的梯度下降也会收敛得很慢。用StandardScaler做Z-score标准化是默认选择from sklearn.preprocessing import StandardScaler num_cols [age, balance, duration, pdays] scaler StandardScaler() df_scaled df.copy() df_scaled[num_cols] scaler.fit_transform(df[num_cols])注意这里是对整个数据集fit_transform实际建模时标准化必须放到训练集和测试集划分之后再做否则会造成数据泄露。第5章我会单独讲这个翻车点。对于树模型归一化其实不影响结果但如果你同时跑K-Means、KNN这种距离类算法标准化就是必须做的一步否则聚类结果没有意义。2.4 编码后的数据维度控制别让one-hot变成特征灾难职业字段有十来个类别婚姻、教育、住房、贷款各再拆几列一个原本20列的表格one-hot之后可能膨胀到40多列。对课程作业这个量级几千行、几十个特征问题不大但报告里最好提一下类别过多时可以考虑频数编码或目标编码。我一般会统计每个类别字段的唯一值数量超过20个的直接做频数编码——用这个类别出现的次数代替它本身。这样写for col in [job, education]: freq df[col].value_counts() df[col _freq] df[col].map(freq) df df.drop(columns[col])频数编码有个好处类别多但频数分布稳定的字段编码后不会引入大量稀疏列而且保留了这个职业常见与否的信息。缺点是无法表达类别之间的相似性但作为课程作业的数据预处理手段已经足够说明你在思考这个问题。3. 用Python实现银行客户分类逻辑回归、随机森林与KNN的配合3.1 先跑通一个可解释的基线逻辑回归分类任务的第一件事不是直接上随机森林而是先建一个简单模型作为基线。逻辑回归在银行场景中使用极广因为它的输出可以解释成概率业务部门能听懂。代码骨架如下from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler X df.drop(columns[target]) y df[target] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) model LogisticRegression(max_iter1000, C1.0, class_weightbalanced) model.fit(X_train_scaled, y_train)逻辑回归核心参数max_iter用来控制迭代次数数据标准化后通常几百次就能收敛给到1000是防意外C是正则化强度的倒数C越小正则越强默认为1如果特征数量多或共线性明显可以调小C试效果class_weightbalanced会根据类别频数自动加权解决银行数据里常见的正负样本不均衡问题——违约客户永远是少数。标准化用fit_transform和transform分开处理这是铁律。fit_transform在训练集上拟合并转换transform在测试集上只用训练集的均值和方差做转换避免测试集信息泄漏进训练过程。3.2 随机森林特征重要性能写进报告逻辑回归跑通之后随机森林是第二梯队。它不需要标准化、能捕捉非线性关系、还自带特征重要性排序实验报告里放一张特征重要性柱状图比写几百字描述都有说服力。from sklearn.ensemble import RandomForestClassifier rf RandomForestClassifier( n_estimators200, max_depth8, min_samples_leaf5, random_state42, class_weightbalanced, n_jobs-1 ) rf.fit(X_train, y_train) importance pd.Series(rf.feature_importances_, indexX.columns).sort_values(ascendingFalse) print(importance.head(10))参数选择逻辑n_estimators在100到300之间性价比最高超过300收益很小还拖慢速度max_depth限制在8左右是防止树过深过拟合银行数据特征量不大深度太大纯属浪费min_samples_leaf5要求叶子节点至少5个样本再分裂这也是常见做法能让模型更稳。n_jobs-1表示用满所有CPU核心课程作业的数据量小不设也行但养成习惯没坏处。特征重要性输出后检查一下排名靠前的特征是否符合业务直觉。比如是否违约历史上就是最重要的特征说明模型学到的东西和数据仓库里沉淀的业务规律一致如果客户ID这种特征排第一那一定是预处理环节出了问题返回2.2节检查。3.3 KNN距离类模型的参数陷阱KNN在银行分类里通常不是主力但作业要求里经常出现因为它和后面的聚类共用一套距离计算逻辑。KNN的核心参数就两个n_neighbors和weights。from sklearn.neighbors import KNeighborsClassifier knn KNeighborsClassifier(n_neighbors5, weightsdistance, p2) knn.fit(X_train_scaled, y_train)n_neighbors5是默认值但5不是万能答案。数据集小的场景k太小容易受噪声点影响k太大又会把远处样本拉进来。我用的是交叉验证选k通常5到15之间取最优。weightsdistance的意思是距离近的邻居投票权重更大比默认的uniform等权投票在类别不均衡时稍好一点。p2表示欧氏距离如果特征做了标准化欧氏距离是合理的默认选择如果某些字段仍然量纲差异大考虑p1的曼哈顿距离会更稳。KNN必须用标准化后的数据这一点比逻辑回归更严格。没标准化的KNN余额字段会完全主导距离计算其他字段全被淹没参数调得再好也白搭。3.4 评估指标的选择准确率在银行分类里会骗人银行分类任务里违约客户往往只占5%左右甚至更低。如果模型把所有客户都预测为不违约准确率也有95%看起来很好看但这个模型一点用没有。所以准确率不是唯一指标甚至不是主要指标。至少要看精确率、召回率、F1分数和AUCfrom sklearn.metrics import classification_report, roc_auc_score print(classification_report(y_test, rf.predict(X_test))) print(AUC:, roc_auc_score(y_test, rf.predict_proba(X_test)[:, 1]))分类报告直接给出Precision、Recall、F1-score以违约类为准判断模型好坏。AUC用预测概率计算衡量模型把正样本排在负样本前面的能力0.8以上基本可用。课程作业实验报告里写这样一段结论随机森林在违约客户识别上召回率0.72高于逻辑回归的0.65而精确率略低说明随机森林更倾向于多抓出违约客户代价是误报多一些——这种对比分析就是拿高分的关键。4. 用Python实现银行数据聚类K-Means与轮廓系数的实战组合4.1 聚类在银行场景里解决什么问题聚类不需要标签它的目标是把客户分成若干群体让同一个群体内部相似、不同群体差异明显。银行里最常见的应用是客户分群和客群价值分层把客户按资产规模、交易行为、产品持有情况分成几类再对每一类设计不同的营销策略和管理方式。课程作业里做聚类本质上是复现这个分析过程。聚类算法的选型上K-Means是作业和入门项目的事实标准简单、快、好解释。缺点是要提前定k值对初始质心敏感。选它做课程作业理由充分如果能提到DBSCAN可以处理任意形状簇和噪声点作为对比讨论就更好了。4.2 K-Means实现步骤与k值选择的两个依据先把特征数据准备好这一节用和分类任务相同但删掉目标标签的预处理流程保证特征口径一致后面才好对比分析。from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score X_cluster df_scaled.drop(columns[target]) k_range range(2, 9) inertias [] silhouettes [] for k in k_range: km KMeans(n_clustersk, initk-means, n_init10, random_state42) labels km.fit_predict(X_cluster) inertias.append(km.inertia_) silhouettes.append(silhouette_score(X_cluster, labels))这里同时计算两类指标inertia是簇内平方和每个样本到它所属簇质心的距离平方之和越小说明簇内越紧凑silhouette_score是轮廓系数范围负一到一越接近1说明样本离近邻簇越远、分类越清晰。K-Means的k值选择有一定玄学成分但两个指标配合起来基本能给出合理区间。inertia绘成折线图后找肘部——曲线从陡降变平缓的拐点这个k就是自然的聚类数。轮廓系数则直接取最大值对应的k。两个方法结论一致时这个k值基本稳了不一致时以轮廓系数为准因为它更能反映簇与簇之间是否真的分得开。4.3 聚类结果的可视化与业务解释聚类结果光有数值指标不够实验报告里要能讲清楚每一类是谁。常见做法是用PCA或TSNE降维到二维平面然后把簇标签作为颜色画散点图。代码from sklearn.decomposition import PCA pca PCA(n_components2) coords pca.fit_transform(X_cluster) plt.scatter(coords[:, 0], coords[:, 1], clabels, cmapviridis, alpha0.6) plt.xlabel(PC1) plt.ylabel(PC2) plt.show()然后再进一步聚合出每个簇的特征均值用于业务解读cluster_profile df_scaled.groupby(cluster).mean()用这个结果就能描述簇0客户平均年龄偏大、余额中等、贷款比例低可以定位为成熟稳健型客群簇1余额高、负债低、联系次数少适合做大额理财推荐。每一类都有画像、有对应的业务动作聚类作业才算是闭环了。只贴代码不接业务解释大体上只能拿到基础分。5. 课程作业避坑从源码到实验报告的五个常见问题5.1 现象sklearn版本升级后KMeans莫名其妙报错我在本机跑旧代码时遇到KMeans提示n_init参数即将被移除的警告新版本里如果不显式写n_init默认行为也会变。同样的问题还出现在LogisticRegression的solver参数上新版默认从liblinear换成了lbfgs。原因sklearn在1.4之后调整了部分算法默认参数旧的写法虽然兼容但会告警未来版本可能直接报错。解决在代码里显式写下所有关键参数包括n_init10、initk-means、max_iter1000这些不要依赖默认值。这也能让实验报告的参数说明更有内容。5.2 现象聚类结果和分类结果完全对不上报告没法写我见过不少同学先把分类模型跑好了再用同样的特征做聚类结果聚出来的簇和分类标签一点关系都没有然后卡在这两部分怎么串起来这一步。原因分类用的是有标签数据目标是找决策边界聚类用的是无标签数据目标是找距离结构。两者优化目标不同结果不一致是正常的。解决实验报告里不要强行让聚类结果匹配分类标签。正确的写法是把聚类当作分类之前的探索性分析先聚类发现客群结构再结合标签看每一簇里违约率的差异——如果某簇违约率明显高于其他簇说明这个簇本身就是一个高风险客群分类模型也会赋予它较高的违约概率。这样就把两部分串成一个完整故事了。5.3 现象标准化写在了数据划分之前模型分数虚高某次作业里随机森林的AUC到了0.97远超合理范围检查代码发现StandardScaler的fit_transform在train_test_split之前执行测试集的信息已经参与了训练数据的标准化过程相当于提前偷看了答案。原因数据泄露。标准化统计的是整个数据集的均值和方差测试集的分布信息混进了训练集的转换过程模型相当于在训练时见过测试集的分布形态。解决严格按2.2节的方式先用fit_transform处理训练集再用训练集的scaler.transform测试集。逻辑回归、KNN、SVM这类距离敏感的算法尤其要注意树模型虽然不依赖标准化但这个流程要养成习惯。5.4 现象类别人数和缺失情况都不一样模型却用成同一个配置银行数据里正负样本不平衡这个坑翻车概率最高。某份作业里y值分布是98%不违约、2%违约同学直接拿原始数据训练模型把所有人都预测为不违约准确率有98%报告里还写了模型效果很好。原因没有做类别不平衡处理准确率被多数类主导。解决第一在train_test_split里加stratifyy让训练测试集的类别比例保持一致第二模型里加class_weightbalanced或手动对少数类过采样第三评估时不看准确率看召回率和AUC。银行场景里漏掉一个违约客户的代价比多拦下一个正常客户更大这就是为什么召回率比准确率重要。5.5 现象实验报告的图表中文全部变成方块matplotlib默认字体不支持中文plt.title(聚类结果)画出来全是方块图表没法看格式分直接扣掉。原因matplotlib没有配置中文字体。解决绘图前加两行配置plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalseSimHei在Windows和大多数Linux发行版都能用。如果环境里没装先fc-list查可用中文字体换成Noto Sans CJK SC之类的名称。配置在绘图脚本开头执行一次即可别在每个绘图函数里重复写。6. 让作业变成可复现的分析项目三个收尾技巧课程作业如果只是把代码跑通、结果截图、报告交上去同龄人之间拉不开差距。我会在收尾阶段多花半小时做三件小事让整份作业可以被任何人一键复现。第一固定随机种子。把random_state42统一写进train_test_split、KMeans、RandomForest等所有带随机性的函数里并且在报告开头注明实验中所有随机种子固定为42以保证可复现。这样老师复跑你的代码结果和你报告里贴的数字一致不会出现怎么我跑出来的数和你不一眼的尴尬。第二把结果落盘。分类的预测结果、概率、聚类的簇标签、每个簇的特征均值统一用to_csv或to_excel导出一份结果文件。这个步骤的价值在于实验报告里的每一个数字都能追溯到一行数据。我习惯建一个output文件夹Results.csv放预测结果ClusterProfile.csv放聚类画像报告里所有的图表都从这两个文件生成。第三报告的结构按照业务问题—数据处理—实验设计—结果分析—结论的顺序写先写一句核心结论再展开过程和代码。老师看报告最烦的就是从头到尾看不到一句带判断的话。你写上随机森林在违约客户识别上的召回率显著优于逻辑回归适合作为该场景的备选模型这类明确判断再附上数据支撑报告评分立刻上一个档次。这套流程走下来作业本身是一份完整的分析报告代码也具备了被别人复用的基础。我自己做任何小型数据分析项目都沿用这个习惯固定种子、落盘结果、先写结论再补过程省掉了大量返工时间。希望帮到你。本文还有配套的精品资源点击获取