【机器学习】(十七)非负矩阵分解NMF:人脸图像特征提取、用特征排序;还原混合信号
非负矩阵分解(NMF)是一种无监督学习算法,目的在于提取有用的特征(可以识别出组合成数据的原始分量),也可以用于降维,通常不用于对数据进行重建或者编码。
与PCA相同,NMF将每个数据点写成一些分量的加权求和,并且分量和系数都大于0,只能适用于每个特征都是非负的数据(正负号实际上是任意的)。
两个分量的NMF:分量指向边界,所有的数据点都可以写成这两个分量的正数组合。
一个分量的NMF:分量指向平均值,指向这里可以对数据做出最好的解释。
在NMF中,不存在“第一非负分量”,所有分量地位平等,减少分量个数会删除一些方向。NMF使用了随机初始化,根据随机种子的不同可能会产生不同的结果。
将NMF应用于人脸图像特征提取(wild数据集)
from sklearn.decomposition import NMF
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
import matplotlib.pyplot as plt
import numpy as np
# 数据集处理
people = fetch_lfw_people(min_faces_per_person=20, resize=0.7)
image_shape = people.images[0].shape # 图片像素值
mask = np.zeros(people.target.shape, dtype=np.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_people= x_people / 255
x_train, x_test, y_train, y_test = train_test_split(x_people, y_people, random_state=0)
# 提取特征
nmf = NMF(n_components=15, random_state=0).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))
NMF的主要参数(n_components参数):想要提取的分量个数。这个数字通常要小于输入特征的个数(否则将每个像素作为单独的分量就可以解释数据)。
根据提取到的特征排序
# 用第三个分量排序,显示稍微向右转的人脸
compn = 3
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))
argsort()函数:将数组按照从小到大的顺序排序,并并返回排序后的下标。当axis=0时,按列排列;当axis=1时,按行排列;如果省略默认按行排列。
a[::-1] 方法:取从后向前(相反)的元素。
np.argsort函数
Python中numpy数组切片:print(a[0::2])、a[::2]、[:,2]、[1:,-1:]、a[::-1]、[ : n]、[m : ]、[-1]、[:-1]、[1:]等的含义(详细)
将MNF应用于还原混合信号
NMF提取模式,适合于具有叠加结构的数据,包括音频,基因表达和文本数据。
# 一个三种信号源合成的信号
s = mglearn.datasets.make_signals()
print(s.shape) # (2000, 3)
# 将数据混合成100维
a = np.random.RandomState(0).uniform(size=(100, 3))
x = np.dot(s, a.T)
print(x.shape) # (2000, 100)
# 用NMF还原三个信号
nmf = NMF(n_components=3, random_state=42)
s_ = nmf.fit_transform(x)
print(s_.shape) # (2000, 3)
# 绘图
models = [x, s, s_ ]
names = ['Mixed', 'Sources', 'NMF recover'] # 混合信号,原始信号,NMF还原信号
fig, axes = plt.subplots(3, figsize=(8, 6), gridspec_kw={'hspace': .5}, subplot_kw={'xticks':(), 'yticks':()})
for model, name, ax in zip(models, names, axes):
ax.set_title(name)
ax.plot(model[:, :3],'-')
numpy.random.RandomState()函数:获得随机数生成器。只要随机数种子seed相同,产生的随机数系列就相同。
dot()函数:返回两个数组的点积。A.T是矩阵的转置。
fit_transform()函数:fit和transform的组合,既包括了训练又包含了转换。
gridspec_kw参数:字典类型,可选参数。把字典的关键字传递给GridSpec构造函数创建子图。应该是调整子图位置的。
Matplotlib 中文用户指南 3.3 使用 GridSpec 自定义子图位置
numpy.random.RandomState() numpy里random总结
对NumPy中dot()函数的理解
fit_transform,fit,transform区别和作用
NMF生成的分量是没有顺序的,如果分量顺序和原始信号完全相同(线的颜色)只是偶然。