非负矩阵分解(Non-negative Matrix Factorization)
NMF简介
NMF用于文本降维
NMF的可解释性
NMF用于归纳单篇文章主题
NMF用于推荐多篇相似文章
NMF简介
NMF也是一种降维方法,相比PCA具有以下特点:
1,可解释性
2,可以用于所有数据集类型(PCA不能用于csr_matrix类型)
3,要求样本特征必须非负,像是表示每日股票价格升降的数组就不可以
NMF用于文本降维现在我们将NMF用在类型为csr_matrix的wiki_features上,先print一下看看它的内容:
output: wiki_features.shape is (60, 13125) wiki_features is (0, 16) 0.024688249778400003 (0, 32) 0.0239370711117 (0, 33) 0.0210896267411 : : (59, 13107) 0.025819936285200004 (59, 13108) 0.0340972474957 (59, 13113) 0.0170000449408 wiki_features.toarray() is [[0. 0. 0. ... 0. 0. 0. ] [0. 0. 0.02960744 ... 0. 0. 0. ] [0. 0. 0. ... 0.01159441 0. 0. ] ... [0. 0. 0. ... 0. 0. 0. ] [0. 0.00610985 0. ... 0. 0.00547551 0. ] [0. 0. 0. ... 0. 0. 0. ]]
其中通过.shape可以看出原始数据有60篇文章,13125种字。.toarray()中第 i 个横向量表示第 i 篇文章中这13125种字的 "tf-idf" 值。其中,"tf" 表示每种字在第 i 篇文章中出现的频率,可以通过这种字出现的次数除以第 i 篇文章总字数计算;"idf" 是一种加权方法,可以减少频词的作用,比如冠词 "the" 。
现在我们来使用NMF给wiki_features降下维叭
# 导入相应的库 from sklearn.decomposition import NMF # 创建一个model,注意NMF必须规定降到的维数 n_components ,但是PCA不必要 model = NMF(n_components = 6) # 训练模型 model.fit(wiki_features) # 降维 nmf_features = model.transform(wiki_features) # 输出维度与内容 print(nmf_features.shape) print(nmf_features.round(2))
最后输出结果如下,我们可以看到13125变成了6,内容的输出咱们保留了两位小数。
NMF的可解释性output: (60, 6) [[0. 0. 0. 0. 0. 0.44] [0. 0. 0. 0. 0. 0.57] [0. 0. 0. 0. 0. 0.4 ] : : : : : : [0.45 0. 0. 0. 0.01 0. ] [0.29 0.01 0.01 0.01 0.19 0.01] [0.38 0.01 0. 0.1 0.01 0. ]]
那么这个结果是怎么得到的呢?其实是wiki_features (60, 13125) 与 model.components_转置 (13125, 6)的乘积,我们可以来验证一下~
output: model.components_.shape is (6, 13125) (np.mat(wiki_features)*(np.mat(model.components_).I)).round(2) is [[-0.01 -0.01 -0. -0.02 -0. 0.44] [-0. -0. -0. -0. -0.01 0.57] [ 0. 0. -0.01 -0.01 -0. 0.4 ] : : : : : : [ 0.45 -0. -0. -0.02 0.01 -0.01] [ 0.29 0.01 0.01 0.01 0.19 0.01] [ 0.38 0.01 -0. 0.1 0.01 -0. ]]
所以我们说NMF具有可解释性,每篇文章降维后的nmf.features是通过清晰的公式计算得到的。
咱们还可以用Dataframe格式看每篇文章降维后的特征向量,
# 导入pandas库 import pandas as pd # 创建Dataframes,用标题进行索引 df = pd.Dataframe(nmf_features,index = titles) # 输出'Anne Hathaway'文章的components print(df.loc['Anne Hathaway'])
输出的结果如下:
NMF用于归纳单篇文章主题output: 0 0.003845 1 0.000000 2 0.000000 3 0.575711 4 0.000000 5 0.000000 Name: Anne Hathaway, dtype: float64
除了降维以外,我们还可以用NMF做很多工作,比如利用 model.components_ 归纳文章主题。比如《Anne Hathaway》在 nmf.features 保存的数据中第 3 行( 0.575711 )远大于其他几行,所以我们可以查看一下 model.components_ 的第 3 个component是什么,从而推出这篇文章的主题。
# 先创建一个方便索引model.components的表格 # 导入 pandas 库 import pandas as pd # 创建表格,model.components是(6, 13125) 的数组,很容易知道它的每一列都表示一种字 components_df = pd.Dataframe(model.components_,columns=words) # 输出看看 print(components_df)
output: aaron abandon abandoned ... zone zones zoo 0 0.011375 0.001210 0.000000 ... 0.000000 0.000424 0.0 1 0.000000 0.000010 0.005663 ... 0.002813 0.000297 0.0 2 0.000000 0.000008 0.000000 ... 0.000000 0.000143 0.0 3 0.004148 0.000000 0.003056 ... 0.001742 0.006720 0.0 4 0.000000 0.000568 0.004918 ... 0.000192 0.001351 0.0 5 0.000139 0.000000 0.008748 ... 0.002401 0.001682 0.0 [6 rows x 13125 columns]
索引到第 3 个componets,但是我们知道一行components有13125种字,不可能全是主题,所以我们使用 .nlargest() 前五个最大值对应的字。
# 选择第三行(注意是从0开始编号) component = components_df.iloc[3] # 输出最大的五个值对应的文字 print(component.nlargest())
最后输出的结果:
NMF用于推荐多篇相似文章output: film 0.627877 award 0.253131 starred 0.245284 role 0.211451 actress 0.186398 Name: 3, dtype: float64
其实可以再进一步,使用 nmf_features 找出与这篇文章主题类似的其他文章,类似浏览器中的推荐功能。
直接比较 nmf_features 是不合理的,因为同一主题的文章对应的的 nmf_features 不一定相似。因为有些文章的主题表达的比较直接,有些比较隐晦(废话多),后者的主题词频可能被稀释。所以我们选择余弦相似度来比较,因为将这些同一主题的文章对应的 nmf_features 画成散点图,虽然绝对值不同,但是都近似在一条过原点的直线上,这样通过比较直线就可以比较文章主题。
下面我们来看具体的代码叭。
# 导入Pandas库 # 为了计算方便,用点积代表余弦值,可以将每一行数组化成单位向量再输入,这里调用了normalize import pandas as pd from sklearn.preprocessing import normalize # 矢量归一化 norm_features = normalize(nmf_features) # 创建一个表格 df = pd.Dataframe(norm_features, index = titles) # 选定一篇文章 target_article = df.loc['Anne Hathaway'] # 计算这篇文章与其他文章的余弦相似度,即归一化后的点积 similarities = df.dot(target_article) # 选择相似度最大的前五篇文章 print(similarities.nlargest())
最后输出结果:
output: Anne Hathaway 1.000000 Michael Fassbender 0.999978 Catherine Zeta-Jones 0.999978 Jessica Biel 0.999978 Mila Kunis 0.999900 dtype: float64
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)