【笔记6】用pandas实现条目数据格式的推荐算法 (基于物品的协同)

简介:
'''
基于物品的协同推荐

矩阵数据


说明:
1.修正的余弦相似度是一种基于模型的协同过滤算法。我们前面提过,这种算法的优势之
一是扩展性好,对于大数据量而言,运算速度快、占用内存少。

2.用户的评价标准是不同的,比如喜欢一个歌手时有些人会打4分,有些打5分;不喜欢时
有人会打3分,有些则会只给1分。修正的余弦相似度计算时会将用户对物品的评分减去
用户所有评分的均值,从而解决这个问题。




如何预测用户对给定物品的打分?
一、基于用户协同
方法1:用户之间的距离/相似度(K近邻算法)
二、基于物品协同
方法1:物品之间的相似度(修正的余弦相似度)
方法2:物品之间的差异值(加权Slope One算法)

由于使用的是用户产生的各种数据,因此又称为社会化过滤算法。


协同过滤会遇到的种种问题,包括数据的稀疏性和算法的可扩展性。此外,协同过滤算法倾向于推荐那些已经很流行的物品。

这类推荐系统会让流行的物品更为流行,冷门的物品更无人问津。
-- Daniel Fleder & Kartik Hosanagar 2009 《 推荐系统对商品分类的影响》
'''

import pandas as pd
from io import StringIO

#数据类型一:条目(用户、商品、打分)(避免巨型稀疏矩阵)
csv_txt = '''"David","Imagine Dragons",3
"David","Daft Punk",5
"David","Lorde",4
"David","Fall Out Boy",1
"Matt","Imagine Dragons",3
"Matt","Daft Punk",4
"Matt","Lorde",4
"Matt","Fall Out Boy",1
"Ben","Kacey Musgraves",4
"Ben","Imagine Dragons",3
"Ben","Lorde",3
"Ben","Fall Out Boy",1
"Chris","Kacey Musgraves",4
"Chris","Imagine Dragons",4
"Chris","Daft Punk",4
"Chris","Lorde",3
"Chris","Fall Out Boy",1
"Tori","Kacey Musgraves",5
"Tori","Imagine Dragons",4
"Tori","Daft Punk",5
"Tori","Fall Out Boy",3'''

#数据类型一:条目(用户、商品、打分)(避免巨型稀疏矩阵)
#根据《data minning guide》第85页的users2数据
csv_txt2 = '''"Amy","Taylor Swift",4
"Amy","PSY",3
"Amy","Whitney Houston",4
"Ben","Taylor Swift",5
"Ben","PSY",2
"Clara","PSY",3.5
"Clara","Whitney Houston",4
"Daisy","Taylor Swift",5
"Daisy","Whitney Houston",3'''

df = None

#方式一:加载csv数据
def load_csv_txt():
    global df
    #df = pd.read_csv(StringIO(csv_txt2), header=None, names=['user','goods','rate'])
    df = pd.read_csv("BX-Book-Ratings.csv", header=None, names=['user','goods','rate'], sep=';')
    
    
    
print('测试:读取数据')
load_csv_txt()
#load_json_txt()


#=======================================
# 注意:不需要build_xy
#=======================================

# 计算两个物品相似度
def computeSimilarity(goods1, goods2):
    '''根据《data minning guide》第71页的公式s(i,j)'''
    df1 = df.ix[df['goods'].isin([goods1]), ['user','rate']]
    df2 = df.ix[df['goods'].isin([goods2]), ['user','rate']]
    
    df3 = pd.merge(df1, df2, on='user', how='inner') #只保留两种商品都被同一用户评过分的商品的评分
    
    # 注意:先构造了一个只有index=df3['user']的pd.Series,目的是方便下一步的减
    mean = pd.Series(df3['user'].tolist(), index=df3['user']).apply(lambda x:df.ix[df['user']==x, 'rate'].mean())
    
    # 每行的用户评分都减去了该用户的平均评分
    df3.index = df3['user']
    df3['rate_x'] = df3['rate_x'] - mean
    df3['rate_y'] = df3['rate_y'] - mean
    
    # 返回修正的余弦相似度
    return sum(df3['rate_x'] * df3['rate_y']) / (sum(df3['rate_x']**2) * sum(df3['rate_y']**2))**0.5 # merge之后默认的列名:rate_x,rate_y
    
    
# csv_txt
#print('\n测试:计算Kacey Musgraves与Imagine Dragons的相似度')
#print(computeSimilarity("Kacey Musgraves","Imagine Dragons"))


#为了让公式的计算效果更佳,对物品的评价分值最好介于-1和1之间
def rate2newrate(rate):
    '''根据《data minning guide》第76页的公式NR(u,N)'''
    ma, mi = df['rate'].max(), df['rate'].min()
    return (2*(rate - mi) - (ma - mi))/(ma - mi)
    
    
#已知rate2newrate求newrate2rate
def newrate2rate(new_rate):
    '''根据《data minning guide》第76页的公式R(u,N)'''
    ma, mi = df['rate'].max(), df['rate'].min()
    return (0.5 * (new_rate + 1) * (ma - mi)) + mi
    
#print('\n测试:计算3的new_rate值')
#print(rate2newrate(3))

#print('\n测试:计算0.5的rate值')
#print(newrate2rate(0.5))



# 预测给定用户对物品的可能评分(对评分进行了修正/还原)
def p2(user, goods):
    '''根据《data minning guide》第75页的公式p(u,i)'''
    #assert pd.isnull(df.ix[df['user']==user & df['goods']==goods, 'rate']) # 必须用户对给定物品尚未评分
    
    #用户对其它所有已打分物品的打分数据
    df2 = df.ix[df['user']==user, ['goods','rate']]
    s1 = pd.Series(df2['rate'].tolist(), index=df2['goods'])
    s1 = s1.apply(lambda x:rate2newrate(x)) #修正
    s2 = s1.index.to_series().apply(lambda x:computeSimilarity(x, goods)) #打分物品分别与给定物品的相似度
    
    return newrate2rate(sum(s1 * s2) / sum(abs(s2)))#还原


# csv_txt
#print('\n测试:预测David对Kacey Musgraves的打分(修正)')
#print(p2("David","Kacey Musgraves"))




#==================================
# 下面是Slope One算法
#
# 两个步骤:
# 1. 计算差值
# 2. 预测用户对尚未评分物品的评分
#==================================

# 1.计算两物品之间的差异
def dev(goods1, goods2):
    '''根据《data minning guide》第80页的公式dev(i,j)'''
    #s = (df[goods1] - df[goods2]).dropna()
    
    df1 = df.ix[df['goods'].isin([goods1]), ['user','rate']]
    df2 = df.ix[df['goods'].isin([goods2]), ['user','rate']]
    print('df1\n', df1)
    print('df2\n', df2)
    
    df3 = pd.merge(df1, df2, on='user', how='inner') #只保留两个物品都有评分的用户的评分
    print(df3)
    print(df3.shape[0])
    
    d = sum(df3['rate_x'] - df3['rate_y'])/df3.shape[0] # 差异值
    return d, df3.shape[0] #返回差异值,及权值(同时对两个物品打分的人数)

# csv_txt
#print('\n测试:计算Kacey Musgraves与Imagine Dragons的分数差异')
#print(dev("Kacey Musgraves","Imagine Dragons"))


#计算所有两两物品之间的评分差异,得到方阵pd.DataFrame(行对列)
def get_dev_table():
    '''根据《data minning guide》第87页的表'''
    #goods_names = df.columns.tolist()
    goods_names = df['goods'].unique().tolist()
    df2 = pd.DataFrame(.0, index=goods_names, columns=goods_names) #零方阵
    
    for i,goods1 in enumerate(goods_names):
        for goods2 in goods_names[i+1:]:
            d, _ = dev(goods1, goods2) # 注意:只取了物品差异值
            df2.ix[goods1, goods2] = d
            df2.ix[goods2, goods1] = -d # 对称的位置取反
    
    return df2
    
    
#print('\n测试:计算所有两两物品之间的评分差异表')
#print(get_dev_table())


#预测某用户对给定物品的评分
# 加权Slope One算法
def slopeone(user, goods):
    '''根据《data minning guide》第82页的公式p(u,j)'''
    df1 = df.ix[df['user'].isin([user]), ['goods', 'rate']]
    
    s1 = pd.Series(df1['rate'].tolist(), index=df1['goods']) # 用户对已打分物品的打分数据
    
    s2 = s1.index.to_series().apply(lambda x:dev(goods, x)) # 待打分物品与已打分物品的差异值及权值
    
    s3 = s2.apply(lambda x:x[0]) #差异值
    s4 = s2.apply(lambda x:x[1]) #权值
    #print(s1, s3, s4)
    
    return sum((s1 + s3) * s4)/sum(s4)
    
    
#print('\n测试:加权Slope One算法,预测用户Ben对物品Whitney Houston的评分')
#print(slopeone('Ben', 'Whitney Houston')) # 3.375


print('\n测试:加权Slope One算法,预测用户276744对书本0600570967的评分') #大数据量
print(slopeone(276744, '0600570967'))

本文转自罗兵博客园博客,原文链接:http://www.cnblogs.com/hhh5460/p/6121924.html ,如需转载请自行联系原作者
相关文章
|
1月前
|
算法
【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点
【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点
65 1
|
1月前
|
算法 索引
❤️算法笔记❤️-(每日一刷-141、环形链表)
❤️算法笔记❤️-(每日一刷-141、环形链表)
46 0
|
1月前
|
算法
【❤️算法笔记❤️】-(每日一刷-876、单链表的中点)
【❤️算法笔记❤️】-(每日一刷-876、单链表的中点)
43 0
|
1月前
|
算法
【❤️算法笔记❤️】-每日一刷-23、合并 K 个升序链表
【❤️算法笔记❤️】-每日一刷-23、合并 K 个升序链表
32 0
|
1月前
|
存储 算法
【❤️算法笔记❤️】-每日一刷-21、合并两个有序链表
【❤️算法笔记❤️】-每日一刷-21、合并两个有序链表
89 0
|
1月前
|
数据可视化 数据挖掘 数据处理
模型预测笔记(四):pandas_profiling生成数据报告
本文介绍了pandas_profiling库,它是一个Python工具,用于自动生成包含多种统计指标和可视化的详细HTML数据报告,支持大型数据集并允许自定义配置。安装命令为`pip install pandas_profiling`,使用示例代码`pfr = pandas_profiling.ProfileReport(data_train); pfr.to_file("./example.html")`。
45 1
|
1月前
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
35 1
|
1月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
59 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
1月前
|
算法
❤️算法笔记❤️-(每日一刷-160、相交链表)
❤️算法笔记❤️-(每日一刷-160、相交链表)
17 1
|
1月前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
14 0