如何用Python机器学习基于购买行为对用户进行聚类分析?
基于购买数据的用户聚类实现(Python)
嘿,你的这个需求非常典型——基于用户的购买行为做相似性聚类,而且你的数据里用户分组的规律已经很明显了,咱们一步步用Python来实现:
1. 先把数据整理成机器学习能处理的格式
你的原始数据是用户-物品的购买记录,我们需要先把它转换成用户-物品二元矩阵:每个用户占一行,每个物品占一列,用户买过该物品标记为1,没买过标记为0。这样算法才能准确计算用户之间的相似度。
import pandas as pd from sklearn.metrics import pairwise_distances from sklearn.cluster import AgglomerativeClustering # 你的原始购买数据 data = [ [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 8], [3, 9], [4, 8], [4, 9] ] # 转换成DataFrame方便处理 df = pd.DataFrame(data, columns=['user_id', 'item_id']) # 构建用户-物品二元矩阵 user_item_matrix = df.pivot_table(index='user_id', columns='item_id', aggfunc=lambda x: 1, fill_value=0) print("用户-物品矩阵:") print(user_item_matrix)
输出的矩阵会是这样:
item_id 1 2 3 8 9 user_id 1 1 1 1 0 0 2 0 1 1 0 0 3 0 0 0 1 1 4 0 0 0 1 1
2. 计算用户间的距离矩阵(对应你提到的需求)
因为是二元购买数据,Jaccard距离是最适合的选择——它衡量的是两个用户购买物品的交集与并集的比值,1减去这个比值就是距离,距离越小说明用户越相似。
# 计算Jaccard距离矩阵(1 - Jaccard相似度) jaccard_distances = pairwise_distances(user_item_matrix, metric='jaccard') # 转换成DataFrame,方便直观查看 distance_df = pd.DataFrame( jaccard_distances, index=user_item_matrix.index, columns=user_item_matrix.index ) print("\n用户间Jaccard距离矩阵:") print(distance_df)
输出的矩阵完全符合你的预期:
user_id 1 2 3 4 user_id 1 0.000000 0.333333 1.0 1.0 2 0.333333 0.000000 1.0 1.0 3 1.000000 1.000000 0.0 0.0 4 1.000000 1.000000 0.0 0.0
能清楚看到:用户1和2的距离约为0.333(相似度很高),用户3和4的距离为0(完全相似),和你观察到的规律一致。
3. 执行聚类分析
这里给你两种简单有效的方法:
方法一:层次聚类(Agglomerative Clustering)
适合你这种已经有初步聚类预期的场景,我们可以直接指定聚类数量为2:
# 基于预先计算好的距离矩阵执行层次聚类 cluster = AgglomerativeClustering( n_clusters=2, affinity='precomputed', # 告诉模型我们已经传入了距离矩阵 linkage='average' ) # 拟合模型,得到每个用户的聚类标签 cluster_labels = cluster.fit_predict(jaccard_distances) # 把结果和用户ID对应起来 result = pd.DataFrame({ 'user_id': user_item_matrix.index, 'cluster_label': cluster_labels }) print("\n层次聚类结果:") print(result)
输出结果:
user_id cluster_label 0 1 0 1 2 0 2 3 1 3 4 1
方法二:K-Means聚类
如果你明确知道要分成2组,K-Means也是个不错的选择,对于你的小数据量来说,结果和层次聚类一致:
from sklearn.cluster import KMeans kmeans = KMeans(n_clusters=2, random_state=42) kmeans_labels = kmeans.fit_predict(user_item_matrix) kmeans_result = pd.DataFrame({ 'user_id': user_item_matrix.index, 'cluster_label': kmeans_labels }) print("\nK-Means聚类结果:") print(kmeans_result)
额外补充
- 为什么选Jaccard而不是余弦相似度?因为你的数据是二元存在型(只有买/没买,没有评分),Jaccard更关注两个用户共同购买物品占总购买物品的比例,而余弦相似度更适合有数值评分的场景。
- 如果后续数据量变大,计算全量距离矩阵效率变低,可以换成近似聚类算法(比如
MiniBatchKMeans),或者基于邻域的相似性匹配方法。
内容的提问来源于stack exchange,提问作者mortensen
相关产品推荐
相关产品推荐

