#P2852. 第2题-数据工程师
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 8
            Accepted: 2
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年4月17日-阿里云(算法岗)
                              
                      
          
 
- 
                        算法标签>机器学习算法          
 
第2题-数据工程师
题解
题面描述
给定一个包含 N 个用户对 M 部电影评分的矩阵,评分范围为 1 到 5 的整数,未评分用 0 表示。要求对指定的目标用户 U,基于用户协同过滤算法,推荐其尚未评分的电影中最可能喜欢的前 T 部电影。
- 
输入:
- 第一行包含两个整数 N 和 M,分别表示用户数量和电影数量。
 - 接下来的 N 行,每行包含 M 个整数,表示用户对每部电影的评分,未评分记为 0。
 - 接下来一行包含一个整数 U,表示目标用户的编号(从 0 开始)。
 - 最后一行包含一个整数 T,表示需要推荐的电影数量。
 
 - 
输出:
输出一行,包含 T 个电影编号(从 0 开始),按照预测评分从高到低依次排列,若预测评分相同则按电影编号从小到大排序。
 
默认选取与目标用户最相似的前 K=3 个用户参与预测。
算法思路
- 
计算用户平均评分
对每个用户 u,计算其对已评分电影的平均评分:
其中 Iu 是用户 u 已评分的电影集合。
 - 
计算用户相似度(Pearson 相关系数)
对用户 u 和 v,首先找出它们都评分过的电影集合 Iuv,然后计算:
若 Iuv 为空或分母为 0,则令 sim(u,v)=0。
 - 
选取最相似的用户
根据上述相似度,将其他所有用户与目标用户排序,取前 K=3 个最相似的用户构成集合 Ku。 - 
预测评分
对于目标用户 u 未评分的电影 j,根据相似用户的评分预测其评分:
 - 
生成推荐列表
对所有预测评分 r^u,j 按从大到小排序,若相同则按电影编号从小到大排序,取前 T 个电影编号作为推荐结果。 
代码实现
import numpy as np
def recommend(ratings, U, T, K=3):
    # ratings: 大小为 (N, M) 的评分矩阵
    # U: 目标用户编号
    # T: 推荐电影数量
    # K: 最相似用户的数量,默认 3
    N, M = ratings.shape
    # 计算每个用户的平均评分(仅对已评分电影)
    user_avg = np.zeros(N)
    for u in range(N):
        rated = ratings[u] > 0
        if np.any(rated):
            user_avg[u] = ratings[u, rated].mean()
        else:
            user_avg[u] = 0.0
    # 计算目标用户 U 与其他用户的 Pearson 相似度
    sims = np.zeros(N)
    for v in range(N):
        if v == U:
            continue
        # 找到共同评分的电影索引
        mask = (ratings[U] > 0) & (ratings[v] > 0)
        if not np.any(mask):
            sims[v] = 0.0
            continue
        # 提取评分并去中心化
        ru = ratings[U, mask] - user_avg[U]
        rv = ratings[v, mask] - user_avg[v]
        denom = np.sqrt(np.sum(ru ** 2)) * np.sqrt(np.sum(rv ** 2))
        if denom == 0:
            sims[v] = 0.0
        else:
            sims[v] = np.sum(ru * rv) / denom
    # 选取与 U 最相似的前 K 个用户
    top_k = np.argsort(-sims)[:K]
    # 对 U 未评分的电影进行评分预测
    preds = np.zeros(M)
    for j in range(M):
        if ratings[U, j] > 0:
            # 已评分电影跳过
            preds[j] = -np.inf
            continue
        # 收集相似用户对电影 j 的评分偏差
        num = 0.0
        den = 0.0
        for v in top_k:
            if sims[v] == 0:
                continue
            if ratings[v, j] > 0:
                num += sims[v] * (ratings[v, j] - user_avg[v])
                den += abs(sims[v])
        # 如果没有用户提供评分,则使用目标用户的平均评分
        if den == 0.0:
            preds[j] = user_avg[U]
        else:
            preds[j] = user_avg[U] + num / den
    # 按预测评分排序,取前 T 个电影编号
    # 若预测相同,则电影编号小的优先
    recs = np.argsort(-preds, kind='stable')[:T]
    return recs
if __name__ == '__main__':
    # 读入数据
    N, M = map(int, input().split())
    ratings = np.array([list(map(int, input().split())) for _ in range(N)])
    U = int(input().strip())
    T = int(input().strip())
    # 调用推荐函数并输出结果
    recommendations = recommend(ratings, U, T)
    print(' '.join(map(str, recommendations)))
        题目内容
你是一家视频网站的数据工程师,公司希望为用户提供个性化的电影推荐,以提升用户的观看体验。团队决定采用基于协同过滤的推荐算法,通过分析用户的历史评分数据,找出与目标用户兴趣相似的其他用户,进而推荐他们喜欢的电影。你的任务是编写一个程序,基于用户的评分数据,实现一个简单的用户协同过滤推荐系统。
请你帮助团队实现一个使用NumPy库的程序,基于协同过滤算法为指定用户生成电影推荐列表。具体要求如下: 1.读取输入数据集,包含(N)个用户对(M)部电影的评分矩阵,评分范围为1−5的整数,未评分记为0。
2.读取目标用户的编号(U),对其进行电影推荐。
3.计算用户之间的相似度,使用皮尔逊相关系数(PearsonCorrelationCoefficient)。
4.根据相似度选取前(K)个最相似的用户,默认(K−3)
5.根据相似用户的评分,预测目标用户未评分电影的评分。
输出目标用户最有可能喜欢的前(T)部电影的编号,按照预测评分从高到低排序,若评分相同则按电影编号从小到大排序。
注意: 1.在预测评分时,即使所有相似用户都未对某个电影评分,也不应忽略该电影, 将预测评分设为目标用户的平均评分。 2.在计算相似度时,对于没有共同评分项目的用户,仍需将其相似度设为0,而 非忽略,以免遗漏潜在的相似用户。
输入描述
- 第一行包含两个整数(N)和(M),表示用户数量和电影数量。
 - 接下来的(N)行,每行包含(M)个整数,表示用户对电影的评分,未评分记为0,评分范围为1−5。
 - 接下来一行包含一个整数(U),表示目标用户的编号(从0开始)。
 - 最后一行包含一个整数(T),表示需要推荐的电影数量。
 
输出描述
- 输出一行,包含(T)个整数,表示推荐的电影编号(从0开始),按预测评分从高到低排序,编号之间用空格分隔。
 
补充说明
皮尔逊相关系数
两个用户(u)和(v)的相似度计算公式为:

其中:
- (∣)为用户(u)和(v)都评分过的电影集合。
 - (ru,i)为用户(u)对电影(i)的评分。
 - (r)为用户(u)的平均评分。
 - 评分预测
 
对于目标用户(u)未评分的电影(j),预测评分的计算公式为:

其中:
- (K)为与用户(u)最相似的前(K)个用户集合。
 - (rv,j)为用户(v)对电影j的评分。
 
样例1
输入
5 5
5 3 0 1 0
4 0 0 1 0
1 1 0 5 0
0 0 5 4 0
0 0 5 4 0
0 
2 
输出
2 4
说明
- 目标用户为编号0的用户
 - 计算用户之间的相似度,找到与目标用户最相似的3个用户。
 - 预测目标用户未评分的电影2和4的评分。
 - 推荐评分最高的前2部电影,分别是电影编号2和4。