计算机软件开发网站建设取什么名字,上海做网站最好的公司,投资网站建设公司多少钱,小程序推广对于推荐系统#xff0c;有很多的很强大的算法。这里作为练习#xff0c;只介绍基本的协同过滤算法#xff08;userbased#xff09;和FM#xff08;通过梯度下降的角度#xff0c;还可以通过交替优化的角度来看#xff09;。 这里的例子是在七月算法的视频中看的#… 对于推荐系统有很多的很强大的算法。这里作为练习只介绍基本的协同过滤算法userbased和FM通过梯度下降的角度还可以通过交替优化的角度来看。 这里的例子是在七月算法的视频中看的分析的内容基于自己的理解并对代码做了部分的勘误。
一简单的user-based协同过滤算法 先来看一眼数据
userss {小明: {中国合伙人: 5.0, 太平轮: 3.0, 荒野猎人: 4.5,老炮儿: 5.0, 我的少女时代: 3.0,肖洛特烦恼: 4.5, 火星救援: 5.0},小红: {小时代4: 4.0, 荒野猎人: 3.0, 我的少女时代: 5.0,
肖洛特烦恼: 5.0, 火星救援: 3.0,后会无期: 3.0},小阳: {小时代4: 2.0, 中国合伙人: 5.0, 我的少女时代: 3.0,
老炮儿: 5.0, 肖洛特烦恼: 4.5,速度与激情7: 5.0},小四: {小时代4: 5.0, 中国合伙人: 3.0, 我的少女时代: 4.0,匆匆那年: 4.0, 速度与激情7: 3.5, 火星救援: 3.5, 后会无期: 4.5},六爷: {小时代4: 2.0, 中国合伙人: 4.0, 荒野猎人: 4.5,老炮儿: 5.0, 我的少女时代: 2.0},小李: {荒野猎人: 5.0, 盗梦空间: 5.0, 我的少女时代: 3.0,
速度与激情7: 5.0, 蚁人: 4.5,老炮儿: 4.0, 后会无期: 3.5},隔壁老王: {荒野猎人: 5.0, 中国合伙人: 4.0,
我的少女时代: 1.0, Phoenix: 5.0,甄嬛传: 4.0, The Strokes: 5.0},邻村小芳: {小时代4: 4.0, 我的少女时代: 4.5,匆匆那年: 4.5, 甄嬛传: 2.5, The Strokes: 3.0}} 这里是假想的一份数据分别是每个用户对于自己看过的电影的评分。这里要进行userbased协同过滤首先就要解释一下什么是userbased协同过滤所谓userbased协同过滤就是把一个用户看成是一条记录然后看到的电影作为属性对应的评分作为属性值。然后通过计算两条记录两个user之间的距离来衡量两条记录两个user的相近度。最后把距离最近的K自己指定的users看过而该user未看过的电影推荐给该user。所以最重要的就是计算距离了下面介绍几种距离的计算方式
1欧几里得距离 def euclidean_dis(rating1, rating2):计算2个打分序列间的欧式距离. 输入的rating1和rating2都是打分dict格式为{小时代4: 1.0, 疯狂动物城: 5.0}distance 0common_ratings Falsefor key in rating1:if key in rating2:distance pow(rating1[key] - rating2[key], 2)common_ratings True# 两个打分序列之间有公共打分电影if common_ratings:return distance# 无公共打分电影else:return float(inf) 2曼哈顿距离 def manhattan_dis(rating1, rating2):计算2个打分序列间的曼哈顿距离. 输入的rating1和rating2都是打分dict格式为{小时代4: 1.0, 疯狂动物城: 5.0}distance 0common_ratings Falsefor key in rating1:if key in rating2:distance abs(rating1[key] - rating2[key])common_ratings True# 两个打分序列之间有公共打分电影if common_ratings:return distance# 无公共打分电影else:return float(inf) 3COS距离 def cos_dis(rating1, rating2):计算2个打分序列间的cos距离. 输入的rating1和rating2都是打分dict格式为{小时代4: 1.0, 疯狂动物城: 5.0}distance 0dot_product_1 0dot_product_2 0common_ratings Falsefor score in rating1.values():dot_product_1 pow(score, 2)for score in rating2.values():dot_product_2 pow(score, 2)for key in rating1:if key in rating2:distance rating1[key] * rating2[key]common_ratings True# 两个打分序列之间有公共打分电影# 注意上面的distance是相似度相似度越大距离就会越小所以用1来减if common_ratings:return 1 - distance/sqrt(dot_product_1 * dot_product_2)# 无公共打分电影else:return 2 4Person距离相关系数 这里使用了
def pearson_dis(rating1, rating2):计算2个打分序列间的pearson距离. 输入的rating1和rating2都是打分dict格式为{小时代4: 1.0, 疯狂动物城: 5.0}sum_xy 0sum_x 0sum_y 0sum_x2 0sum_y2 0n 0for key in rating1:if key in rating2:n 1x rating1[key]y rating2[key]sum_xy x * ysum_x xsum_y ysum_x2 pow(x, 2)sum_y2 pow(y, 2)# now compute denominatordenominator sqrt(sum_x2 - pow(sum_x, 2) / n) * sqrt(sum_y2 - pow(sum_y, 2) / n)# 相关系数的取值在-1到1之间值越大相关性越大距离就越小所以要用1来减一下if denominator 0:return 2else:return 1 - (sum_xy - (sum_x * sum_y) / n) / denominator 有了各种距离的定义我们就可以根据定义的距离来计算两个user之间的想近程度了计算方法如下
# 查找最近邻
def compute_nearest_neighbor(username, users):在给定username的情况下计算其他用户和它的距离并排序distances []# 查找最近邻的时候要除去自身要不然肯定是自己离自己最近了for user in users:if not user username:distance pearson_dis(users[user], users[username])# distance cos_dis(users[user], users[username])# distance manhattan_dis(users[user], users[username])# distance euclidean_dis(users[user], users[username])distances.append((distance, user))distances.sort()print(distances)return distances 最终进行推荐
# 推荐
def recommend(username, users):对指定的user推荐电影# 找到最邻近nearest compute_nearest_neighbor(username, users)[0][1]print(爱好相同的人:, nearest)recommendations []# 找到最邻近看过 但是username本身没有看过的电影 计算推荐neighbor_ratings users[nearest]user_ratings users[username]for artist in neighbor_ratings:if artist not in user_ratings:recommendations.append((artist, neighbor_ratings[artist]))results sorted(recommendations, keylambda artist_tuple: artist_tuple[1], reverseTrue)print(推荐电影:)for result in results:print(result[0], result[1]) 测试
recommend(六爷, userss) 测试结果 二简单的张量分解来实现推荐 首先把数据整理成一个矩阵缺失的用0根据实际情况来定来表示 主要的目标就是填充缺失的评分这里使用FunkSVD其代价函数为
,
详情请参见https://www.cnblogs.com/pinard/p/6351319.html
使用SGD来做优化代码如下
def matrix_factorization(R, P, Q, K, steps10000, alpha0.0002, beta0.02):Q Q.Tfor step in range(steps):for i in range(len(R)):for j in range(len(R[i])):if R[i][j] 0:e_ij R[i][j] - np.dot(P[i, :], Q[:, j])for k in range(K):P[i][k] P[i][k] alpha * (2 * e_ij * Q[k][j] - beta * P[i][k])Q[k][j] Q[k][j] alpha * (2 * e_ij * P[i][k] - beta * Q[k][j])e 0for i in range(len(R)):for j in range(len(R[i])):if R[i][j] 0:e e pow(R[i][j] - np.dot(P[i, :], Q[:, j]), 2)for k in range(K):e e (beta / 2) * (pow(P[i][k], 2) pow(Q[k][j], 2))if e 0.001:breakreturn P, Q.T
使用上述函数进行缺失值的填充
R [[5.0, 0, 0, 3.5, 5.0, 0, 0, 0],[0, 0, 2.5, 0, 0, 4.0, 0, 0],[0, 0, 0, 0, 5.0, 0, 0, 0],[0, 0, 0, 0, 4.5, 0, 0, 0],[5.0, 5.0, 0, 0, 4.0, 0, 0, 5.0],[0, 0, 3.0, 0, 0, 5.0, 0, 0],[4.5, 0, 0, 0, 0, 0, 5.0, 4.5],[3.0, 2.0, 4.5, 4.0, 3.0, 1.0, 5.0, 3.0],[2.0, 2.0, 4.0, 5.0, 0, 0, 4.0, 0],[0, 0, 4.5, 4.0, 0, 0, 0, 0],[0, 0, 0, 3.5, 0, 0, 3.0, 5.0],[0, 0, 0, 0, 0, 5.0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 3.0],[0, 0, 0, 4.5, 3.5, 0, 3.0, 0],[0, 4.5, 0, 0, 5.0, 5.0, 3.0, 4.5],[5.0, 4.0, 0, 3.0, 0, 4.0, 0, 5.0]]
R np.array(R)
M, N np.shape(R)
# 设置隐藏属性的个数为2
K 2
P np.random.rand(M, K)
Q np.random.rand(N, K)
nP, nQ matrix_factorization(R, P, Q, K)
nR np.dot(nP, nQ.T)
nR np.around(nR, decimals1)
print(更新后的得分矩阵为)
print(nR)
运行结果