降维、特征提取与流形学习--非负矩阵分解(NMF)
非负矩阵分解(NMF)是一种无监督学习算法,目的在于提取有用的特征(可以识别出组合成数据的原始分量),也可以用于降维,通常不用于对数据进行重建或者编码。
- NMF将每个数据点写成一些分量的加权求和(与PCA相同),并且分量和系数都大于0,
- 只能适用于每个特征都是非负的数据(正负号实际上是任意的)。
1、将NMF应用于模拟数据
应用NMF时,我们必须保证数据是正的
📣如图
-
两个分量的NMF:分量指向边界,所有的数据点都可以写成这两个分量的正数组合。
-
一个分量的NMF:分量指向平均值,指向这里可以对数据做出最好的解释。
在NMF中,不存在“第一非负分量”,所有分量地位平等,减少分量个数会删除一些方向。NMF使用了随机初始化,根据随机种子的不同可能会产生不同的结果。
2、将NMF应用于人脸图像
NMF的主要参数(n_components参数):想要提取的分量个数。这个数字通常要小于输入特征的个数(否则将每个像素作为单独的分量就可以解释数据)。
(1)先观察一下运用NMF找到的15个分量长什么样
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
import numpy as np
from matplotlib import pyplot as plt
people = fetch_lfw_people(min_faces_per_person=40,resize=0.7)
image_shape = people.images[0].shape
#每个人最多有50张照片,防止数据偏斜
mask = np.zeros(people.target.shape,dtype=bool)
for target in np.unique(people.target):
mask[np.where(people.target==target)[0][:50]]=1
X_people = people.data[mask]
y_people = people.target[mask]
X_train, X_test, y_train, y_test = train_test_split(X_people,y_people,stratify=y_people,random_state=42)
#画出nmf模型训练得到的各个分量(这里指定15个),每个分量都是一张有点人形的图片(因为每个分量保留了所有的原始特征)。
#所有的数据点都可以写成这些分量的加权求和
from sklearn.decomposition import NMF
nmf = NMF(n_components=15,random_state=0)
nmf.fit(X_train)
X_train_nmf = nmf.transform(X_train)
X_test_nmf = nmf.transform(X_test)
fix,axes = plt.subplots(3,5,figsize=(15,12),subplot_kw={'xticks':(),'yticks':()})
for i ,(component,ax) in enumerate(zip(nmf.components_,axes.ravel())):
ax.imshow(component.reshape(image_shape))
ax.set_title("{}.component".format(i))
(2)、按照某个分量,重建数据点
#将数据样本点按照第10个分量排序,绘制数据点中前10张图片
compn = 10
inds = np.argsort(X_train_nmf[:,compn])[::-1] #按照第三个分量排序
fig,axes = plt.subplots(2,5,figsize=(15,8),subplot_kw={'xticks':(),'yticks':()})
for i ,(ind,ax) in enumerate(zip(inds,axes.ravel())):
ax.imshow(X_train[ind].reshape(image_shape))
- 可以看出在所有数据点中,分量10排名前10的数据点长什么样(它们的具有分量10提取的特点,脸有点歪)
- 每个分量提取了数据的不同模式,将这些分量叠加(加权求和)就能重构出训练集中的每一张图像。
3、应用于具有叠加结构的数据(信号源数据)
(1)先了解一下数据集
S = mglearn.datasets.make_signals()
plt.figure(figsize=(10,2))
plt.plot(S,'-')
plt.xlabel("Time")
plt.ylabel("Signal")
print(S.shape)
print(S)
#输出
(2000, 3)
[[2.65408203 2.48908887 1.07757433]
[2.94981947 3.45507031 0.79929765]
[2.97649958 3.65235694 0.73473133]
...
[2.22337048 1.33481395 4.31421863]
[2.36722058 1.56522921 4.53698235]
[1.77945297 1.62362822 0.47660599]]
- 可以看出该数据具有2000条,每条有对应三个信号源的数据
(2)将混合信号分解为原始分量
-
我们假设有100台测量装置来观测混合信号,得到了2000条具有100维特征的信号数据X
#将数据混合成100维的状态 A = np.random.RandomState(0).uniform(size=(100,3)) X = np.dot(S,A.T) print(X) print(X.shape)
-
应用NMF还原这个混合信号
#用nmf还原这三个信号被混合成100维的信号X nmf = NMF(n_components=3,random_state=42) S_nmf =nmf.fit_transform(X) #用于对比的pca pca = PCA(n_components=3,random_state=42) S_pca = pca.fit_transform(X) #S_pca就是H #画图 models = [X,S,S_nmf,S_pca] names = ["Obsevations(first measurements)", "Ture sourses", "NMF recovered signals", "PCA recovered signals"] fig, axes = plt.subplots(4,figsize=(10,5),gridspec_kw={'hspace':.5},subplot_kw={'xticks':(),'yticks':()}) for model,name,ax in zip(models,names,axes): ax.set_title(name) ax.plot(model,'-')
📣
- NMF在发现原始信号源时得到了不错的结果,而PCA失败了(PCA不适合这种叠加数据结构)
- NMF生成的分量是没有顺序的,如果分量顺序和原始信号完全相同(线的颜色)只是偶然。
4、参考文献
《Pyhon机器学习基础教程》P120-P126