基本使用
自动进行交叉验证
surprise 有一系列的内建的算法和数据集供用户来进行尝试。在最简单的形式中,它的模型仅需几行代码就可以运行一次交叉验证的流程:
代码如下:
1 | from surprise import SVD |
运行之后的结果应该是如下所示(实际结果可能会因随机性而异):1
2
3
4
5
6
7Evaluating RMSE, MAE of algorithm SVD on 5 split(s).
Fold 1 Fold 2 Fold 3 Fold 4 Fold 5 Mean Std
RMSE 0.9311 0.9370 0.9320 0.9317 0.9391 0.9342 0.0032
MAE 0.7350 0.7375 0.7341 0.7342 0.7375 0.7357 0.0015
Fit time 6.53 7.11 7.23 7.15 3.99 6.40 1.23
Test time 0.26 0.26 0.25 0.15 0.13 0.21 0.06
如果数据集(movielens_100k dataset)还没有下载,load_builtin()方法会提供下载,并将数据集保存在用户目录下的.surprise_data文件夹下,当然,你也可以选择其他地方进行保存。
我们将使用著名的SVD模型,当然其他算法模型亦可以,可以通过查看链接获取更多细节。
cross-validation()方法通过使用cv参数来进行交叉验证的过程。通过计算准确率来衡量效果。我们这里使用了经典的五次交叉验证,但是也可以使用更精彩的交叉验证(查看资料)。
Train-test划分和fit()方法
如果您不想运行完整的交叉验证程序,则可以使用train_test_split()对给定尺寸的trainset和testset进行采样,并使用您选择的精度度量。
你需要选择fit()方法,fit()方法可以在训练集上来训练算法,test()方法将会返回从测试集上生成的预测值。
实例代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from surprise import SVD
from surprise import Dataset
from surprise import accuracy
from surprise.model_selection import train_test_split
# Load the movielens-100k dataset (download it if needed),
data = Dataset.load_builtin('ml-100k')
# sample random trainset and testset
# test set is made of 25% of the ratings.
trainset, testset = train_test_split(data, test_size=.25)
# We'll use the famous SVD algorithm.
algo = SVD()
# Train the algorithm on the trainset, and predict ratings for the testset
algo.fit(trainset)
predictions = algo.test(testset)
# Then compute RMSE
accuracy.rmse(predictions)
返回的结果是0.9411
在此说明:你可以通过下面一行代码来训练并测试一个算法。1
predictions = algo.fit(trainset).test(testset)
在一些例子中,你的训练集和测试集数据已经被另一些例子所定义,请参考此处来处理这些问题。
训练整个测试集数据和predict()方法
毫无疑问,我们可以简单地将算法运用到我们的整个数据集,而不是使用交叉验证。这种方法可以通过使用build_full_trainset()方法来实现,该方法可以建立一个trainset对象。
实例代码如下:
1 | from surprise import KNNBasic |
我们可以通过predict()方法来预测评分。我们假设您对用户196和302物品感兴趣(确保他们在训练集中),并且你知道正确的评分是4,通过下面的代码可以实现计算:
1 | uid = str(196) # raw user id (as in the ratings file). They are **strings**! |
计算结果:1
user: 196 item: 302 r_ui = 4.00 est = 4.06 {'actual_k': 40, 'was_impossible': False}
说明:
predict()使用原始ID(请阅读关于[原始ID和内部ID](http://surprise.readthedocs.io/en/stable/FAQ.html#raw-inner-note)的信息)。 由于我们使用的数据集已经从文件中读取,原始ID是字符串(即使它们代表数字)
使用用户的自定义数据集
尽管surprise有一系列的内建数据集,但是你还是能够使用用户自定义的数据集。可以通过文件导入(csv)或者一个pandas dataframe导入。此外,你需要为surprise定义一个reader对象来解析文件或者数据框。
- 为载入一个文件(如csv),你可以使用load_from_file()方法来实现。
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from surprise import BaselineOnly
from surprise import Dataset
from surprise import Reader
from surprise.model_selection import cross_validate
# path to dataset file
file_path = os.path.expanduser('~/.surprise_data/ml-100k/ml-100k/u.data')
# As we're loading a custom dataset, we need to define a reader. In the
# movielens-100k dataset, each line has the following format:
# 'user item rating timestamp', separated by '\t' characters.
reader = Reader(line_format='user item rating timestamp', sep='\t')
data = Dataset.load_from_file(file_path, reader=reader)
# We can now use this dataset as we please, e.g. calling cross_validate
cross_validate(BaselineOnly(), data, verbose=True)
其他更多关于阅读器和如何使用的信息,详情查看reader class 文档。
说明:
正如您在前一节中已经知道的那样,Movielens-100k数据集是内置的,因此加载数据集的更快的方法是执行data = Dataset.load_builtin('ml-100k')。 我们当然会在这里忽略这个。
为载入一个从pandas dataframe 的数据集,你需要使用load_from_df()方法。你同样需要一个reader对象吗,但只需指定rating_scale参数即可。dataframe必须要有三列数据,包括用户id,物品id,用户对物品的评分数据。因此每一列都需要给定评分。
这不是限制性的,因为您可以轻松地重新排列数据框的列。
实例代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import pandas as pd
from surprise import NormalPredictor
from surprise import Dataset
from surprise import Reader
from surprise.model_selection import cross_validate
# Creation of the dataframe. Column names are irrelevant.
ratings_dict = {'itemID': [1, 1, 1, 2, 2],
'userID': [9, 32, 2, 45, 'user_foo'],
'rating': [3, 2, 4, 3, 1]}
df = pd.DataFrame(ratings_dict)
# A reader is still needed but only the rating_scale param is requiered.
reader = Reader(rating_scale=(1, 5))
# The columns must correspond to user id, item id and ratings (in that order).
data = Dataset.load_from_df(df[['userID', 'itemID', 'rating']], reader)
# We can now use this dataset as we please, e.g. calling cross_validate
cross_validate(NormalPredictor(), data, cv=2)dataframe的初始情况可能如下:
itemID rating userID
0 1 3 9
1 1 2 32
2 1 4 2
3 2 3 45
4 2 1 user_foo
使用交叉验证迭代
对于交叉验证,我们可以使用cross_validate()方法,它能为我们做所有的困难的工作。但为了更好的控制,我们还可以实例化交叉验证迭代器,并使用迭代器的split()方法和算法的test()方法对每个分裂进行预测。下面地案例是我们使用经典地k次交叉验证地过程,分裂了三次。
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from surprise import SVD
from surprise import Dataset
from surprise import accuracy
from surprise.model_selection import KFold
# Load the movielens-100k dataset
data = Dataset.load_builtin('ml-100k')
# define a cross-validation iterator
kf = KFold(n_splits=3)
algo = SVD()
for trainset, testset in kf.split(data):
# train and test algorithm.
algo.fit(trainset)
predictions = algo.test(testset)
# Compute and print Root Mean Squared Error
accuracy.rmse(predictions, verbose=True)
可能的结果:
RMSE: 0.9374
RMSE: 0.9476
RMSE: 0.9478
其他的交叉验证迭代的方法也可以使用,如留一法和ShuffleSplit。在此处查看所有的迭代器。surprise的交叉验证的涉及工具是受scikit-learnAPI工具的启发。
一个特殊的交叉验证案例是当其他文件预先定义了folds。例如:movielens-100k数据集已经提供了5个训练和测试的文件。surprise通过surprise.model_selection.split.PredefinedKFold对象来解决这个问题。
实例代码:
1 | from surprise import SVD |
当然,如果你仅通过导入单一的文件来进行训练,用单一的文件来测试,谁也阻止不了你。然而,folds_files参数仍需要是一个list。
使用GridSearchCV调整算法参数
cross_validate()函数针对给定的一组参数报告交叉验证过程的准确性度量。
如果你想知道哪个参数组合可以产生最好的结果,那么GridSearchCV类就可以解决问题。 给定一个参数的字典,这个类彻底地尝试所有的参数组合,并报告任何准确性度量(在不同的分割平均)的最佳参数。 它受到scikit-learn的GridSearchCV的启发。
下面的按理是我们使用不同的值来设置SVD算法的n_epochs,lr_all和reg_all参数.
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from surprise import SVD
from surprise import Dataset
from surprise.model_selection import GridSearchCV
# Use movielens-100K
data = Dataset.load_builtin('ml-100k')
param_grid = {'n_epochs': [5, 10], 'lr_all': [0.002, 0.005],
'reg_all': [0.4, 0.6]}
gs = GridSearchCV(SVD, param_grid, measures=['rmse', 'mae'], cv=3)
gs.fit(data)
# best RMSE score
print(gs.best_score['rmse'])
# combination of parameters that gave the best RMSE score
print(gs.best_params['rmse'])
运行结果:1
20.961300130118
{'n_epochs': 10, 'lr_all': 0.005, 'reg_all': 0.4}
我们在这里评估3倍交叉验证过程的平均RMSE和MAE,但是可以使用任何交叉验证迭代器。
一旦调用了fit(),best_estimator属性为我们提供了一个具有最佳参数集的算法实例,我们可以使用它:1
2algo = gs.best_estimator['rmse']
algo.fit(data.build_full_trainset())
说明:如bsl_options和sim_options等字典型参数需要特殊处理,如:
1
2
3
4
5
param_grid = {'k': [10, 20],
'sim_options': {'name': ['msd', 'cosine'],
'min_support': [1, 5],
'user_based': [False]}
}
自然而然,两者可以组合使用,如KNNBaseline算法:1
2
3
4
5
6
7param_grid = {'bsl_options': {'method': ['als', 'sgd'],
'reg': [1, 2]},
'k': [2, 3],
'sim_options': {'name': ['msd', 'cosine'],
'min_support': [1, 5],
'user_based': [False]}
}
为了进一步分析,cv_results属性具有所有需要的信息,并且可以在pandas dataframe中导入:1
results_df = pd.DataFrame.from_dict(gs.cv_results)
在我们的案例中,cv_results属性可能是这样的(已经转成了浮点型数据):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20'split0_test_rmse': [1.0, 1.0, 0.97, 0.98, 0.98, 0.99, 0.96, 0.97]
'split1_test_rmse': [1.0, 1.0, 0.97, 0.98, 0.98, 0.99, 0.96, 0.97]
'split2_test_rmse': [1.0, 1.0, 0.97, 0.98, 0.98, 0.99, 0.96, 0.97]
'mean_test_rmse': [1.0, 1.0, 0.97, 0.98, 0.98, 0.99, 0.96, 0.97]
'std_test_rmse': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
'rank_test_rmse': [7 8 3 5 4 6 1 2]
'split0_test_mae': [0.81, 0.82, 0.78, 0.79, 0.79, 0.8, 0.77, 0.79]
'split1_test_mae': [0.8, 0.81, 0.78, 0.79, 0.78, 0.79, 0.77, 0.78]
'split2_test_mae': [0.81, 0.81, 0.78, 0.79, 0.78, 0.8, 0.77, 0.78]
'mean_test_mae': [0.81, 0.81, 0.78, 0.79, 0.79, 0.8, 0.77, 0.78]
'std_test_mae': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
'rank_test_mae': [7 8 2 5 4 6 1 3]
'mean_fit_time': [1.53, 1.52, 1.53, 1.53, 3.04, 3.05, 3.06, 3.02]
'std_fit_time': [0.03, 0.04, 0.0, 0.01, 0.04, 0.01, 0.06, 0.01]
'mean_test_time': [0.46, 0.45, 0.44, 0.44, 0.47, 0.49, 0.46, 0.34]
'std_test_time': [0.0, 0.01, 0.01, 0.0, 0.03, 0.06, 0.01, 0.08]
'params': [{'n_epochs': 5, 'lr_all': 0.002, 'reg_all': 0.4}, {'n_epochs': 5, 'lr_all': 0.002, 'reg_all': 0.6}, {'n_epochs': 5, 'lr_all': 0.005, 'reg_all': 0.4}, {'n_epochs': 5, 'lr_all': 0.005, 'reg_all': 0.6}, {'n_epochs': 10, 'lr_all': 0.002, 'reg_all': 0.4}, {'n_epochs': 10, 'lr_all': 0.002, 'reg_all': 0.6}, {'n_epochs': 10, 'lr_all': 0.005, 'reg_all': 0.4}, {'n_epochs': 10, 'lr_all': 0.005, 'reg_all': 0.6}]
'param_n_epochs': [5, 5, 5, 5, 10, 10, 10, 10]
'param_lr_all': [0.0, 0.0, 0.01, 0.01, 0.0, 0.0, 0.01, 0.01]
'param_reg_all': [0.4, 0.6, 0.4, 0.6, 0.4, 0.6, 0.4, 0.6]
正如你所看到的,每个列表具有相同大小的参数组合数量。 它对应于下表:1
2
3
4
5
6
7
8
9split0_test_rmse split1_test_rmse split2_test_rmse mean_test_rmse std_test_rmse rank_test_rmse split0_test_mae split1_test_mae split2_test_mae mean_test_mae std_test_mae rank_test_mae mean_fit_time std_fit_time mean_test_time std_test_time params param_n_epochs param_lr_all param_reg_all
0.99775 0.997744 0.996378 0.997291 0.000645508 7 0.807862 0.804626 0.805282 0.805923 0.00139657 7 1.53341 0.0305216 0.455831 0.000922113 {‘n_epochs’: 5, ‘lr_all’: 0.002, ‘reg_all’: 0.4} 5 0.002 0.4
1.00381 1.00304 1.00257 1.00314 0.000508358 8 0.816559 0.812905 0.813772 0.814412 0.00155866 8 1.5199 0.0367117 0.451068 0.00938646 {‘n_epochs’: 5, ‘lr_all’: 0.002, ‘reg_all’: 0.6} 5 0.002 0.6
0.973524 0.973595 0.972495 0.973205 0.000502609 3 0.783361 0.780242 0.78067 0.781424 0.00138049 2 1.53449 0.00496203 0.441558 0.00529696 {‘n_epochs’: 5, ‘lr_all’: 0.005, ‘reg_all’: 0.4} 5 0.005 0.4
0.98229 0.982059 0.981486 0.981945 0.000338056 5 0.794481 0.790781 0.79186 0.792374 0.00155377 5 1.52739 0.00859185 0.44463 0.000888907 {‘n_epochs’: 5, ‘lr_all’: 0.005, ‘reg_all’: 0.6} 5 0.005 0.6
0.978034 0.978407 0.976919 0.977787 0.000632049 4 0.787643 0.784723 0.784957 0.785774 0.00132486 4 3.03572 0.0431101 0.466606 0.0254965 {‘n_epochs’: 10, ‘lr_all’: 0.002, ‘reg_all’: 0.4} 10 0.002 0.4
0.986263 0.985817 0.985004 0.985695 0.000520899 6 0.798218 0.794457 0.795373 0.796016 0.00160135 6 3.0544 0.00636185 0.488357 0.0576194 {‘n_epochs’: 10, ‘lr_all’: 0.002, ‘reg_all’: 0.6} 10 0.002 0.6
0.963751 0.963463 0.962676 0.963297 0.000454661 1 0.774036 0.770548 0.771588 0.772057 0.00146201 1 3.0636 0.0597982 0.456484 0.00510321 {‘n_epochs’: 10, ‘lr_all’: 0.005, ‘reg_all’: 0.4} 10 0.005 0.4
0.973605 0.972868 0.972765 0.973079 0.000374222 2 0.78607 0.781918 0.783537 0.783842 0.00170855 3 3.01907 0.011834 0.338839 0.075346 {‘n_epochs’: 10, ‘lr_all’: 0.005, ‘reg_all’: 0.6} 10 0.005 0.6
命令行的使用
surprise 同样支持命令行工具,例如:1
surprise -algo SVD -params "{'n_epochs': 5, 'verbose': True}" -load-builtin ml-100k -n-folds 3
查看使用细节运行:1
surprise -h