010. (4.10-4.12) 根据下载记录数据集和2种算法 设计推荐系统(代码后面更新)

离线实验步骤

这次的推荐算法和对其的评测主要依靠离线实验,所以首先回顾下:
在这里插入图片描述

读取数据集内容,并划分为训练集和测试集

声明

这次任务的数据集是QQ音乐部分用户的下载记录。dat文件中每一行包括用户ID和下载歌曲所对应的艺术家(一个用户ID在多行中出现)。我选择将测试集和训练集定义为字典类型,value为列表类型。

读取

我用的是 with open语句代开文件,并把数据放入列表,其中还包括去除换行符等特殊字符。

如何解决收集dat文件中数据后的非英文字符?

在这里插入图片描述在这里插入图片描述
打开文件时,参数encoding=‘UTF-8’,和’rb’读取的内容不同。
使用codecs模块可以指定一个编码进行文件处理

理解:

划分

用户行为数据集按照均匀分布随机分成M份,挑选一份作为测试集,将剩下的M-1份作为训练集。进行M次实验就可以得到M个不同的训练集和测试集。如果数据集够大,模型足够简单,为了快速通过离线实验初步地选择算法,也可以只进行一次实验。
在这里插入图片描述

期间我用print输出测试集和训练集来检查,内容很多时console貌似不能显示全部内容

此外,为了方便,我将训练集和测试集储存为pkl格式,从而利用数据包。

基于用户的协同过滤算法

算法公式(可通过矩阵实现,我用的是字典矩阵):
  • 相似度:在这里插入图片描述
    经改进后:
    在这里插入图片描述
  • 兴趣度:在这里插入图片描述
过程记录

注意在字典键不存在的情况下赋值,应先dictdefault 或 setdefault,不确定是否存在用get。

dictdefault的效率应该高于setdefault。

由于建立矩阵的时间接近2分钟,可以考虑pickle。

因为计算准确率、召回率和覆盖率都要有遍历过程,最好将它们的计算过程整合,提高效率。

不止于此,如程序能先有更合理的结构,再在细节上处理(如一些第三方库提供的功能可能更快捷),可有效提升效率。

对数据集dat文件encoding='UTF-8’后(与’rb’读取的内容不同),再用算法推荐的结果:
大致结果
小修小改:
在这里插入图片描述

基于物品的协同过滤算法(与基于用户有共通之处)

算法公式

基于物品的协同过滤算法主要分为两步。
(1) 计算物品之间的相似度。
(2) 根据物品的相似度和用户的历史行为给用户生成推荐列表。

  • 相似度:
    在这里插入图片描述
    也是要在计算相似度前,先建立倒排表,但这次是用户->艺术家的对应关系。
    在这里插入图片描述

  • 兴趣度:
    在这里插入图片描述
    改进版:在这里插入图片描述

  • 相似度归一:
    在这里插入图片描述

过程记录(主要是运算快?)

因为我的测试集和训练集字典是用户对应艺术家,所以不用建立倒排表了

可以使相似度归一再得到最终的相似矩阵

程序运行速度比UserCF快了太多

一比矩阵文件大小吓一跳,可能我的UserCF算法还有缺陷
在这里插入图片描述

覆盖率一般不会过高。因为相似度归一 除的是小于1的数,所以数值上看兴趣值比UserCF大

小修小改:在这里插入图片描述

笔记

1.python中数组和列表读取一列的方法

2.Python中代码换行,还有三引号方法

3.*在进行文件处理时,发现函数传入参数和返回对象不是同者,即使同名也如此。

4.operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号。要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。

from operator import itemgetter

通过公共键对字典列表排序:itemgetter
如itemgetter(0)根据字典keys排序,1则是value

5.Python可以构造多维字典,而numpy库包括数组、矩阵等功能,pandas 是基于 Numpy 构建的。
Python二维字典的几个小例子
Python numpy中矩阵的用法总结

6.numpy 和 pandas:

Numpy:是数值计算的扩展包,它能高效处理N维数组,复杂函数,线性代数
Panadas:是做数据处理。市python的一个数据分析包
numpy对象最重要特点向量化运算,pandas对象最重要特点是字典和列表混合

7.字典的get、setdefault、from collections import defaultdict,defaultdict()

Python中通过Key访问字典,当Key不存在时,会引发‘KeyError’异常。为了避免这种情况的发生,可以使用collections类中的defaultdict()方法来为字典提供默认值。(或者用get,setdefault等方法)

from collections import defaultdict
# defaultdict接受一个工厂函数作为参数
dict1 = defaultdict(int)
dict2 = defaultdict(set)
dict3 = defaultdict(str)
dict4 = defaultdict(list)
dict1[2] ='two'

print(dict1[1])
print(dict2[1])
print(dict3[1])
print(dict4[1])
# 输出:
0
set()

[]
#
>>> d= defaultdict(dict())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    d= defaultdict(dict())
TypeError: first argument must be callable or None

>>> d= defaultdict(dict)
>>> d
defaultdict(<class 'dict'>, {
    
    })

setdefault 和 defaultdict的一个重要区别:
(对代码分析结构发现,影响挺大)

#defaultdict
>>> from collections import defaultdict
>>> d=defaultdict(str)
>>> d['0']
''
>>> d=defaultdict('abc')
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    d=defaultdict('abc')
TypeError: first argument must be callable or None

>>>print(d)
defaultdict(<class 'str'>, {
    
    '0': ''})  

#setdefault
>>> d={
    
    }
>>> for i in range(0,10):
		d.setdefault(str(i),'abc')
>>> d
{
    
    'i': 1, '0': 1, '10': 1, '1': 'abc', '2': 'abc', '3': 'abc', '4': 'abc', '5': 'abc', '6': 'abc', '7': 'abc', '8': 'abc', '9': 'abc'}

通过defaultdict,使用list作第一个参数,再用上setdefault,可以很容易将有对应关系的列表转化为字典,再用list将键-值对序列转换为列表字典。

8.调用函数时,仅接收函数返回值,也会执行其中的输出语句。
9.format的一点笔记

>>> precision = 0.52333
>>> recall=0.2326
>>> coverage=0.9456
>>> print('{:.2%} {:.2%}'.format(precision))
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    print('{:.2%} {:.2%}'.format(precision))
IndexError: tuple index out of range

>>> print('{0:.2%} {0:.2%}'.format(precision))
52.33% 52.33%

>>> print('准确率: {1:.2%}\n召回率: {2:.2%}\n覆盖率: {3:.2%}'.format(precision, recall, coverage))
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module> # 必须指定从0开始!!!,或不设位置!!
IndexError: tuple index out of range

>>> print('准确率: {0:.2%}\n召回率: {1:.2%}\n覆盖率: {2:.2%}'.format(precision, recall, coverage))
准确率: 52.33%
召回率: 23.26%
覆盖率: 94.56%

10 .items()返回列表,列表里用元组储存每一键值对。

猜你喜欢

转载自blog.csdn.net/u013598957/article/details/105435110