使用sklearn NMF组件重建新数据与inverse_transform不匹配
Reconstructing new data using sklearn NMF components Vs inverse_transform does not match
我在我的训练数据上使用 scikit-learn NMF 模型拟合了一个模型。现在我使用
对新数据执行逆变换
result_1 = model.inverse_transform(model.transform(new_data))
然后我使用幻灯片 15 中的方程 here.
手动计算我的数据的逆变换,从 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
也是大数组。
会发生什么
在 scikit-learn 中,NMF 做的不仅仅是简单的矩阵乘法:它优化了!
解码(inverse_transform
)是线性的:模型计算X_decoded = dot(W, H)
,其中W
是编码矩阵,H=model.components_
是模型参数的学习矩阵。
然而,编码(transform
)是非线性:它执行W = argmin(loss(X_original, H, W))
(仅相对于W
),其中损失是 X_original
和 dot(W, H)
之间的均方误差,加上一些额外的惩罚(W
的 L1 和 L2 范数),并且 W
必须是 non-negative.最小化是通过坐标下降进行的,结果在X_original
中可能是非线性的。因此,您不能简单地通过矩阵相乘得到 W
。
为什么这么奇怪
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))
给出 non-negative 结果
[[0.17328951 0.39649958]
[0.16462405 0. ]]
你可以看到它不只是从下面剪裁 W
矩阵,而且还修改了正元素,以提高拟合度(并遵守正则化惩罚)。
我在我的训练数据上使用 scikit-learn NMF 模型拟合了一个模型。现在我使用
对新数据执行逆变换result_1 = model.inverse_transform(model.transform(new_data))
然后我使用幻灯片 15 中的方程 here.
手动计算我的数据的逆变换,从 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
也是大数组。
会发生什么
在 scikit-learn 中,NMF 做的不仅仅是简单的矩阵乘法:它优化了!
解码(inverse_transform
)是线性的:模型计算X_decoded = dot(W, H)
,其中W
是编码矩阵,H=model.components_
是模型参数的学习矩阵。
编码(transform
)是非线性:它执行W = argmin(loss(X_original, H, W))
(仅相对于W
),其中损失是 X_original
和 dot(W, H)
之间的均方误差,加上一些额外的惩罚(W
的 L1 和 L2 范数),并且 W
必须是 non-negative.最小化是通过坐标下降进行的,结果在X_original
中可能是非线性的。因此,您不能简单地通过矩阵相乘得到 W
。
为什么这么奇怪
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))
给出 non-negative 结果
[[0.17328951 0.39649958]
[0.16462405 0. ]]
你可以看到它不只是从下面剪裁 W
矩阵,而且还修改了正元素,以提高拟合度(并遵守正则化惩罚)。