基于用户/物品画像的个性化Collaborative Filtering(CF) Python实现咨询
嘿,这个思路很棒啊——用深度用户/物品画像替代传统的评分相似度做协同过滤,刚好能验证画像对推荐性能的提升作用。我来一步步给你拆解Python实现的方案,分用户侧和物品侧两块来讲:
核心逻辑梳理
不管是用户侧还是物品侧,你的需求核心都是先基于画像相似度锁定「同类群体」,再从同类里选K近邻,最后用协同过滤的方式生成推荐。和传统CF的区别是:传统CF靠评分矩阵算相似度,而你这里靠画像特征算相似度,先圈定典型群体再选近邻,更贴合个性化的画像维度。
第一步:画像相似度计算
首先得把用户/物品画像转化为可计算相似度的向量,不同类型的画像特征对应不同的相似度算法:
- 数值型特征(比如年龄、消费金额、物品价格):用余弦相似度或欧氏距离
- 类别/标签型特征(比如用户兴趣标签、物品分类):用Jaccard相似度,或者先做One-Hot编码转数值再用余弦
下面是两种常见场景的实现代码:
import numpy as np from sklearn.metrics.pairwise import cosine_similarity from sklearn.preprocessing import StandardScaler # 1. 数值型画像的余弦相似度计算 def calc_numerical_similarity(target_vec, all_vecs): # 确保输入是二维数组(适配sklearn的接口) target = target_vec.reshape(1, -1) # 计算余弦相似度,返回每个样本与目标的相似度数组 similarities = cosine_similarity(target, all_vecs)[0] return similarities # 2. 标签型画像的Jaccard相似度计算 def calc_jaccard_similarity(target_tags, all_user_tags): similarities = [] target_set = set(target_tags) for user_tags in all_user_tags: user_set = set(user_tags) intersection = len(target_set & user_set) union = len(target_set | user_set) sim = intersection / union if union != 0 else 0 similarities.append(sim) return np.array(similarities)
第二步:用户侧个性化CF实现
按照你的需求,分三个阶段完成:
阶段1:匹配典型用户画像
这里有两种落地方式,你可以根据数据规模选:
- 预聚类典型画像:先对所有用户画像做聚类,把每个簇的中心作为「典型画像」,找到目标用户所属的簇
- 直接锁定同类用户:跳过聚类,直接找和目标用户画像相似度Top N的用户作为同类群体
这里以聚类方式为例:
from sklearn.cluster import KMeans # 假设user_portraits是标准化后的数值矩阵,形状为(用户数, 画像特征数) # 先聚类得到典型用户群(簇数可以用肘部法则确定,这里暂设为10) kmeans = KMeans(n_clusters=10, random_state=42) user_cluster_labels = kmeans.fit_predict(user_portraits) typical_portraits = kmeans.cluster_centers_ # 每个簇的中心就是典型画像 # 找到目标用户所属的簇 target_user_idx = 0 # 替换成你的目标用户索引 target_cluster = user_cluster_labels[target_user_idx] # 获取同簇内所有用户的索引 same_cluster_users = np.where(user_cluster_labels == target_cluster)[0]
阶段2:从同类中选K近邻
在同簇内,用画像相似度选出Top K个最相似的用户(排除目标用户自己):
k = 5 # 你要的近邻数 target_portrait = user_portraits[target_user_idx] # 计算同簇内用户与目标用户的画像相似度 cluster_similarities = calc_numerical_similarity(target_portrait, user_portraits[same_cluster_users]) # 按相似度从高到低排序,排除自己后取Top K sorted_indices = np.argsort(cluster_similarities)[::-1] top_k_user_indices = [ same_cluster_users[i] for i in sorted_indices if same_cluster_users[i] != target_user_idx ][:k]
阶段3:生成推荐
收集Top K近邻用户的高分物品,排除目标用户已经交互过的物品:
# 假设user_item_matrix是用户-物品评分矩阵(行=用户,列=物品,0表示未交互) user_item_matrix = np.array([...]) # 替换成你的真实评分数据 # 收集近邻用户的高分物品(比如评分>=4) recommended_items = set() for user_idx in top_k_user_indices: high_rated_items = np.where(user_item_matrix[user_idx] >= 4)[0] recommended_items.update(high_rated_items) # 排除目标用户已经交互过的物品 target_rated_items = np.where(user_item_matrix[target_user_idx] > 0)[0] final_recs = [item for item in recommended_items if item not in target_rated_items] print("用户侧CF推荐结果:", final_recs)
第三步:物品侧个性化CF实现
逻辑和用户侧完全对称,只是把用户换成物品:
阶段1:匹配典型物品画像
# 对物品画像聚类,得到典型物品群 item_kmeans = KMeans(n_clusters=8, random_state=42) item_cluster_labels = item_kmeans.fit_predict(item_portraits) typical_item_portraits = item_kmeans.cluster_centers_ # 假设目标用户感兴趣的物品是item_idx=10 target_item_idx = 10 target_item_cluster = item_cluster_labels[target_item_idx] # 获取同簇内所有物品的索引 same_cluster_items = np.where(item_cluster_labels == target_item_cluster)[0]
阶段2:从同类中选K近邻物品
k = 5 target_item_portrait = item_portraits[target_item_idx] # 计算同簇内物品与目标物品的画像相似度 cluster_item_similarities = calc_numerical_similarity(target_item_portrait, item_portraits[same_cluster_items]) # 按相似度排序,排除自己后取Top K sorted_item_indices = np.argsort(cluster_item_similarities)[::-1] top_k_item_indices = [ same_cluster_items[i] for i in sorted_item_indices if same_cluster_items[i] != target_item_idx ][:k]
阶段3:生成推荐
给目标用户推荐这些同类物品(排除已交互的):
# 找目标用户未交互的物品 target_unrated_items = np.where(user_item_matrix[target_user_idx] == 0)[0] item_recs = [item for item in top_k_item_indices if item in target_unrated_items] print("物品侧CF推荐结果:", item_recs)
第四步:性能验证
要验证画像的作用,需要把你的新方法和传统CF(surprise库的用户/物品CF)做对比,常用的评估指标:
- 评分预测任务:MAE、RMSE
- Top-N推荐任务:Precision@K、Recall@K、NDCG
这里给你一个Precision@K的实现示例:
def precision_at_k(recommended_items, true_liked_items, k): # true_liked_items是用户实际喜欢的物品(比如评分>=4的) rec_k = recommended_items[:k] hits = len(set(rec_k) & set(true_liked_items)) return hits / k if k > 0 else 0 # 分别计算两种方法的Precision@K true_items = np.where(user_item_matrix[target_user_idx] >=4)[0] your_precision = precision_at_k(final_recs, true_items, k=5) # 传统CF的precision需要你用surprise库跑出来后计算
一些优化建议
- 如果画像混合了数值、类别、标签特征,可以用加权融合的方式计算相似度(比如数值特征占60%权重,标签特征占40%)
- 聚类的簇数别瞎选,用肘部法则或轮廓系数确定最优簇数
- 数据量大时,用近似最近邻算法(比如Annoy、FAISS)加速相似度计算,避免O(n)的时间开销
- 后期可以尝试把画像相似度和评分相似度加权结合,说不定能得到更好的效果
内容的提问来源于stack exchange,提问作者Geek88
相关产品推荐
相关产品推荐

