问题描述
我正在尝试使用 sklearn.decomposition.NMF
到矩阵 R
,其中包含有关用户如何评价项目的数据,以预测用户对他们尚未看到的项目的评分。
矩阵的行是用户,列是项目,值是分数,0 分表示用户还没有给这个项目打分。
现在使用下面的代码,我只能得到两个矩阵,当它们相乘时,返回原始矩阵。
import numpy
R = numpy.array([
[5,3,1],[4,[1,1,5],4],[0,5,])
from sklearn.decomposition import NMF
model = NMF(n_components=4)
A = model.fit_transform(R)
B = model.components_
n = numpy.dot(A,B)
print(n)
问题是,模型没有预测新值来代替 0
的值,这将是预测的分数,而是按原样重新创建矩阵。
如何让模型预测用户分数来代替原始矩阵的零?
解决方法
这就是应该发生的事情。
但是,在大多数情况下,您的组件数量不会与产品和/或客户的数量如此相似。
例如考虑 2 个组件
model = NMF(n_components=2)
A = model.fit_transform(R)
B = model.components_
R_estimated = np.dot(A,B)
print(np.sum(R-R_estimated))
-1.678873127048393
R_estimated
array([[5.2558264,1.99313836,0.,1.45512772],[3.50429478,1.32891458,0.9701988 ],[1.31294288,0.94415991,1.94956896,3.94609389],[0.98129195,0.72179987,1.52759811,3.0788454 ],[0.,0.65008935,2.84003662,5.21894555]])
在这种情况下,您可以看到许多以前的零现在是您可以使用的其他数字。这里有一些上下文https://en.wikipedia.org/wiki/Matrix_factorization_(recommender_systems)。
如何选择 n_components?
我认为上面的问题已经回答了,但如果完整的程序可能如下所示。
为此,我们需要知道 R 中的真实值,并且我们希望专注于预测。
在许多情况下,R 中的 0 是那些新案例/场景。 通常用产品或客户的平均值更新 R,然后计算分解以选择理想的 n_components。对于选择它们可能是一个或多个标准来计算测试样本中的优势
- 创建 R_with_Averages
- 型号选择: 2.1) 拆分 R_with_Averages 测试和训练 2.2)使用度量(其中您只考虑 R 中的真实评估)在不同的 n_components(从 1 和任意数字)之间进行比较 2.3) 选择最佳模型 --> 最佳 n_components
- 使用最佳模型进行预测。
也许很高兴看到:
- Sarwar,B. M.、Karypis,G.、Konstan,J. A. 和 Riedl,J. (2000)。降维在推荐系统中的应用——案例研究。在 ACM WebKDD’00(电子商务研讨会的网络挖掘)中。这为您提供了整体视图。
- http://www.quuxlabs.com/blog/2010/09/matrix-factorization-a-simple-tutorial-and-implementation-in-python/。示例代码非常相似。
sklearn
对NMF
的实现好像不支持缺失值(Nan
s,这里0个值基本代表新用户对应的未知评分),参考这个{{ 3}}。但是,我们可以使用 suprise
的 NMF
实现,如以下代码所示:
import numpy as np
import pandas as pd
from surprise import NMF,Dataset,Reader
R = np.array([
[5,3,1],[4,[1,1,5],4],[0,5,],dtype=np.float)
R[R==0] = np.nan
print(R)
# [[ 5. 3. nan 1.]
# [ 4. nan nan 1.]
# [ 1. 1. nan 5.]
# [ 1. nan nan 4.]
# [nan 1. 5. 4.]]
df = pd.DataFrame(data=R,index=range(R.shape[0]),columns=range(R.shape[1]))
df = pd.melt(df.reset_index(),id_vars='index',var_name='items',value_name='ratings').dropna(axis=0)
reader = Reader(rating_scale=(0,5))
data = Dataset.load_from_df(df[['index','items','ratings']],reader)
k = 2
algo = NMF(n_factors=k)
trainset = data.build_full_trainset()
algo.fit(trainset)
predictions = algo.test(trainset.build_testset()) # predict the known ratings
R_hat = np.zeros_like(R)
for uid,iid,true_r,est,_ in predictions:
R_hat[uid,iid] = est
predictions = algo.test(trainset.build_anti_testset()) # predict the unknown ratings
for uid,iid] = est
print(R_hat)
# [[4.40762528 2.62138084 3.48176319 0.91649316]
# [3.52973408 2.10913555 2.95701406 0.89922637]
# [0.94977826 0.81254138 4.98449755 4.34497549]
# [0.89442186 0.73041578 4.09958967 3.50951819]
# [1.33811051 0.99007556 4.37795636 3.53113236]]
NMF 实现是按照 [NMF:2014] 论文中描述的 issue 和如下所示:
注意,这里只使用已知评分进行优化,导致已知评分的预测值接近真实评分(但未知评分的预测值一般不接近{{1 }},正如预期的那样)。
同样,像往常一样,我们可以使用交叉验证找到因子数 0
。