32 Kmeans——信用卡用户行为模式聚类
32.1 引言信用卡用户分层
聚类目标:
- 客户细分: 识别不同消费群体
- 风险控制: 识别高风险行为
- 精准营销: 针对性营销策略
32.2 本章学习目标
先修内容:阅读本章前,建议先完成第 章节 10 章(Pandas 数据框基础)、第 章节 14 章(读取外部数据文件)与第 章节 30 章(K-Means 原理与肘部法)。
- K-Means 在客户细分场景中的完整应用流程(读取—清洗—聚类—解读);
- 删除无关列、前向填充缺失值等聚类前的数据预处理操作;
- 用
groupby计算各簇特征均值,为每个客户群刻画行为画像; - 用轮廓系数评估聚类质量并解读其取值区间;
- 在教学平台完成信用卡用户行为模式聚类任务。
32.3 数据准备
# 注:09_CC GENERAL.csv数据文件本地没有,但平台已经内置
# =============================================================================
# 题目:K-Means信用卡用户行为模式聚类
# =============================================================================
# 本代码使用K-Means算法对信用卡用户进行聚类分析。
# 聚类是无监督学习方法,将相似的用户归为一组,发现数据内在结构。
# 在金融场景中用于客户细分、风险识别、精准营销等。
# ==================== 导入必要的库 ====================
import pandas as pd # 数据处理库
import numpy as np # 数值计算库
from sklearn.cluster import KMeans # K-Means聚类算法
from sklearn.metrics import silhouette_score # 轮廓系数评估指标
import matplotlib.pyplot as plt # 绘图库
import seaborn as sns # 统计绘图库
# ==================== 读取数据 ====================
# 读取信用卡用户数据,包含用户ID和各种消费行为特征
data = pd.read_csv('09_CC GENERAL.csv') # 从CSV文件加载数据
# ==================== 数据探索 ====================
print('数据形状:', data.shape) # 打印数据维度(样本数,特征数)
print('\n数据预览:')
print(data.head()) # 显示前5行数据,了解数据结构
# ==================== 数据清洗 ====================
# 删除客户ID列,因为聚类算法不应受ID影响
data_clean = data.drop(['CUST_ID'], axis=1) # axis=1表示删除列
# ==================== 处理缺失值 ====================
# 使用前向填充方法处理缺失值,即用前一个有效值填充
data_clean = data_clean.ffill() # ffill=forward fill,前向填充
print(f'\n缺失值处理:')
print(data_clean.isnull().sum().sum()) # 检查是否还有缺失值,应该输出0
# ==================== 数据描述统计 ====================
print('\n数据描述统计:')
print(data_clean.describe()) # 显示各特征的统计量(均值、标准差、分位数等)32.4 K-Means聚类
任务要求:将下方代码原样输入教学平台并运行(注释可省略)。该代码读取信用卡用户数据,删除客户 ID 列并用前向填充处理缺失值后,以 K=5 对用户行为特征做 K-Means 聚类,输出聚类散点图、各簇特征均值表与平均轮廓系数。
# 注:09_CC GENERAL.csv数据文件本地没有,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd # 导入Pandas数据分析库
data = pd.read_csv('09_CC GENERAL.csv') # 从CSV文件读取数据存入data
# 数据处理
data.drop(['CUST_ID'], axis=1, inplace=True)
data.fillna(method='ffill', inplace=True) # 使用前向填充法处理缺失值;旧版写法,新版 pandas 请改用 data = data.ffill()
from sklearn.cluster import KMeans # 导入Scikit-learn的KMeans模块
import matplotlib.pyplot as plt # 导入Matplotlib绘图库
# 使用Kmeans算法对数据进行聚类
kmeans = KMeans(n_clusters=5, n_init=10, max_iter=300,algorithm="elkan", random_state=42)
kmeans.fit(data) # 在数据上训练kmeans模型
# 可视化展示聚类结果
plt.scatter(data.iloc[:, 0], data.iloc[:, 1], c=kmeans.labels_, cmap='viridis')
plt.savefig("s.png") # 保存图形至文件
plt.show() # 显示图形
# 分析不同类别的用户特征和行为差异
data['cluster'] = kmeans.labels_
cluster_summary = data.groupby('cluster').mean() # 按指定列分组聚合
print(cluster_summary) # 输出聚类数据
# 对聚类结果进行评估
from sklearn.metrics import silhouette_score
print(silhouette_score(data, kmeans.labels_)) # 输出平均轮廓系数预期输出:平台先输出一张散点图(以数据的前两个特征维度为横纵坐标,按簇着色),随后打印 cluster_summary 各簇特征均值表与一个平均轮廓系数。判读要点:散点图只展示了前两维,高维簇结构未必在图上完全显现,不宜仅凭图形下结论;均值表中逐列比较各簇高低,找出区分度最大的特征(如余额、购买金额、现金提取行为),据此为每个簇命名客户画像;轮廓系数越接近 1 簇结构越好,接近 0 说明簇间重叠严重。09_CC GENERAL.csv 数据文件本地没有、平台已内置,具体数值以平台运行结果为准。
口径提示:平台代码计算轮廓系数时直接使用 silhouette_score(data, kmeans.labels_),而此时 data 已经新增了 cluster 标签列,该标签列被当作特征一并参与了距离计算;本章下方扩展代码则先用 data_clean.iloc[:, :-1] 剔除标签列再计算,两种口径得到的平均轮廓系数会有差异,严格评估聚类质量时应采用剔除标签列的做法。
32.5 聚类可视化
# 注:该代码块依赖的数据来自上方平台任务代码块,本块承接上方平台任务的代码与数据(变量沿用平台任务)
# ==================== 可视化前两维特征的聚类结果 ====================
# 注意:高维数据只能投影到2D平面展示,可能丢失部分信息
plt.figure(figsize=(10, 8)) # 创建10x8英寸的画布
# 绘制散点图,不同簇用不同颜色表示
scatter = plt.scatter(
data_clean.iloc[:, 0], # x坐标:第一个特征
data_clean.iloc[:, 1], # y坐标:第二个特征
c=labels, # 颜色根据簇标签着色
cmap='viridis', # 使用viridis配色方案(紫色到黄色)
s=50, # 点的大小为50
alpha=0.6 # 透明度0.6,便于看到重叠点
)
plt.colorbar(scatter, label='Cluster') # 添加颜色条,显示簇标签
plt.title('信用卡用户聚类结果', fontsize=14) # 设置标题
plt.xlabel('特征1', fontsize=12) # x轴标签
plt.ylabel('特征2', fontsize=12) # y轴标签
plt.grid(True, alpha=0.3) # 添加网格线,透明度0.3
plt.tight_layout() # 自动调整布局
plt.show() # 显示图形32.6 用户行为分析
# 注:该代码块依赖的数据来自上方平台任务代码块,本块承接上方平台任务的代码与数据(变量沿用平台任务)
# ==================== 按簇统计特征均值 ====================
# 计算每个簇各特征的平均值,用于理解各簇的行为模式
cluster_summary = data_clean.groupby('cluster').mean() # 按簇分组,计算均值
print('各簇平均特征:')
print(cluster_summary)
# 输出解读:比较各簇在余额、购买频率、信用额度等方面的差异
# ==================== 计算轮廓系数 ====================
# 轮廓系数衡量聚类质量:值越接近1,聚类效果越好
silhouette_avg = silhouette_score(data_clean.iloc[:, :-1], labels) # 排除cluster列
print(f'\n平均轮廓系数: {silhouette_avg:.4f}')
# ==================== 轮廓系数解读 ====================
# 轮廓系数范围:[-1, 1]
# >0.5: 良好聚类,样本分配合理
# 0.2-0.5: 中等聚类,部分样本可能分配错误
# <0.2: 较差聚类,簇之间重叠严重
# <0: 样本可能被分配到错误的簇
print('\n轮廓系数解读:')
if silhouette_avg > 0.5:
print(' 聚类效果良好,簇间分离度高')
elif silhouette_avg > 0.2:
print(' 聚类效果中等,可考虑调整K值或特征')
else:
print(' 聚类效果较差,建议重新选择特征或算法')32.7 商业应用
用户分群策略:
- 高消费高频率: VIP客户,专属服务
- 高消费低频率: 潜力客户,提升频率
- 低消费高频率: 价格敏感,优惠券激励
- 低消费低频率: 流失风险,召回活动
32.8 本章小结
要点:
- 聚类前必须做数据预处理:删除客户 ID 这类无关列、用前向填充等方法处理缺失值;
- 各簇的”画像”来自
groupby('cluster').mean()的特征均值表,聚类价值最终体现在画像的业务解读上; - 轮廓系数综合衡量簇内紧凑度与簇间分离度,取值 [-1, 1],是比肉眼读散点图更可靠的聚类质量指标;
- 客户细分结果应转化为差异化的营销与风控动作,而非止步于分出几个簇。
易错点:
- 忘记删除 ID 列,让无业务含义的编号参与距离计算,干扰聚类结果;
- 计算轮廓系数时把
cluster标签列留在特征里(见”口径提示”),口径不当导致评估失真; - 只看散点图前两维就断言聚类好坏,忽略高维信息在二维投影中的丢失;
- 把 K=5 当成唯一合理选择,不再检查其他 K 值或业务上是否真的需要五个客群。
32.9 动手与思考
以下练习每题附参考答案(默认折叠)。请先独立完成并写下你的判断,再点开对照,最后上机验证。
输出预测:某样本点 i 属于簇 A,其簇内平均距离 a(i)=2.0,到最近邻簇 B 的平均距离 b(i)=1.1。按轮廓系数公式 s=(b-a)/max(a,b) 计算 s(i) 并判断该点是否被分错了簇。
参考答案(先写下你的预测再点开)
解题思路:先代公式再判读。a(i)=2.0 是样本点 i 到本簇 A 其他点的平均距离,b(i)=1.1 是它到最近邻簇 B 各点的平均距离;分母取两者较大者 max(a,b)=2.0,故 s(i)=(1.1-2.0)/2.0=-0.9/2.0=-0.45。轮廓系数的取值范围是 [-1, 1]:s(i) 越接近 1 说明该点紧扣本簇、远离邻簇;接近 0 说明它落在两簇的边界上;小于 0 则说明它离邻簇比离本簇更近。本例 s(i)=-0.45<0,点 i 到簇 B 的平均距离(1.1)明显小于到本簇 A 的平均距离(2.0),它更像簇 B 的成员——在簇 A 待的位置上是被分错了的,K-Means 的“分配—更新”若能继续迭代,它正是最可能换簇(或形成换簇压力)的样本。
# 验证脚本:代入轮廓系数公式计算s(i)并判断符号 within_cluster_dist = 2.0 # 簇内平均距离a(i):到本簇A其他点的平均距离 nearest_cluster_dist = 1.1 # 最近邻簇平均距离b(i):到邻簇B各点的平均距离 silhouette_value = (nearest_cluster_dist - within_cluster_dist) / max(within_cluster_dist, nearest_cluster_dist) # 公式s=(b-a)/max(a,b) print('s(i) =', silhouette_value) # 输出轮廓系数 print('是否小于0:', silhouette_value < 0) # 小于0说明离邻簇更近,分错了簇预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):
s(i) = -0.44999999999999996 是否小于0: True(注:-0.44999999999999996 即 -0.45,尾差是二进制浮点数无法精确表示 0.45 所致。)
回扣本章:对应本章小结“要点”第 3 条——轮廓系数取值 [-1, 1],综合衡量簇内紧凑度与簇间分离度,负值提示样本可能被分到了错误的簇。
概念辨析:
ffill()前向填充与删除缺失值行两种处理方式各适合什么场景?对”余额”这类金额特征,前向填充可能引入什么偏差?参考答案(点开前请先独立完成)
解题思路:两种方式各自的前提假设不同。删除缺失值行适合:样本量大、缺失行占比很低、且缺失与业务含义无关(随机缺失)的场景——损失少量样本换取“每一行都是真实观测”的干净口径。前向填充适合:时间序列中同一主体相邻时点的缺失(如某交易日无成交,用上一交易日数值递延),或缺失占比不容忽视、删除会明显缩水样本的场景。对“余额”这类金额特征,前向填充的偏差在于:它是把“前一个用户的余额”抄给缺失的用户(
ffill按行顺序取上一个有效值),而不同用户之间的余额本无可比性,这等于凭空制造了一个“ borrowing 来的观测”——若数据行恰好按余额高低或客群顺序排列,填充值会系统性偏大或偏小,扭曲该用户的画像并把误差传入距离计算与各簇均值表;即便行序随机,它也只是把噪声伪装成了数据。更稳妥的候选做法包括按列中位数/均值填充,或对比“删除行、填充、单独标记缺失”几种口径下聚类结果是否稳定。回扣本章:对应本章小结“要点”第 1 条(聚类前必须做数据预处理,删除无关列、处理缺失值)与“易错点”第 1 条——预处理口径本身会影响聚类结果,不能机械套用。
概念辨析:轮廓系数与簇内平方和 SSE 都能评价聚类,为什么簇数增多时 SSE 必然下降、轮廓系数却未必上升?这与第 章节 30 章的肘部法有何联系?
参考答案(点开前请先独立完成)
解题思路:根源在两个指标的构造方式不同。SSE 只看“簇内”:K 增大时每个簇被切得更小更紧,样本到本簇质心的距离只减不增,故 SSE 随 K 单调下降(极端情况 K 等于样本数时每个点自成一簇,SSE 为 0)——单调的指标本身没有“最优 K”的内部判据。轮廓系数同时看“簇内”与“簇间”:s(i)=(b(i)-a(i))/max(a(i),b(i)),其中 a(i) 是簇内平均距离、b(i) 是到最近邻簇的平均距离;K 增大时 a(i) 固然变小,但邻簇也变得更近,b(i) 随之下降,若切分穿过了自然的过渡带,边界样本的 b(i) 会逼近甚至小于 a(i),s(i) 反而变小——因此轮廓系数随 K 呈先升后降的形态,可在中等 K 处取到最大值,具备“选 K”的能力。与肘部法的联系:第 章节 30 章的肘部法正是为了弥补 SSE 的单调性缺陷,转而寻找“SSE 下降骤缓的拐点”;轮廓系数则从另一个方向补偿——引入簇间分离度,直接找 s 最大的 K。两者是互补的参考准则,实务中常并列报告、交叉验证,再接受业务合理性检验。
回扣本章:对应本章小结“要点”第 3 条(轮廓系数综合衡量簇内紧凑度与簇间分离度)与“易错点”第 4 条(不把某个 K 当成唯一合理选择)。
变式任务:把平台代码中的
n_clusters依次改为 3、4、6(其余参数不变),在平台上分别运行并记录平均轮廓系数,绘制”K-轮廓系数”对照表;结合各簇画像,你认为几个客群最便于制定差异化营销策略?参考答案(点开前请先独立完成)
解题思路:改造思路——每次只改
n_clusters一个参数(3、4、6 依次代入),n_init=10、max_iter=300、algorithm="elkan"、random_state=42等其余设置保持不变,这样轮廓系数的差异才能归因于 K 本身;每次运行后记录silhouette_score的输出,汇成“K—平均轮廓系数”对照表,并同步保存各 K 下的cluster_summary均值表。注意口径:平台代码把cluster标签列留在了特征里再算轮廓系数(见本章“口径提示”),严格评估时应先用data_clean.iloc[:, :-1]剔除标签列再算,自己复算时全程保持同一口径。结构性判读——轮廓系数随 K 不一定单调:K 调小时每个簇更大更杂,簇内距离变大;K 调大则可能切开自然的过渡带、边界样本变差,两种方向都可能压低得分,应观察哪个 K 附近得分相对较高。营销视角的选 K 标准不是“轮廓系数最高”一项,还要看各簇画像:便于制定差异化策略的 K 应使各簇在余额、购买金额、取现行为等特征上呈现清晰的“高/低”分化(每个簇都能说出一句话画像,如“高余额高消费”“低余额高频取现”),且簇数与可运营的客群资源匹配——通常 3—5 个客群足以支撑差异化的产品与触达方案,K 过大反而使策略碎片化。预期输出:数据文件由教学平台内置(09_CC GENERAL.csv 本地没有),本机无法复现,具体数值以平台运行结果为准。
注意:以上为变式的改造思路与判读框架;列表 32.2 对应的平台原始代码块仍须原样输入教学平台,不要用本变式替换。
回扣本章:对应本章小结“要点”第 4 条(客户细分应转化为差异化的营销与风控动作,而非止步于分出几个簇)与“易错点”第 2、4 条(口径统一、K 不是唯一答案)。