参考官方文档:https://yiyibooks.cn/sorakunnn/surprisesurprise-v1.0.5/surprise-v1.0.5/index.html
对官方文档代码略有调整,便于理解记忆。

安装

pip3 install scikit-surprise

1. 进阶过程

从代码量上看,这是个由少到多到少的过程。

  1. 读入数据->选择模型->模型训练->模型预测
  2. 读入数据->(数据处理进阶)数据划分->选择模型->模型训练->模型预测
  3. 读入数据->数据划分->选择模型->(训练进阶)k-flod训练->模型预测
  4. 读入数据->数据划分->(模型进阶)设定模型及参数->k-flod训练->模型预测
  5. 读入数据->数据划分->(设定模型及参数->k-flod训练进阶)网络调参->模型预测

2. 数据格式

2.1 文件数据格式

data.txt

  1. 1,1,1
  2. 1,2,2
  3. 1,3,3
  4. 1,4,4
  5. 1,5,5
  6. 2,1,1
  7. 2,2,2
  8. 2,3,3
  9. 2,4,4
  10. 2,5,5
  11. 3,1,1
  12. 3,2,2
  13. 3,3,3
  14. 3,4,4
  15. 3,5,5
  16. 4,1,1
  17. 4,2,2
  18. 4,3,3
  19. 4,4,4
  20. 4,5,5
  21. 5,2,2
  22. 5,3,3

要求
1.无法识别中文,如果有中文,需要将其转换成ID号再进行操作
2.不能有表头,需要去掉表头和元数据中有中文的列
每一行说明了user对item的评分,比如“2,1,1”,是指user-2对item-1的评分是1

2.2 dataframe数据格式

  1. # dataFrame 形式:
  2. ratings_dict = {'itemID': [1, 1, 1, 2, 2],
  3. 'userID': ['a','b','c','a','c'],
  4. 'rating': [3, 2, 4, 3, 1]}
  5. df = pd.DataFrame(ratings_dict)

2.3 数据处理样式

内置数据集。格式与文件数据一致,只是读取方式不一样。

  1. from surprise import Dataset
  2. # 默认载入movielens数据集
  3. data = Dataset.load_builtin('ml-100k')

文件数据

  1. from surprise import Dataset, Reader
  2. # 指定文件所在路径
  3. file_path = './mydata.csv'
  4. # 告诉文本阅读器,文本的格式是怎么样的
  5. reader = Reader(line_format='user item rating', sep=',')
  6. # 加载数据
  7. data = Dataset.load_from_file(file_path, reader=reader)
  8. trainset = data.build_full_trainset()
  9. # 上面这一段代码读取之前构建的本地数据集’mydata.csv’,并用Reader读取数据,将数据加载为Dataset结构。
  10. # 这里要注意的是,Dataset结构并不是surprise结构直接进行计算的最终结构,
  11. # 还需要通过data.build_full_trainset()将其转换为Trainset这样的数据结构,才能在后续过程中直接用于训练。
  12. # 为了下面 "模型训练的参数" 统一变量,将 trainset 改为 data
  13. data = data.build_full_trainset()

dataframe数据

  1. from surprise import Dataset, Reader
  2. # #仍然需要一个reader,但只需要 rating_scale param。
  3. reader = Reader(rating_scale=(1, 5))
  4. # The columns must correspond to user id, item id and ratings (in that order).
  5. # #列必须对应于用户ID,项目ID和评级(按此顺序)。
  6. data = Dataset.load_from_df(df[['userID', 'itemID', 'rating']], reader)
  7. # 这里要注意的是,Dataset结构并不是surprise结构直接进行计算的最终结构,
  8. # 还需要通过data.build_full_trainset()将其转换为Trainset这样的数据结构,才能在后续过程中直接用于训练。
  9. data = data.build_full_trainset()

3. 实战

注意

  1. 以下数据采用内置数据集,数据格式就是文件数据的格式。
  2. 代码时刻在变,不变的是变量名称,要记清楚变量对应的含义,逐个对比看下去就自然明白了。

data: 数据变量
algo: 模型变量
measures:评价指标
cv: k折数

  1. 预测方式只在“进阶过程 1”写,其余略
  2. 实战分为两种模型,一种是 基于隐语义的SVD模型,一种是基于内存的KNN模型(包括了userCF和itemCF【根据参数user_based:False来指定 】;非常耗内存,慎用!)

进阶过程 1

读入数据->选择模型->模型训练->模型预测

  1. from surprise import SVD
  2. from surprise import Dataset
  3. # 加载movielens-100k数据集(本地没有的情况会自动下载)
  4. data = Dataset.load_builtin('ml-100k')
  5. trainset = data.build_full_trainset() # 实例化数据
  6. # 选择模型:此处使用著名的SVD算法
  7. algo = SVD()
  8. # 模型训练
  9. algo.fit(trainset)
  10. uid = str(196) # raw user id (as in the ratings file). They are **strings**!
  11. iid = str(302) # raw item id (as in the ratings file). They are **strings**!
  12. # get a prediction for specific users and items.
  13. # 模型预测
  14. pred = algo.predict(uid, iid, r_ui=4, verbose=True)

结果

  1. user: 196 item: 302 r_ui = 4.00 est = 4.32 {'was_impossible': False}

进阶过程 2

读入数据->(数据处理进阶)数据划分->选择模型->模型训练->模型评价->模型预测(预测方式同上)
使用train_test_split()对给定尺寸的trainset和testset进行采样
你会发现,实例化数据已经被 train_test_split() 所取代了

  1. from surprise import SVD
  2. from surprise import Dataset
  3. from surprise import accuracy
  4. from surprise.model_selection import train_test_split
  5. #加载movielens-100k数据集(本地没有的情况会自动下载)
  6. data = Dataset.load_builtin('ml-100k')
  7. # 简单的随机trainset和testset
  8. #test set is made of 25% of the ratings.
  9. trainset, testset = train_test_split(data, test_size=.25)
  10. algo = SVD()
  11. #在trainset上训练算法,并用testset预测评分
  12. algo.fit(trainset)
  13. predictions = algo.test(testset)
  14. # 然后计算RMSE
  15. accuracy.rmse(predictions)

结果

  1. RMSE: 0.9336

进阶过程 3

读入数据->数据划分->选择模型->(训练进阶)k-flod训练->模型评价->模型预测(预测方式同上)
使用cross_validate()函数实现

  1. from surprise import SVD
  2. from surprise import Dataset
  3. from surprise import accuracy
  4. from surprise.model_selection import KFold
  5. # 加载 movielens-100k 数据集
  6. data = Dataset.load_builtin('ml-100k')
  7. # 定义一个交叉验证迭代器
  8. kf = KFold(n_splits=3)
  9. algo = SVD()
  10. for trainset, testset in kf.split(data):
  11. # 训练并测试算法
  12. algo.fit(trainset)
  13. predictions = algo.test(testset)
  14. # 计算并打印 RMSE(均方根误差,Root Mean Squared Error)
  15. accuracy.rmse(predictions, verbose=True)

结果

  1. RMSE: 0.9429
  2. RMSE: 0.9405
  3. RMSE: 0.9474

进阶过程 4

读入数据->数据划分->(模型进阶)设定模型及参数->k-flod训练->模型评价->模型预测(预测方式同上)
本质只是替换了上面的SVD()模型,和给新模型设立一些参数,参数bsl_options、sim_options先不管,后面看“重要参数”一节详细介绍,这里当做占位符即可。

用第10~18行替换了svd()模型

  1. from surprise import KNNBasic
  2. from surprise import Dataset
  3. from surprise import accuracy
  4. from surprise.model_selection import KFold
  5. # 加载 movielens-100k 数据集
  6. data = Dataset.load_builtin('ml-100k')
  7. # 定义一个交叉验证迭代器
  8. kf = KFold(n_splits=3)
  9. bsl_options = {'method': 'sgd',
  10. 'learning_rate': .00005,
  11. }
  12. sim_options = {'name': 'pearson_baseline',
  13. 'user_based': False }
  14. algo = KNNBasic(bsl_options=bsl_options, sim_options=sim_options)
  15. for trainset, testset in kf.split(data):
  16. # 训练并测试算法
  17. algo.fit(trainset)
  18. predictions = algo.test(testset)
  19. # 计算并打印 RMSE(均方根误差,Root Mean Squared Error)
  20. accuracy.rmse(predictions, verbose=True)

结果
主要看 RMSE部分,其余都是运算日志

  1. Estimating biases using sgd...
  2. Computing the pearson_baseline similarity matrix...
  3. Done computing similarity matrix.
  4. RMSE: 0.9690
  5. Estimating biases using sgd...
  6. Computing the pearson_baseline similarity matrix...
  7. Done computing similarity matrix.
  8. RMSE: 0.9612
  9. Estimating biases using sgd...
  10. Computing the pearson_baseline similarity matrix...
  11. Done computing similarity matrix.
  12. RMSE: 0.9644

进阶过程 5

读入数据->(设定模型及参数->k-flod训练 进阶)交叉验证函数训练->模型评价—>模型预测(预测方式同上)
这里开始减少代码,交叉验证本质就是k-flod训练 ,这里只是代码少了。
通过cross_validate()实现

  1. from surprise import KNNBasic
  2. from surprise import Dataset
  3. from surprise.model_selection import cross_validate
  4. #加载movielens-100k数据集(本地没有的情况会自动下载)
  5. data = Dataset.load_builtin('ml-100k')
  6. bsl_options = {'method': 'sgd',
  7. 'learning_rate': .00005,
  8. }
  9. sim_options = {'name': 'pearson_baseline',
  10. 'user_based': False }
  11. algo = KNNBasic(bsl_options=bsl_options, sim_options=sim_options)
  12. # 运行5折(5-fold)交叉验证过程并打印结果
  13. cross_validate(algo, data, measures=['RMSE', 'MAE'], cv=5, verbose=True)

结果

  1. Fold 1 Fold 2 Fold 3 Fold 4 Fold 5 Mean Std
  2. RMSE (testset) 0.9559 0.9464 0.9536 0.9467 0.9476 0.9500 0.0039
  3. MAE (testset) 0.7458 0.7399 0.7456 0.7395 0.7401 0.7422 0.0029
  4. Fit time 2.10 1.98 1.92 1.88 1.98 1.97 0.07
  5. Test time 3.48 3.62 3.66 4.00 4.14 3.78 0.25
  6. {'test_rmse': array([0.95593654, 0.94643255, 0.95357356, 0.94668252, 0.94756849]),
  7. 'test_mae': array([0.74581825, 0.73990404, 0.74556115, 0.73952742, 0.74006751]),
  8. 'fit_time': (2.0961997509002686,
  9. 1.9842283725738525,
  10. 1.9201650619506836,
  11. 1.876598834991455,
  12. 1.982205867767334),
  13. 'test_time': (3.483961820602417,
  14. 3.622770309448242,
  15. 3.658863067626953,
  16. 3.996823310852051,
  17. 4.144801139831543)}

进阶过程 6

读入数据->交叉验证 进阶)网络调参->模型评价->模型预测
得到参数,再重新训练模型->模型评价->模型预测
6.1 SVD模型用法

  1. from surprise import SVD
  2. from surprise import Dataset
  3. from surprise.model_selection import GridSearchCV
  4. # 使用 movielens-100K 数据集
  5. data = Dataset.load_builtin('ml-100k')
  6. param_grid = {'n_epochs': [5, 10], 'lr_all': [0.002, 0.005],
  7. 'reg_all': [0.4, 0.6]}
  8. gs = GridSearchCV(SVD, param_grid, measures=['rmse', 'mae'], cv=3)
  9. gs.fit(data)
  10. # 最佳 RMSE 得分
  11. print(gs.best_score['rmse'])
  12. # 能达到最佳 RMSE 得分的参数组合
  13. print(gs.best_params['rmse'])

结果

  1. 0.961300130118
  2. {'n_epochs': 10, 'lr_all': 0.005, 'reg_all': 0.4}

6.2 knn模型用法
诸如bsl_options和sim_options之类的字典参数需要特殊处理。
一套组合拳,直接下班等结果!

  1. from surprise import KNNBasic
  2. from surprise import Dataset
  3. from surprise.model_selection import GridSearchCV
  4. # 使用 movielens-100K 数据集
  5. data = Dataset.load_builtin('ml-100k')
  6. param_grid = {
  7. 'bsl_options': {'method': ['als', 'sgd'],
  8. 'reg': [1, 2]},
  9. 'k': [2, 3],
  10. 'sim_options': {'name': ['msd', 'cosine'],
  11. 'min_support': [1, 5],
  12. 'user_based': [False]}
  13. }
  14. gs = GridSearchCV(KNNBasic, param_grid, measures=['rmse', 'mae'], cv=3)
  15. gs.fit(data)
  16. # 最佳 RMSE 得分
  17. print(gs.best_score['rmse'])
  18. # 能达到最佳 RMSE 得分的参数组合
  19. print(gs.best_params['rmse'])

结果

  1. 1.0891580028064445
  2. {
  3. 'bsl_options': {'method': 'als', 'reg': 1},
  4. 'k': 3,
  5. 'sim_options': {
  6. 'name': 'msd',
  7. 'min_support': 5,
  8. 'user_based': False
  9. }
  10. }

4. 重要参数

参数分为两块:模型参数(含参数中的参数)和训练参数。

模型参数

主要有优化函数(又称基线估计 Baselines estimates)和相似性度量参数(Similarity measure)
对应到模型变量名称:
bsl_options : 优化函数(又称基线估计 Baselines estimates)
sim_options: 相似性度量参数(Similarity measure)

bsl_options

有两种优化函数:

  • 随机梯度下降法(SGD,Stochastic Gradient Descent)
  • 交替最小二乘法(ALS,Alternating Least Squares)

随机梯度下降法参数:

  • reg:优化的成本函数的正则化参数
  • learning_rate:学习速率
  • n_epochs:SVD过程的迭代次数

交替最小二乘法参数:

  • reg_i : 项目的正则化参数 ,默认10
  • reg_u: 用户的正则化参数, 默认15
  • n_epochs:ALS过程的迭代次数
  1. # 用法示例 1
  2. print('Using ALS')
  3. bsl_options = {'method': 'als',
  4. 'n_epochs': 5,
  5. 'reg_u': 12,
  6. 'reg_i': 5
  7. }
  8. algo = BaselineOnly(bsl_options=bsl_options)
  9. # 用法示例 2
  10. print('Using ALS')
  11. print('Using SGD')
  12. bsl_options = {'method': 'sgd',
  13. 'learning_rate': .00005,
  14. }
  15. algo = BaselineOnly(bsl_options=bsl_options)

sim_options

许多算法都使用相似性度量来评估 rating。 它们的配置方式与基线评估类似:您只需在创建算法时传递sim_options参数即可。 这个参数是一个包含以下(均为可选)关键字的字典:

  • ‘name’:similarities模块中预先定义的相似度的名称。 默认值为’MSD’。可多选,看”进阶过程6”。具体参数看本节下的“name的参数”
  • ‘user_based’:选择在用户/物品间计算相似度。 对预测算法性能有巨大影响。 默认值True。
  • ‘min_support’: The minimum number of common items (when ‘user_based’ is ‘True’) or minimum number of common users (when ‘user_based’ is ‘False’) for the similarity not to be zero. Simply put, if |Iuv|<min_support then sim(u,v)=0. 对 Item 也是一样。
  • ‘shrinkage’:要应用的收缩参数(仅与pearson_baseline相似度相关)。 默认值为100。

name的参数:

cosine 计算所有成对的用户(或项目)之间的余弦相似度。
msd 计算所有用户对(或项目)之间的均方差相似度。
pearson 计算所有用户对(或项目)之间的皮尔逊相关系数。
pearson_baseline 使用基线而不是平均值来计算所有成对的用户(或项目)之间的(缩小的)Pearson相关系数。

示例:

  1. # 用法示例 1
  2. sim_options = {'name': 'cosine',
  3. 'user_based': False # 计算物品间的相似度
  4. }
  5. algo = KNNBasic(sim_options=sim_options)
  6. # 用法示例 2
  7. sim_options = {'name': 'pearson_baseline',
  8. 'shrinkage': 0 # 不收缩
  9. }
  10. algo = KNNBasic(sim_options=sim_options)

综合用法示例

  1. bsl_options = {'method': 'sgd',
  2. 'learning_rate': .00005,
  3. }
  4. sim_options = {'name': 'pearson_baseline',
  5. 'user_based': False }
  6. algo = KNNBasic(bsl_options=bsl_options, sim_options=sim_options)

训练参数

data:数据
algo:模型
measures:评价指标 ‘rmse’, ‘mae’ ,可多选,measures = [‘rmse’, ‘mae’]
cv : k 折数
verbose : bool 日志是否打印