27届计算机毕设源码基于多维特征融合的互联网贷款客户聚类与风险预警研究我27届毕业设计做的是这个题目“基于多维特征融合的互联网贷款客户聚类与风险预警研究”后来又延伸出了一个方向“基于数据挖掘的互联网贷款用途与风险定价可视化研究”。很多学弟学妹在选毕设题目的时候会纠结这个题到底难不难、怎么做、能不能有源码参考。我的建议是——这个方向确实值得做因为它的数据源规范、算法链条完整、可视化效果好而且跟当下互联网金融风控的实际业务结合得很紧。这篇文章把我从开题到最后答辩的完整思路、技术选型、实操步骤和踩过的坑都整理出来希望能给正在做同类题目的同学一点参考。这个项目的核心是以客户多维特征为基础先用聚类算法把互联网贷款客户划分成不同的群体然后针对每个群体的违约特征做风险预警最后用数据挖掘的结果驱动贷款用途分析和风险定价整个过程用可视化大屏展示成果。说白了就是让贷款平台能回答三个问题客户是谁、风险多大、该怎么定价。因为内容偏应用型整个项目的难易程度对本科毕设来说是刚刚好的——算法不劝退、代码量足够证明工作量、可视化又能拉高整体答辩的观感分。如果你正在做“客户聚类”、“风险预测”、“Python数据分析与可视化”方向这篇内容可以直接对应到你的技术栈和开发节奏。1. 项目整体设计与需求拆解1.1 核心需求与切入点先说这个题目到底在解决什么问题。互联网贷款平台比如消费金融、小贷产品、银行线上信贷最大的痛点只有一个不知道借款的人是谁也不知道借了钱之后会干什么。传统的线下风控主要靠人工审核和征信报告但互联网贷款完全线上化客群覆盖面大、数据维度杂、单笔金额小靠人工根本不现实。所以“客户聚类”解决的是客群分层问题“风险预警”解决的是坏账预测问题而“贷款用途与风险定价”是把这两部分的结果变成业务决策——告诉平台这笔钱借给谁、利率定在多少、需要不需要人工介入。放到毕设语境里我把它拆成了四个模块数据采集与清洗——拿到一份结构合理、字段完整的模拟贷款数据集多维特征融合——把用户的基础信息、行为数据、借贷历史组合成可用特征聚类分析与风险预警——用无监督学习分组用有监督学习预测风险可视化展示——把聚类结果、风险分布、贷款用途、定价区间呈现到Web大屏1.2 为什么选择多维特征融合与聚类这个技术路线这一点在开题答辩时一定会被问到你把理由理清楚一组题目就立得住。多维特征融合的本质是单一维度的特征无法描述一个复杂的人。比如只看收入年收入50万的个体户可能不敢借5万因为资金全压在货上收入10万的打工人反而更敢借因为工资稳定可预期。只看历史借款次数也不行多借不等于高风险还要看还款行为、间隔时间、用途等等。聚类在这个场景里的好处是不需要标注数据。征信样本里真正的违约客户比例是很低的好客户可能占95%以上如果你一上来就做有监督分类正负样本极度不均衡训练效果通常很差。而聚类不用标签直接把客户按特征相似度分成几群每个群的违约率、行为偏好一目了然在早期风控里是非常实用的客群划分手段。所以说这个项目的组合逻辑是无监督负责看清客群结构有监督负责落地风险预测可视化负责把模型结果翻译成人话。三条线互不冲突又互相支撑答辩时很好讲。1.3 数据集设计与模拟方案校招毕设最大的麻烦在于真实贷款数据拿不到。我当时的做法是自建模拟数据集然后用人工“注入”违约模式让数据看起来更接近真实。模拟数据字段设计如下特征类别字段举例说明基础属性年龄、性别、城市等级、学历客户画像底层数据收入资产月收入、公积金基数、房产车辆标志还款能力的核心描述借贷行为借款金额、期限、利率、历史借款次数平台最关心的行为记录还款表现历史逾期天数、当前逾期次数、还款间隔风险判别的主要依据消费行为消费频率、大额支出占比、夜间消费比例贷款用途推断的辅助维度模拟数据的生成逻辑我用的是“正态分布 人为规则”。比如月收入取均值为1.2万、标准差为6000的正态分布然后把收入低于5000且借款金额大于3万的样本赋予更高的初始逾期概率。这样生成出的数据虽然纯属模拟但特征之间的相关方向是对的聚类模型和风险模型跑出来的结果也有业务解释力。提示如果你用的是公开的信贷数据集比如Kaggle上的German Credit、Lending Club Loan Data注意字段含义与国内语境差异建议在报告中说明数据来源和处理方式避免答辩被追问时答不上来。2. 技术架构、算法选型与工具链2.1 整体技术栈选型与分工项目的技术栈划分得很简单主语言就是Python辅助Web展示用了HTML ECharts。模块技术选型负责内容数据处理Pandas、NumPy、Scikit-learn清洗、归一化、特征工程聚类模型K-Means、层次聚类AgglomerativeClustering客群划分风险预警逻辑回归、XGBoost、LightGBM违约概率预测可视化分析Flask后端 ECharts前端大数据屏展示数据探索Matplotlib、Seaborn前期EDA分析与论文配图选择这套组合的原因很现实Python生态对数据挖掘的支持最成熟Sklearn一行代码就能跑通K-MeansXGBoost和LightGBM直接用pip装就能跑ECharts做出来的可视化比Matplotlib好看一个数量级而且不依赖付费BI工具全是免费开源。2.2 聚类算法选型K-Means vs 层次聚类做客户聚类最终目标不是算法复杂度而是“分出来的群体能不能解释”。我当时对比了两种方法K-Means运行速度快、超参少、适合大数据量但需要提前指定K值且对初始质心和离群点敏感。对于10万条以内的数据量性能完全够用。层次聚类AgglomerativeClustering不需要预设K值可以通过树状图观察聚类结果更稳定。缺点是计算复杂度高样本量大了之后内存占用会急剧上升在Python里超过3万条就不太建议直接用。我的做法是先用层次聚类对一小批样本1万条做树状图确定大致的分群数量再用K-Means把全部数据分群。这是实践里很常见的“混合策略”抽样1万条 → 层次聚类 → 画树状图 → 确定K的范围用轮廓系数Silhouette Score和SSE簇内平方和交叉验证选K用K-Means跑全量数据输出中心点与分群结果2.3 聚类效果评估指标很多同学分完类就完事了答辩时被问“你这个聚类结果怎么评价好坏”就答不上来了。这里我整理了几个常用指标轮廓系数Silhouette Score值域[-1,1]越大说明样本越贴近自己的簇而远离其他的簇。一般超过0.25就可以接受0.4以上说明聚类效果不错。这个在Sklearn里一行代码算出来。SSE簇内平方和每个点到所属簇中心的距离平方和。选K的时候画肘部曲线看拐点。SSE下降得越快说明增加簇带来的收益越大下降变平缓后继续增加K的意义就不大了。业务可解释性这是我最强调的也是论文里单独拿出一个章节写的。分出来的每个群要能命名、能描述。比如“高薪短借客户”“低收长借高危客群”“稳定消费型客户”等等。如果群里的特征分布乱成一锅粥指标再高也没有落地价值。我当时选K5最终呈现的分群画像大概是客群标签占比核心特征A群白领短借群32%中高收入、借款金额小、期限短、历史逾期少B群小微经营群18%收入波动大、借款频率高、金额中等、笔数多C群高收入低风险群22%高收入高学历、资产丰富、还款极规律D群高风险长借群15%低收入、借款金额大、期限长、历史逾期明显E群消费主力群13%中收入、消费行为活跃、借款用途偏向购物和旅游每个群的画像靠的是把聚类结果对应回原始特征的均值、众数做的统计汇总。这一步不复杂但很关键它是后续风险定价和可视化的基础。2.4 数据挖掘与风险建模的衔接聚类做好了怎么往风险预警上走我当时的思路是把所有客户先分群再把每个群内的数据打上“是否逾期”的标签以“逾期天数15”为坏客户定义。然后用标签训练一个二分类模型预测客户的违约概率。这个概率同时输出为风险评分0-100分映射规则可以简单定义为风险评分 round(100 - 违约概率*100)也可用逻辑回归的系数做更规范的分数换算。比较讨巧的是模型里可以加入“所属聚类簇编号”作为特征让聚类结果反哺有监督模型。比如D群客户的风险权重天然就高模型会自动学到“处于这个簇的客户违约概率要上调”。这一步让你的项目在逻辑上形成闭环论文里也很好画框图。3. 实操实现从数据清洗到可视化大屏3.1 数据清洗与预处理第一件事永远是看数据长什么样。运行df.info()、df.describe()、df.isnull().sum()把字段类型、缺失值、异常值摸个底。我的数据集是自建的缺失值不多但有几类处理思路必须记录下来连续特征做缺失值填补。分三类均值填充适用于近似正态分布的字段比如收入、中位数填充适合右偏分布如借款金额、按分组填充比如同一城市等级下取该组的均值作为缺省值。不要一股脑都用均值填充答辩时被问到“为什么这里用中位数不用均值”你要能说出分布形态的道理。分类特征做编码。学历、城市等级、职业类型这类字段要转成数值。可以用LabelEncoder或pd.get_dummies()。注意如果你后续要做逻辑回归尽量用One-Hot编码避免把类别之间的等级性质硬编码进去如果用树模型LabelEncoder问题不大。异常值处理。对连续特征用IQR法做截尾Q1 - 1.5*IQR和Q3 1.5*IQR之外的样本不直接删除而是截断到边界值。借贷场景里极端值可能代表真实的大客户或高风险客户直接删会损失信息截尾更稳妥。归一化/标准化。K-Means这类基于距离的算法必须做不然收入这个维度会直接碾压其他所有特征。我当时用的StandardScaler而不是MinMaxScaler因为它对离群值不那么敏感。这是实操中不少人忽略的细节。3.2 多维特征融合的具体做法我这里说的“多维特征融合”不是深度学习里的特征拼接而是工程化的特征衍生。原始字段是“收入”“消费金额”“借款次数”这种单点值但真正有判别力的是它们之间的比例关系和派生指标。我实际用到的融合方式主要有三类比值类特征。比如“月供收入比 月还款金额 / 月收入”“消费收入比 月消费 / 月收入”“借款频率 历史借款次数 / 注册时长月”。这些比例特征比绝对值更稳定也能直接解释客户的还款意愿和资金链条紧不紧张。聚合类特征。按用户ID对历史借贷行为做汇总。比如“平均借款金额”“最大借款金额”“标准差借款金额”、“提前还款次数”、“逾期次数占比”。这些指标描述的是客户的资金使用习惯和风险惯性。交叉类特征。两个特征相乘或相加组合而成。常见做法有“收入学历权重”把学历映射成数值后再跟收入相乘高分高收入客户的得分会显著高量级。又比如“借款金额期限”无监督模型容易学到这类隐含模式。我当时没有用PCA做降维原因有两个一是聚类的业务可解释性在论文里是加分项PCA降维后特征变得不可解释二是字段量几十个不算多相关性也控制在合理范围。但如果你发现特征数量上百可能存在共线性可以用PCA或者相关性热力图筛一遍。3.3 K-Means聚类的Python实现直接给出我当时的核心代码框架这份代码在Sklearn版本1.3以上都能直接跑import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans, AgglomerativeClustering from sklearn.metrics import silhouette_score import matplotlib.pyplot as plt # 读取已预处理的数据 df pd.read_csv(loan_customer_processed.csv) # 选择聚类特征列 feature_cols [age, monthly_income, loan_amount, loan_term, monthly_payment_income_ratio, consume_income_ratio, history_loan_counts, overdue_days_mean, loan_frequency, city_level_encoded, edu_level_encoded] X df[feature_cols] # 标准化 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 层次聚类确认K值范围抽样1万条 sample_df X_scaled[:10000] agglom AgglomerativeClustering(distance_threshold0, n_clustersNone) agglom.fit(sample_df) # 画出不同K对应的轮廓系数 silhouette_scores [] K_range range(2, 11) for k in K_range: km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X_scaled) silhouette_scores.append(silhouette_score(X_scaled, labels)) plt.plot(K_range, silhouette_scores, markero) plt.xlabel(K) plt.ylabel(Silhouette Score) plt.show() # 正式聚类K5由轮廓系数和业务解释共同决定 kmeans KMeans(n_clusters5, n_init10, random_state42) df[cluster] kmeans.fit_predict(X_scaled) # 每个聚类的中心点还原到原始尺度后看均值 cluster_profile df.groupby(cluster)[feature_cols].mean() print(cluster_profile)注意n_init10要写。Sklearn的新版本里默认值已经变了不指定它会弹警告。random_state也要固定住不然每次跑出来的聚类结果标签编号会变动后面做可视化的时候容易对不上颜色。3.4 层次聚类的应用与树状图绘制我在论文里展示了层次聚类的树状图用来佐证K值选择的合理性。Sklearn自身不带画树状图的函数是用的scipy.cluster.hierarchyfrom scipy.cluster.hierarchy import dendrogram, linkage # 对抽样数据用ward方法做层次聚类 Z linkage(sample_df, methodward) # 画树状图只显示后30个合并点防止图像过密 plt.figure(figsize(12, 8)) dendrogram(Z, truncate_modelastp, p30) plt.axhline(y某个阈值, colorred, linestyle--) plt.show()这个图的作用是让别人直观地看到“5簇”这个选择并非瞎拍脑袋。树状图中横线的高度就是簇间合并的代价横线位置高、跨越大的地方就是天然的分群边界。3.5 风险预警模型与评分映射聚类完成之后我接着做了风险预警。核心代码如下这里先用逻辑回归做基线再上XGBoost对比效果from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from xgboost import XGBClassifier from sklearn.metrics import classification_report, roc_auc_score # 构建标签历史逾期天数均值15 或 当前逾期标记1 视为坏客户 df[is_bad] ((df[overdue_days_mean] 15) | (df[current_overdue] 1)).astype(int) features feature_cols [cluster] # 聚类结果作为特征参与建模 X df[features] y df[is_bad] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) # 逻辑回归基线 lr LogisticRegression(max_iter1000, random_state42) lr.fit(X_train, y_train) y_pred_lr lr.predict_proba(X_test)[:, 1] print(LR AUC:, roc_auc_score(y_test, y_pred_lr)) # XGBoost xgb XGBClassifier(n_estimators200, max_depth4, learning_rate0.1, scale_pos_weightsum(y_train0)/sum(y_train1), random_state42) xgb.fit(X_train, y_train) y_pred_xgb xgb.predict_proba(X_test)[:, 1] print(XGB AUC:, roc_auc_score(y_test, y_pred_xgb)) # 输出风险评分0-100 df[risk_score] (1 - y_pred_xgb) * 100 df[risk_level] pd.cut(df[risk_score], bins[0, 60, 75, 85, 100], labels[高危, 中危, 低危, 优质])这里有一个处理经验正负样本不均衡问题用了scale_pos_weight参数给坏客户加权把“把坏人漏掉”的代价放大。在答辩时表现出这一层的思考明显能拉开档次。3.6 可视化大屏Flask ECharts 实现可视化是很多同学最担心的一环其实非常简单。我用的是Flask提供后端APIECharts渲染前端图表整个大屏是一张HTML页面顶部是标题中间排列四个图表左侧K-Means聚类散点图基于PCA降维到2维展示右侧各客群逾期率柱状图左下贷款用途分布玫瑰图饼图变形右下各客群风险定价区间散点图Flask代码骨架from flask import Flask, jsonify, render_template import pandas as pd import json app Flask(__name__) app.route(/) def index(): return render_template(dashboard.html) app.route(/api/cluster_data) def cluster_data(): # 读取聚类结果并做PCA降维 from sklearn.decomposition import PCA pca PCA(n_components2) df[[x, y]] pca.fit_transform(X_scaled) data df[[x, y, cluster, risk_level]].to_dict(records) return jsonify(data) app.route(/api/risk_stats) def risk_stats(): # 按客群聚合逾期率 stats df.groupby(cluster)[is_bad].mean().reset_index() return jsonify(stats.to_dict(records)) if __name__ __main__: app.run(debugTrue)ECharts前端示例散点图核心配置$.getJSON(/api/cluster_data, function(data) { var clusters [...new Set(data.map(d d.cluster))]; var series clusters.map(c ({ name: 客群 c, type: scatter, data: data.filter(d d.cluster c).map(d [d.x, d.y]) })); var chart echarts.init(document.getElementById(scatterChart)); chart.setOption({ tooltip: {}, legend: { top: 10 }, xAxis: { name: PC1 }, yAxis: { name: PC2 }, series: series }); });这一套做下来大屏效果确实好看。答辩的时候PPT里放一张实拍截图在纯粹讲算法的项目里非常亮眼。3.7 贷款用途与风险定价的关联分析只看聚类和风险还不够我的延伸题目还做了“贷款用途与风险定价”的关联分析。贷款用途字段以枚举形式出现装修、教育、医疗、购物、旅游、经营周转我用pd.get_dummies展开然后按聚类群组做交叉频次统计。实际结论非常清晰D群高风险长借群的贷款用途里“经营周转”和“医疗”占比显著偏高A群白领短借群的贷款用途集中在“购物”和“旅游”C群高收入低风险群的定价利率可以下调1个百分点风险性价比最优D群的定价利率需要上调2-3个百分点并且搭配借款额度上限限制风险定价我用的是“基准利率 风险溢价 客群调整系数”这么个简化公式最终贷款利率 基准利率(8.0%) 客群风险溢价 用途调整系数客群风险溢价由模型的违约概率映射得到用途调整系数根据历史坏账率经验设定。比如医疗用途的历史坏账率偏高系数相应增加教育用途虽然金额不大但违约率低可以给优惠。4. 实操中的常见问题、避坑指南与心得4.1 常见问题速查表问题现象原因分析解决方案K-Means聚类结果每次跑都不一样没有固定random_state固定随机种子同时设置n_init10普通人也能看懂的聚类图很乱看不出群簇用高维特征直接画图先用PCA降到2维再用散点图展示轮廓系数很高但业务解释很差特征选择只看了数值没看含义结合业务重新筛选特征删除噪声特征模型AUC高达0.98答辩时被质疑标签泄漏用到了未来信息或目标字段作特征检查特征列表中是否有与标签直接相关的字段前端图表数据量大页面卡死一次性加载了全部样本点后端抽样返回散点图只展示5000个点数据处理后收入均值异常未处理离群点使用IQR或分位数截断后再训练逻辑回归迭代次数警告数据未标准化或max_iter过小用StandardScaler处理后max_iter1000程序中文乱码编码问题CSV读取未指定编码pd.read_csv(file.csv, encodingutf-8)4.2 一个非常容易翻车的地方标签泄漏我必须单独提这个坑因为我在中期检查时差点翻车。做风险预警的时候数据表里有一个字段叫“历史逾期天数平均值”我拿它跟“是否违约”标签同时建模AUC直接到了0.99。答辩老师看了一眼就说“你这个特征本身不就是标签吗历史逾期天数均值本质定义了违约再拿它去预测违约这是自问自答。”解决的方法是把标签定义用到的字段从特征列表里剔除掉。比如标签是“逾期天数15”那建模时就不能用任何直接从逾期天数派生出来的字段。可以用历史借款次数、借款间隔、消费波动率等间接特征而不是逾期情况本身。我在论文里特意加了一节“特征合规性审查”列出哪些特征可以进入模型、哪些必须排除这个细节在答辩时非常加分因为你提前堵住了老师想挑刺的嘴。4.3 可视化大屏的实用经验ECharts虽然用起来容易但有几个实际经验值得记下来散点图会过度绘制。几千个点叠在一起就是一团黑要限制样本量。我的做法是每个客群随机抽500个点总计2500个点视觉上既能看清分布又不卡页面论文中再标注说明“展示部分样本”。大屏配色建议统一。用深色背景#0a0e27加亮色系列橙、蓝、绿是数据大屏最稳的方案。不要用默认白色背景会很“毕设”味。玫瑰图的实现可以更直观地表达贷款用途结构。ECharts中把饼图的roseType设置为radius就自动变成玫瑰图。建议配合客群切换联动点击某个客群下方玫瑰图只显示这个群体的贷款用途分布。4.4 关于源码和复现的说明我做毕设时也网上找过透源码和报告结果大部分不是残缺版就是需付费的引流项目或者数据不匹配、装上跑不起来。后来索性自己动手从数据构造开始写反而把整个流程吃透了。所以我的建议是参考源码可以但必须照着数据把每一步跑通。如果你拿到了别人的项目先确认三件事——数据能不能对齐依赖包版本合不合适字段命名是否一致。如果不一致照着我的流程重新生成模拟数据即可算法代码核心部分是通用的。算法层面不需要贪多。本科毕设用K-Means层次聚类逻辑回归XGBoostECharts已经是完整且扎实的组合。在这个基础上把每个环节做深做透比堆十几个算法效果更好。5. 从项目延伸到能力沉淀做完整套项目之后最大的收获倒不是代码能力而是把“数据挖掘”四个字从课本变成了一种解题习惯。第一你对数据的感觉会变。看到一张新表第一反应不是“跑个模型”而是先看分布、看缺失、看相关性先想业务逻辑合不合理。第二你对无监督学习的认知会更务实。K-Means不是调个库而是要理解不同人群的边界在哪里特征维度怎么取舍才能让分群有意义。聚类最终服务于决策而不是服务于美观的分簇图。第三你会对模型评估多一层敬畏。AUC、准确率高只代表你在这个数据集上拟合得好不代表放到真实环境里一定有用。风控模型尤其如此真实业务中模型还会面临客户偏移、数据质量波动、政策调整等复杂影响。这个项目如果要继续扩展我建议顺着两条线一条是线上部署把训练好的模型导出成PMML文件或pickle用Flask搭一个简单的评分服务接口另一条是引入时序观察客户过去几个月的消费和还款趋势把静态风险升级为动态风险。我给学弟学妹最诚恳的建议是选题选得再复杂不如一个环节做得扎实。多维特征融合和可视化这两条线是我做下来性价比最高、答辩效果最好的部分。如果你们时间紧优先保数据质量聚类效果可视化展示这三块风险模型可以适当简化绝对不影响你的毕设评级。纸上得来终觉浅从我的实战经历来看真正把整个流程跑通一遍任何人的技术成长都会非常明显。祝你们毕设顺利答辩顺利。 SEO 优化官网定制响应式建站教育培训建站