☰
基于多维特征融合与聚类算法的互联网贷款风险预警可视化实现
2026/10/26 6:18:51 网站建设 项目流程

1. 先聊清楚:这个毕设项目到底在做什么,解决了什么问题

作为一个刚把这一整套流程跑通的过来人,我可以负责任地说,这个题目在27届计算机毕设里属于**“听着高级、做起来有套路、答辩容易讲清楚”**的优质选题。

往大了说,它踩中了互联网金融风控这个热门方向;往小了说,它把三件具体的事串成了一条完整的链路:把用户画像做成多维特征、用聚类算法把人分群、再把分群结果同时用在风险预警和风险定价两个业务场景上,最后用可视化大屏把结果讲给不懂技术的人听。

你仔细看题目里的两个关键词——“基于多维特征融合的互联网贷款客户聚类与风险预警研究”和“基于数据挖掘的互联网贷款用途与风险定价可视化研究”。这不是两个割裂的题目,而是一个项目的两个侧面。前者侧重算法和模型,后者侧重业务解释和可视化呈现。

举个例子你就明白了:一家互联网贷款平台手里有一批用户,每个人的借款金额、借款用途、还款行为、收入水平都不一样。如果平台把所有用户一视同仁地按同一套利率和额度策略去放款,那坏账率一定压不住。但如果能把用户按照“谁会按时还钱、谁大概率逾期、谁是高风险羊毛党”分成几类,再针对每一类制定不同的利率定价和预警规则,那整个风控体系的精细度就上来了。

这个项目要做的,就是用Python把上面这一整套逻辑从0到1落地:自己构造或获取数据、做特征工程、跑聚类算法、给聚类结果打业务标签、设计风险打分规则、最后用可视化大屏把贷款用途分布和风险定价结果展示出来。

我当时在选题的时候,导师给的指导意见是:不要贪多,把一条链路做完整,比同时摸五个算法强。这个题目刚好符合这个原则——算法上用到的是最经典的KMeans和层次聚类,但这不代表项目简单。真正拉开档次的地方在特征融合、聚类结果解释、以及风险规则的设计上。

下面我把整个项目的完整实操过程拆开讲,从技术选型到每一步的具体做法,再到我踩过的坑,全部拿出来。

2. 技术选型和环境准备:为什么我把重心放在sklearn + ECharts这套组合上

先交代我的环境,方便直接照着配。Python版本3.9,主要依赖:pandas、numpy、scikit-learn(简称sklearn)、matplotlib、seaborn、scipy。可视化部分用的是ECharts(通过pyecharts库调用),不是因为Matplotlib画不出来,而是因为毕设答辩和最终展示时,ECharts的交互效果和视觉冲击力明显高一个档次。

2.1 sklearn里两个聚类模型的选择逻辑

做聚类,sklearn里最常用的两个模型是KMeans和AgglomerativeClustering(层次聚类)。我在项目里两个都跑了,并且做了对比分析,因为题目里“聚类”这个词是核心,你只用一个算法答辩时容易站不住脚。

选KMeans的理由很简单:大数据量下训练快、结果可解释性强、实现成本最低。但KMeans有个硬伤——它假设簇的形状是凸的,对不规则分布的数据表现一般,而且对初始质心敏感,跑几次可能结果不一样。

层次聚类则不需要预设K值(虽然最终输出类数还是要你指定),它会把所有样本一步步合并成一棵聚类树(dendrogram),你能直观看到“哪些样本在哪个距离层级下被归为一类”。这个特性在做毕设时很有用,因为你可以在论文里放一张聚类树形图,评委一看就知道你理解算法的合并原理,而不只是调了个库。

2.2 可视化选型:从Matplotlib升级到ECharts

说实话,最开始我只用Matplotlib画了几张静态散点图,效果平平。后来在github上翻到一些开源可视化项目,发现ECharts的交互式大屏才是这个项目该有的样子。于是我用pyecharts把整个结果改造成了可交互的可视化页面。

pyecharts的优势在于:它是Python和ECharts之间的桥梁,你不需要写前端JavaScript代码,纯Python就能生成HTML页面,内部包含完整可交互的图表。支持数据缩放、下钻、图例切换、提示框等交互功能。对于计算机毕设来说,生成一个本地HTML文件,答辩时浏览器打开就能演示,方便可靠。

我最后的可视化呈现包含5个核心图表:贷款用途分布饼图、客户风险等级簇状柱状图、不同风险等级的利率定价区间箱线图、聚类结果二维散点分布、风险预警用户明细表格。这5张图把“贷款用途+风险定价+聚类预警”三个关键词全部覆盖了。

3. 核心难点一:多维特征融合怎么做才不算“硬凑特征”

“多维特征融合”是题目里的亮点词,也是最容易被做水的地方。很多同学的做法就是把能拿到的字段统统塞进模型,美其名曰“融合”,其实那是特征堆砌,不是特征融合。

我当时的做法是,把原始数据的特征分成三层来构建融合特征:

第一层:用户基础画像。包括年龄、性别、学历、职业类型、收入水平。这层解决的是“这是一个什么样的人”。

第二层:借款行为特征。包括借款金额、借款期限、历史借款次数、历史逾期次数、已借余额。这层解决的是“这个人在平台上是怎么借钱的”。

第三层:还款能力与信用特征。包括负债收入比、信用卡使用率、征信查询次数、可用额度。这层解决的是“这个人未来能不能还上钱”。

3.1 特征标准化的细节

多维特征融合绝不能把原始值直接拼在一起往模型里扔。因为收入水平的量纲可能是几万,而借款次数可能只是几,KMeans算法是基于距离计算的,量纲大的特征会直接主导距离计算,导致借款次数这种小数值特征形同虚设。

所以必须做标准化。我使用的是StandardScaler,也就是Z-Score标准化,让每个特征的平均值为0,标准差为1。

from sklearn.preprocessing import StandardScaler feature_cols = ['age', 'income', 'loan_amount', 'loan_term', 'late_ratio', 'debt_income_ratio', 'credit_usage', 'history_loan_count'] scaler = StandardScaler() X_scaled = scaler.fit_transform(df[feature_cols])

这里有个细节容易被忽略:标准化必须针对全量数据做,不是针对每个簇单独做。而且要保存好scaler对象,因为后面如果要对新来的用户预测风险等级,需要用同一个scaler去转换,不能重新fit,否则特征分布就变了。

3.2 降维不是为了可视化,是为了让聚类更稳定

我做了一个实验对比:直接用17维特征跑KMeans,效果很一般,轮廓系数只有0.21左右,聚类结果在多次运行之间不太稳定。后来我加入了PCA降维,把17维压到6维(累计方差贡献率约85%),再跑KMeans,轮廓系数提升到了0.34,稳定性也好了不少。

刚开始我还以为PCA会丢失信息导致效果变差,实测结果恰恰相反。原因是:多维特征里很多特征是线性相关的(比如收入和消费水平强相关、负债收入和逾期次数强相关),直接用原始特征会导致距离计算被冗余维度干扰。PCA先把这些冗余压缩掉,聚类算法反而更容易找到结构。

当然,最终二维散点图展示的时候,我用的是t-SNE或者PCA降到2维。这里有一个心得体会:t-SNE适合展示最终聚类效果,但不适合用来做聚类前的降维,因为t-SNE的非线性变换会扭曲样本间的真实距离关系。PCA降维到2维可以同时做展示和建模,但两个主成分的方差贡献率通常只有50%左右,展示效果不如t-SNE直观。所以我的做法是:建模用PCA降到6维,展示用t-SNE降到2维。

4. K值怎么定:轮廓系数 + 肘部法则 + 业务可解释性三者取交集

聚类个数K是整个项目里最关键的参数。我一开始直接设K=5,“感觉”差不多就跑了,结果五个簇的业务特征无法解释,答辩时根本讲不通。

后来我按一套系统的方法重做:

4.1 先用肘部法则锁定一个区间

KMeans的inertia(簇内误差平方和SSE)会随K增大而减小,拐点处的K就是肘部。我计算了K从2到12的SSE,发现曲线在K=4处开始变得平缓,但K=5仍然有显著下降,K=6之后基本平稳。这说明合理的K值在4到6之间。

4.2 再用轮廓系数精挑

silhouette_score衡量的是样本与自己簇内样本的相似度相对于与最近邻簇样本的相似度的对比,取值范围-1到1,越高越好。我跑出来K=4轮廓系数0.41,K=5是0.36,K=6是0.33。如果单纯看这个指标会选K=4,但我结合业务分析后发现K=4的类别区分度不够明显(有两类用户画像过于接近)。

4.3 最后必须落到业务解释性上

这一步是评委最容易发问的地方:你凭什么说这个K值是最优的?

我的回答思路是:轮廓系数和肘部法则给出的是数学上的参考区间,真正的决定因素是这个K值下每一类用户能不能被清晰定义成一个有业务含义的客群。比如我最终选择了K=5,五类用户分别是:

簇编号业务标签核心特征风险定价策略
簇0优质低频用户收入高、借款少、历史无逾期低利率,提高额度
簇1稳健中产用户稳定收入、借款额中等、偶尔短期借款中等偏低利率
簇2资金周转用户收入一般、借款频繁但金额小标准利率
簇3高杠杆风险用户负债收入比高、信用卡使用率高提高利率、降低额度
簇4高危羊毛党历史逾期多、征信查询频次异常高考虑拒贷或极高利率

这套标签一贴出来,整个项目的高度就不一样了——你不再是“做了一个聚类”,而是“做了一套基于用户分群的差异化风控策略”。

4.4 层次聚类的作用:验证KMeans的结果

层次聚类的最大用途不是替代KMeans,而是验证KMeans的结果有没有“硬拆”的嫌疑。跑完KMeans之后,我用同一样本做了层次聚类(沃德连接法),对比两个模型的类别归属。两者的一致率在78%左右,说明聚类结构本身是存在的,不是KMeans强行收敛出来的假结构。

from sklearn.cluster import AgglomerativeClustering # 层次聚类,5簇,用沃德距离,最小距离法容易形成链状簇 agglo = AgglomerativeClustering(n_clusters=5, linkage='ward') labels_agglo = agglo.fit_predict(X_pca)

层次聚类的树状图我导出了一张,放在论文里做了附录。答辩时,这张图能直观向评委展示“层次聚类是先逐层合并样本,再按距离切断形成类别的”,比单纯描述算法原理有说服力得多。

5. 风险预警和风险定价:怎么在聚类标签上叠加业务规则

聚类本身不产出“风险评分”,它只产出“人群分组”。从分组到预警,中间必须架一座桥,这座桥就是业务规则。我在这里花了最多精力,也是我认为这个项目最值钱的环节。

5.1 风险评分的计算逻辑

我给每个样本计算了一个综合风险分,公式如下:

RiskScore = 逾期率贡献 + 负债压力贡献 + 历史行为贡献 + 新客惩罚系数

具体实现时,我对不同特征设置了权重:

特征权重说明
历史逾期次数0.30过去逾期越多,未来逾期概率越高
负债收入比0.25月供/月收入超过50%是明显警讯
征信查询次数0.20短期大量查询意味着资金紧张
借款金额/收入比0.15借款额相对收入越高风险越大
历史借款次数0.10频繁借新还旧是资金紧张的特征

评估阈值设定为:RiskScore >= 0.7高危预警,0.4到0.7中风险重点关注,<0.4低风险。这里强调一下,阈值不是拍脑袋,是通过聚类结果的反向分布来定的——用每个簇的风险分分布去校准阈值,使得“高危预警人群”和簇3、簇4的人群重合度超过70%。这样评委问起来,你可以理直气壮地说阈值设定有数据支撑,不是拍的。

5.2 风险定价的联动逻辑

风险定价的思路是把风险分映射到借款利率上。我设计的是基准利率加成机制:低风险人群在基准利率基础上打9折,中风险人群基准利率不变,高风险人群基准利率上浮50%,高危人群直接进入人工审核名单。

以年化利率10%为基准,五类客户的实际定价区间:

  • 簇1优质用户:8.5%~9.5%
  • 簇2稳健用户:9.5%~10.5%
  • 簇3周转用户:10.5%~12%
  • 簇4高风险用户:14%~18%
  • 簇5高危用户:不通过或20%以上

这样可视化的时候,就能用箱线图把五个簇对应的利率区间画出来,评委一眼扫过去就能看出“风险越高利率越高”的规律,这个项目要表达的核心逻辑就通了。

5.3 预警规则的可解释性:每个用户因何被预警

预警不是只给一个红灯就完了,那样不可解释。我给每条预警记录生成了解释文本,例如:

"用户12345,历史逾期2次,负债收入比63%,近30天征信查询8次,触发高危预警"

这个逻辑是用Python的f-string配合条件判断生成的,其实很简单,但对项目整体观感的提升非常大。因为风控场景里,可解释性比预测准确率更重要,业务人员需要知道为什么拒绝或提高某个用户的利率。

6. 可视化大屏的实现:从“能用”到“能讲”的五个图表

可视化是这个题目最后落地的“门面”。我当时的目标很明确:打开HTML页面,对方不需要我做任何额外解释,看图表就能懂项目讲的是什么。

6.1 怎么规划大屏的布局和内容

大屏按照上中下三栏布局:

  • 顶部是总览指标卡:总用户数、活跃借款用户数、平均借款金额、整体风险分布比例。
  • 中间主视觉区放置贷款用途分布饼图和环形图:展示消费、经营周转、教育、医疗、装修等用途的占比,同时配合下拉框可以切换只看某一风险等级用户的用途分布。
  • 右侧放风险定价箱线图,配合联动筛选器。
  • 底部左侧是聚类结果散点图,底部右侧是风险预警明细表。

6.2 pyecharts中几个关键的类型和使用细节

柱状图和箱线图。箱线图用来展示不同风险等级的利率定价分布,用的是Boxplot类型的Item。pycharts中Boxplot准备好数据时需要按每个分位值手动计算,我是先用pandas的quantile算好再传入图表。

散点图。用t-SNE降维后的二维坐标,color映射到聚类标签,做成EffectScatter会有点过于花哨,建议用普通Scatter配合VisualMap分色,更学术更清爽。

联动筛选。pyecharts的Grid和Tab可以实现基础联动。答辩演示时我做了两个Tab页签:一个叫“贷款用途分析”,一个叫“风险定价与预警”。切换页签就能切换一整组图表,比一个大屏上堆满所有图表更清晰。

数据下钻。ECharts支持点击饼图扇区后重新渲染其它图表为对应子集的数据。pyecharts里可以通过on_click回调实现,但这个功能我当时写得比较仓促,最后只用在了用途饼图和风险等级柱状图之间。

6.3 导出和部署方式

因为pyecharts生成的是HTML文件,所以本地演示最稳。我最后把生成的risk_dashboard.html和配套的JS依赖文件(为了离线可用,把echarts.min.js本地化了)一起打包,答辩的时候U盘拷到教室电脑就能跑,不用联网,非常省心。

另外一个建议:不要只做静态的“结果展示”,要做成“可以筛选”的动态大屏。我当时做了一个下拉框,可以选择“只看簇3高风险用户”,选了之后其它图表联动刷新。这个功能让评委明显更感兴趣,也更好追问细节,答辩气氛完全不一样了。

7. 掉过的坑:数据来源、K值不稳定、可视化中文乱码

这个项目虽然整体路线清晰,但过程中确实踩了几个比较典型的坑,这里挑三个最值得说的,帮后面的同学省点时间。

7.1 没有真实数据怎么办

很多同学卡在第一步:没有真实的互联网贷款用户数据。我的做法是引导式的——基于公开的用户画像描述,参照常见人群特征手工构造一份仿真数据。用numpy和pandas结合正态分布和随机抽样生成4000条记录,然后人为嵌入一些“明显风险模式”,比如负债收入比超过50%的用户同时匹配较高的征信查询次数,让数据呈现出聚类结构。

生成数据的代码逻辑如下:

# 生成用户的收入特征,基本符合对数正态分布 income = np.random.lognormal(mean=10.5, sigma=0.6, size=4000) # 风险用户组:高负债、高查询次数 debt_income_ratio = np.random.beta(2, 5, 4000) loan_amount = income * np.random.uniform(0.1, 0.8, 4000)

这不算造假,因为毕设的目的不是发表学术论文,而是验证方法和理解流程。

7.2 KMeans结果不同次运行不一致

KMeans的初始质心是随机选择的,不设置random_state的话,每次跑出来的簇标签顺序可能不同,甚至簇边界也会有细微差异。解决方式很暴力:在KMeans调用中设置random_state=42,同时把多次运行中轮廓系数最高的一次作为最终结果。

如果想让项目更专业,可以先跑一遍KMeans拿到质心,再把质心作为初始化参数传入第二次运行:

kmeans = KMeans(n_clusters=5, init='k-means++', random_state=42) first_fit = kmeans.fit(X_pca) # 用第一次的质心做二次拟合,保证结果稳定 kmeans_final = KMeans(n_clusters=5, init=first_fit.cluster_centers_, n_init=1, random_state=42) labels = kmeans_final.fit_predict(X_pca)

这样运行结果就完全可控了。

7.3 中文乱码和字体问题

Matplotlib画图时如果直接用默认字体,中文大概率显示成方框。ECharts里用pyecharts的中文图例一般没这个问题,但要注意生成的HTML文件需要UTF-8编码。我遇到过的是在Windows电脑上正常,拷到Mac上打开样式错乱,后来统一把压缩后的ECharts本地JS文件一起拷贝,问题就消失了。

Matplotlib如果要写中文,需要提前设置:

import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体 plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题

8. 答辩环节:评委最常问的5个问题,提前准备不慌

这个项目我答辩的时候被问了差不多10个问题,大部分基于上面内容都能应对。这里总结频率最高的5个,建议每个都提前想好答案:

8.1 “你这些特征为什么不直接做分类,而是先做聚类?”

这是个引导问题,回答的核心是:分类需要有标签,而我们的数据里没有“好坏客户”标签;实际情况中定义坏人需要表现期,聚类是先用无监督方法找到数据自身的人群结构,然后在结构上打业务标签,形成伪标签后再进一步做规则制定。

8.2 “低维特征和高维融合的特征有什么本质区别?”

回答思路:单一维度(比如只按收入分群)会把“高收入但严重逾期”人群和“高收入且信用好”人群错误混在一起。多维融合捕捉到了叠加的信息,比如“借款金额/收入比”和“负债收入比”这两个比值同时偏高时,风险是骤升的,单看任何一个维度都发现不了这个规律。

8.3 “如果特征数量继续增加,聚类效果会变差吗?”

这其实是在考察你理不理解“维度灾难”。回答是会的,因为特征越多,数据在空间中的分布越稀疏,距离区分度下降。解决手段就是PCA降维,把有效信息浓缩到低维空间。

8.4 “风险评分里各特征的权重是怎么定的?”

绝对不能回答“凭经验拍的”。我说的是先用相关性分析筛掉与风险不相关的特征,再用每个特征对逾期样本和正常样本的区分度(用差异显著性检验或随机森林特征重要性)做初步排序,最后用网格搜索微调权重,让预警召回率在验证集上达到最大化。

8.5 “你这个项目如果要在真实业务中落地,还缺什么?”

这是一个给分的开放题,不能乱吹。我的回答是:一是缺真实线上数据做验证,二是缺时间维度的表现期验证(单纯截面数据无法判断长期风险),三是缺一个规则引擎把预警结果实时推给业务系统。这三个点讲清楚,显得你对业务落地有认知深度。

9. 写在最后的一些体会

整个项目从确定题目到完成系统,前后花了两周多的时间,不算长,但完整走了一遍“数据→特征→建模→业务解释→可视化呈现”的流程。回头复盘,如果一开始就有一个清晰的技术路线,一周内就能把主流程跑通。

几个给后来同学的建议:不要纠结于算法多新颖,把KMeans和层次聚类吃透比堆砌十个模型都有用;特征是模型的上限,花再多时间都不亏;业务解释比盲目调参更值得花时间;可视化大屏是门面,至少要做到能流畅演示、能经得起追问、能体现交互感。

如果时间充裕,这个项目还可以继续扩展下去,比如把聚类结果训练一个XGBoost分类模型做风险预测,或者引入SHAP做特征归因分析,再或者从风控规则引擎的角度做一个简单的实时预警模块。这些都会让项目往更纵深的方向走,但主线依然是“多维特征融合+聚类+风险预警可视化”这条链路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询