6

我在训练数据上使用 scikit-learn NMF 模型拟合了一个模型。现在我使用执行新数据的逆变换

result_1 = model.inverse_transform(model.transform(new_data))

然后,我使用此处幻灯片 15 中的等式,手动从 NMF 模型中获取分量来计算我的数据的逆变换。

temp = np.dot(model.components_, model.components_.T)
transform = np.dot(np.dot(model.components_.T, np.linalg.pinv(temp)), 
model.components_)
result_2 = np.dot(new_data, transform)

我想了解为什么 2 个结果不匹配。在计算逆变换和重建数据时我做错了什么?

示例代码:

import numpy as np
from sklearn.decomposition import NMF

data = np.array([[0,0,1,1,1],[0,1,1,0,0],[0,1,0,0,0],[1,0,0,1,0]])
print(data)
//array([[0, 0, 1, 1, 1],
       [0, 1, 1, 0, 0],
       [0, 1, 0, 0, 0],
       [1, 0, 0, 1, 0]])


model = NMF(alpha=0.0, init='random', l1_ratio=0.0, max_iter=200, n_components=2, random_state=0, shuffle=False, solver='cd', tol=0.0001, verbose=0)
model.fit(data)
NMF(alpha=0.0, beta_loss='frobenius', init='random', l1_ratio=0.0,
  max_iter=200, n_components=2, random_state=0, shuffle=False, solver='cd',
  tol=0.0001, verbose=0)

new_data = np.array([[0,0,1,0,0], [1,0,0,0,0]])
print(new_data)
//array([[0, 0, 1, 0, 0],
       [1, 0, 0, 0, 0]])

result_1 = model.inverse_transform(model.transform(new_data))
print(result_1)
//array([[ 0.09232497,  0.38903892,  0.36668712,  0.23067627,  0.1383513 ],
       [ 0.0877082 ,  0.        ,  0.12131779,  0.21914115,  0.13143295]])

temp = np.dot(model.components_, model.components_.T)
transform = np.dot(np.dot(model.components_.T, np.linalg.pinv(temp)), model.components_)
result_2 = np.dot(new_data, transform)
print(result_2)
//array([[ 0.09232484,  0.389039  ,  0.36668699,  0.23067595,  0.13835111],
       [ 0.09193481, -0.05671439,  0.09232484,  0.22970145,  0.13776664]])

注意:虽然这不是描述我的问题的最佳数据,但代码本质上是相同的。result_1在实际情况下,result_2彼此之间的差异也更大。data也是new_data大数组。

4

1 回答 1

3

发生什么了

在 scikit-learn 中,NMF 不仅仅是简单的矩阵乘法:它优化了!

解码 ( inverse_transform) 是线性的:模型计算X_decoded = dot(W, H),其中W是编码矩阵,H=model.components_是模型参数的学习矩阵。

transform然而,编码 ( ) 是非线性的:它执行W = argmin(loss(X_original, H, W))(仅关于),其中损失是和W之间的均方误差,加上一些额外的惩罚(L1 和 L2 范数),并且约束必须是非负的。最小化是通过坐标下降来执行的,结果可能是非线性的。因此,您不能简单地通过矩阵相乘得到。X_originaldot(W, H)WWX_originalW

为什么这么奇怪

NMF 必须执行这种奇怪的计算,否则模型可能会产生负面结果。实际上,在您自己的示例中,您可以尝试通过矩阵乘法执行变换

 print(np.dot(new_data, np.dot(model.components_.T, np.linalg.pinv(temp))))

并得到W包含负数的结果:

[[ 0.17328927  0.39649966]
 [ 0.1725572  -0.05780202]]

然而,NMF 中的坐标下降通过稍微修改矩阵来避免这个问题:

 print(model.transform(new_data))

给出非负结果

[[0.17328951 0.39649958]
 [0.16462405 0.        ]]

您可以看到它不仅W从下方裁剪矩阵,而且还修改了正元素,以提高拟合度(并遵守正则化惩罚)。

于 2018-03-20T11:46:18.870 回答