基于物品的协同过滤(ItemCF)(基础算法详细解析)

为什么选择学习这篇代码?

  1. 核心思想: 它体现了“用户行为数据”是搜广推系统的基石。通过分析用户对物品的偏好,来发现物品之间的关联,进而进行推荐。

  2. 直观易懂: “喜欢A的用户也喜欢B,那么A和B是相似的”这个逻辑非常直观。

  3. 应用广泛: 它的思想被广泛应用于推荐系统、搜索引擎的相关推荐、甚至广告系统的兴趣匹配中。

  4. 可扩展性: 它是许多更复杂算法(如矩阵分解、深度学习推荐模型)的基础或前置知识。

当一个用户喜欢了某个物品A时,我们找到与物品A相似的其他物品B、C、D,并将这些相似物品推荐给该用户。这里的关键在于如何定义和计算“物品相似度”。

 整体代码:

import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity

data = {
    'user_id': ['user_A', 'user_A', 'user_A', 'user_B', 'user_B', 'user_B', 'user_C', 'user_C', 'user_D', 'user_D', 'user_D'],
    'item_id': ['item_1', 'item_2', 'item_3', 'item_1', 'item_3', 'item_4', 'item_2', 'item_5', 'item_1', 'item_2', 'item_4'],
    'interaction': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 
}
df = pd.DataFrame(data)
print("--- 原始用户-物品交互数据 ---")
print(df)
print("\n")

user_item_matrix = df.pivot_table(index='user_id', columns='item_id', values='interaction').fillna(0)
print("--- 用户-物品矩阵 ---")
print(user_item_matrix)
print("\n")

item_user_matrix = user_item_matrix.T
print("--- 物品-用户矩阵 (用于计算物品相似度) ---")
print(item_user_matrix)
print("\n")

# cosine_similarity返回的是一个矩阵,(num_items x num_items)
item_similarity = cosine_similarity(item_user_matrix)

item_similarity_df = pd.DataFrame(item_similarity, index=item_user_matrix.index, columns=item_user_matrix.index)
print("--- 物品相似度矩阵 (余弦相似度) ---")
print(item_similarity_df)
print("\n")

def recommend_items(user_id, user_item_matrix, item_similarity_df, top_n=3, k_similar_items=5):
    user_interactions = user_item_matrix.loc[user_id]
    print(user_interactions)
    interacted_items = user_interactions[user_interactions > 0].index.tolist()

    print(f"用户 {user_id} 已交互的物品: {interacted_items}")

    recommendation_scores = {}

    for item in interacted_items:
        similar_items = item_similarity_df[item].sort_values(ascending=False)
        similar_items = similar_items[similar_items.index != item]
        similar_items = similar_items[similar_items > 0] 
        similar_items = similar_items.head(k_similar_items)

        print(f"  与 {item} 最相似的物品: {similar_items.index.tolist()}")

        for similar_item, similarity_score in similar_items.items():
            if user_item_matrix.loc[user_id, similar_item] == 0: 
                recommendation_scores[similar_item] = recommendation_scores.get(similar_item, 0) + similarity_score

    recommended_items = pd.Series(recommendation_scores).sort_values(ascending=False)

    return recommended_items.head(top_n)

print("--- 为 'user_A' 生成推荐 ---")
recommended_for_A = recommend_items('user_A', user_item_matrix, item_similarity_df, top_n=2)
print(f"推荐给 user_A 的物品:\n{recommended_for_A}")
print("\n")

print("--- 为 'user_C' 生成推荐 ---")
recommended_for_C = recommend_items('user_C', user_item_matrix, item_similarity_df, top_n=2)
print(f"推荐给 user_C 的物品:\n{recommended_for_C}")
print("\n")

 逐段解析:

步骤1: 模拟用户-物品交互数据
          假设我们有以下用户和物品的交互数据
          1表示用户与物品有交互(如购买、点击、收藏),0则表示没有。

data = {
    'user_id': ['user_A', 'user_A', 'user_A', 'user_B', 'user_B', 'user_B', 'user_C', 'user_C', 'user_D', 'user_D', 'user_D'],
    'item_id': ['item_1', 'item_2', 'item_3', 'item_1', 'item_3', 'item_4', 'item_2', 'item_5', 'item_1', 'item_2', 'item_4'],
    'interaction': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 
}
df = pd.DataFrame(data)
print("--- 原始用户-物品交互数据 ---")
print(df)

然后将数据转换为pandas的dataframe格式,展示如下图。

步骤2: 构建用户-物品矩阵
        使用pivot_table将刚刚的dataframe数据转换为用户-物品矩阵,横标签为用户id,竖标签为物品id,矩阵各元素为用户与物品之间的交互情况(1为有交互,0为无交互),并且将矩阵中为NaN的元素替换为0

user_item_matrix = df.pivot_table(index='user_id', columns='item_id', values='interaction').fillna(0)
print("--- 用户-物品矩阵 ---")
print(user_item_matrix)

 该矩阵如下图所示

步骤3: 计算物品之间的相似度
为了计算物品相似度,我们需要将上面的用户-物品矩阵进行转置,使行代表物品,列代表用户。然后放入cosine_similarity函数中,计算得到余弦相似度,这个值得到了这五个物品两两之间的相似度。

item_user_matrix = user_item_matrix.T
print("--- 物品-用户矩阵 (用于计算物品相似度) ---")
print(item_user_matrix)
item_similarity = cosine_similarity(item_user_matrix)

 转置后的矩阵如下图

 将相似度矩阵转换为DataFrame,方便查看和索引

item_similarity_df = pd.DataFrame(item_similarity, index=item_user_matrix.index, columns=item_user_matrix.index)
print("--- 物品相似度矩阵 (余弦相似度) ---")
print(item_similarity_df)

 下图就是相似度矩阵

 

 步骤4: 生成推荐列表

def recommend_items(user_id, user_item_matrix, item_similarity_df, top_n=3, k_similar_items=5):
    """
    为指定用户生成推荐列表

    Args:
        user_id (str): 目标用户的ID
        user_item_matrix (pd.DataFrame): 用户-物品交互矩阵
        item_similarity_df (pd.DataFrame): 物品相似度矩阵
        top_n (int): 最终推荐的物品数量
        k_similar_items (int): 考虑每个已交互物品的多少个最相似物品

    Returns:
        pd.Series: 推荐物品及其推荐得分
    """
    # 获取用户已交互的物品
    user_interactions = user_item_matrix.loc[user_id]
    print(user_interactions)
    # 找到用户已交互且交互值为1的物品
    interacted_items = user_interactions[user_interactions > 0].index.tolist()

    print(f"用户 {user_id} 已交互的物品: {interacted_items}")

    # 用于存储推荐物品及其得分
    recommendation_scores = {}

    for item in interacted_items:
        # 获取与当前物品最相似的物品(排除自身)
        # 排序并取前 k_similar_items 个
        similar_items = item_similarity_df[item].sort_values(ascending=False)
        # 过滤掉自身和相似度为0的物品
        similar_items = similar_items[similar_items.index != item]
        similar_items = similar_items[similar_items > 0] # 排除相似度为0的物品
        similar_items = similar_items.head(k_similar_items)

        print(f"  与 {item} 最相似的物品: {similar_items.index.tolist()}")

        for similar_item, similarity_score in similar_items.items():
            # 检查该相似物品是否用户已经交互过
            if user_item_matrix.loc[user_id, similar_item] == 0: # 如果用户未交互过
                # 累加推荐得分
                # 这里的得分可以是简单相加,也可以是加权平均(例如,用户对原物品的评分 * 相似度)
                # 由于我们是二元交互,直接累加相似度即可
                recommendation_scores[similar_item] = recommendation_scores.get(similar_item, 0) + similarity_score

    # 将推荐得分转换为Series并排序
    recommended_items = pd.Series(recommendation_scores).sort_values(ascending=False)

    return recommended_items.head(top_n)

loc是pandas中常用的索引方式,表示索引dataframe矩阵中标签名为user_id的那一行或列的全部元素;

user_interactions > 0会生成一个布尔序列,表示每个物品的交互值是否大于 0;

接着user_interactions[user_interactions > 0]则筛掉了原来矩阵中为0的元素及其标签,剩下了都是1的;

.index则得到该矩阵的序号,即标签,不包含元素;再用.tolist生成列表。

user_interactions = user_item_matrix.loc[user_id]
interacted_items = user_interactions[user_interactions > 0].index.tolist()

下面这部分代码从相似度矩阵中提取与特定物品 item 相关的相似度列,然后按照相似度值从高到低排序。

similar_items = item_similarity_df[item].sort_values(ascending=False)

下面三句,第一句是提取出除自己外的其他元素;第二句是排除掉相似度为0的物品;第三句是仅保留前k_similar_items个物品。

similar_items = similar_items[similar_items.index != item]
similar_items = similar_items[similar_items > 0] 
similar_items = similar_items.head(k_similar_items)

首先,recommendation_scores是字典。

recommendation_scores.get(similar_item, 0) 的含义是:

  • “去 recommendation_scores 字典里找 similar_item 的当前得分。”

  • “如果 similar_item 已经在字典里了,那就取出它当前的得分。”

  • “如果 similar_item 还没有在字典里,那就把它当前的得分视为 0。”

... + similarity_score 的作用:

  • recommendation_scores.get(similar_item, 0) 的结果(无论是已有的得分还是 0)会与当前的 similarity_score 相加。

这里直接将相似度作为用户对未交互过的物品的预估评分,并以此叠加。 

recommendation_scores[similar_item] = recommendation_scores.get(similar_item, 0) + similarity_score

以上就是对代码的解析,这个代码只是对于ItemCF的基础实现,可以理解这个代码进行入门。

本套大数据热门技术Spark+机器学习+贝叶斯算法系列课程,历经5年沉淀,调研企业上百家,通过上万学员汇总,保留较为完整的知识体系的同时,让每个模块看起来小而精,碎而不散。在本课程中基于大量案例实战,深度剖析和讲解Spark2.4原理和新特性,且会包含完全从企业真实业务需求中抽取出的案例实战。内容涵盖Spark核心编程、Spark SQL和Spark Streaming、Spark内核以及源码剖析、推荐系统、Kafka消费机制、Spark机器学习、朴素贝叶斯算法、企业级实战案例等。通过理论和实际的紧密结合,可以使学员对大数据Spark技术栈有充分的认识和理解,在项目实战中对Spark和流式处理应用的场景、以及大数据开发有更深刻的认识;并且通过对流处理原理的学习和与批处理架构的对比,可以对大数据处理架构有更全面的了解,为日后成长为架构师打下基础。本套教程可以让学员熟练掌握Spark技术栈,提升自己的职场竞争力,实现更好的升职或者跳槽,或者从J2EE等传统软件开发工程师转型为Spark大数据开发工程师,或是对于正在从事Hadoop大数据开发的朋友可以拓宽自己的技术能力栈,提升自己的价值。Spark应用场景Yahoo将Spark用在Audience Expansion中的应用,进行点击预测和即席查询等。淘宝技术团队使用了Spark来解决多次迭代的机器学习算法、高计算复杂度的算法等。应用于内容推荐、社区发现等。腾讯大数据精准推荐借助Spark快速迭代的优势,实现了在“数据实时采集、算法实时训练、系统实时预测”的全流程实时并行高维算法,最终成功应用于广点通pCTR投放系统上。优酷土豆将Spark应用于视频推荐(图计算)、广告业务,主要实现机器学习、图计算等迭代计算。本套大数据热门技术Spark+机器学习+贝叶斯算法共计13季,本套为第12季。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值