我在寻找一个具有Python接口的NMF实现,并且能够处理缺失数据和零值。
我不想在开始分解之前对缺失值进行填补,我希望它们在最小化函数中被忽略。
似乎scikit-learn、nimfa、graphlab和mahout都没有提供这样的选项。
谢谢!
回答:
使用这个Matlab到Python代码转换表,我能够重写来自Matlab工具箱库的NMF。
我需要分解一个40k X 1k
的矩阵,稀疏度为0.7%。使用500个潜在特征,我的机器在100次迭代中花了20分钟。
这是方法:
import numpy as npfrom scipy import linalgfrom numpy import dotdef nmf(X, latent_features, max_iter=100, error_limit=1e-6, fit_error_limit=1e-6): """ Decompose X to A*Y """ eps = 1e-5 print 'Starting NMF decomposition with {} latent features and {} iterations.'.format(latent_features, max_iter) X = X.toarray() # I am passing in a scipy sparse matrix # mask mask = np.sign(X) # initial matrices. A is random [0,1] and Y is A\X. rows, columns = X.shape A = np.random.rand(rows, latent_features) A = np.maximum(A, eps) Y = linalg.lstsq(A, X)[0] Y = np.maximum(Y, eps) masked_X = mask * X X_est_prev = dot(A, Y) for i in range(1, max_iter + 1): # ===== updates ===== # Matlab: A=A.*(((W.*X)*Y')./((W.*(A*Y))*Y')); top = dot(masked_X, Y.T) bottom = (dot((mask * dot(A, Y)), Y.T)) + eps A *= top / bottom A = np.maximum(A, eps) # print 'A', np.round(A, 2) # Matlab: Y=Y.*((A'*(W.*X))./(A'*(W.*(A*Y)))); top = dot(A.T, masked_X) bottom = dot(A.T, mask * dot(A, Y)) + eps Y *= top / bottom Y = np.maximum(Y, eps) # print 'Y', np.round(Y, 2) # ==== evaluation ==== if i % 5 == 0 or i == 1 or i == max_iter: print 'Iteration {}:'.format(i), X_est = dot(A, Y) err = mask * (X_est_prev - X_est) fit_residual = np.sqrt(np.sum(err ** 2)) X_est_prev = X_est curRes = linalg.norm(mask * (X - X_est), ord='fro') print 'fit residual', np.round(fit_residual, 4), print 'total residual', np.round(curRes, 4) if curRes < error_limit or fit_residual < fit_error_limit: breakreturn A, Y
在这里,我使用了Scipy稀疏矩阵作为输入,缺失值通过toarray()
方法转换为0
。因此,使用numpy.sign()
函数创建了掩码。然而,如果你有nan
值,你可以通过使用numpy.isnan()
函数获得相同的结果。