通过叠加PCA和t-SNE对机器学习的降维
我们必须在任何机器学习任务中几乎总是执行的一个常见步骤是:维度降低以及用于实现以下目的的两种常用技术:
主成分分析(PCA)
t分布随机相邻嵌入(t-SNE)
两者都有它们的小众用途,但在这篇文章中,我们将看到我们如何将它们结合起来,以实现更好的输出以满足我们的需求。
获取并设置数据
我们将使用数据库(http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html)来完成这项任务:
!wget http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip -O att_faces.zip
!unzip att_faces.zip
数据集有10个图像,每个图像有40个不同的个体,上面给出了400个图像中的每个图像的图像路径。
收集所有图像路径:
import glob
imagepaths = glob.glob('**/*.pgm', recursive=True)
print(len(imagepaths))
创建我们需要的数据集:
import numpy as np
import pandas as pd
from scipy.misc import imread
faces = pd.DataFrame([])
individual_id = 0
for i, path in enumerate(imagepaths):
print("===== loading image", i+1)
img = imread(path)
img = img.astype(np.uint8)
img = img / 255
img = img.flatten()
data_entry = pd.DataFrame([img])
data_entry['individual_id'] = individual_id
if ((i+1)%10 == 0):
individual_id+=1
faces = faces.append(data_entry)
图像是112x92,上面的代码使图像变平整以将每个像素作为一个特征 - 为每个图像提供一组10304个特征 - 这意味着我们的数据集现在具有10304个维度。
拔出individual_id以识别个人:
individuals = faces['individual_id']
faces = faces.drop(['individual_id'], axis=1)
individuals.unique()
让我们绘制上面的数据并快速查看这些图像的外观:
import matplotlib.pyplot as plt
from scipy.misc import imread
def plot_faces(data):
fig, axes = plt.subplots(40, 10, figsize=(9, 41),
subplot_kw={'xticks':[], 'yticks':[]},
gridspec_kw=dict(hspace=0.01,
wspace=0.01))
for i, ax in enumerate(axes.flat):
ax.imshow(data.iloc[i].values.reshape(112, 92), cmap="gray")
使用上面的功能,plot_faces(faces) :
为40个人中的每一个创建一种颜色:
import random
r = lambda: random.randint(0,255)
random_colors = []
for i in range(0, len(individuals.unique())):
random_colors.append('#%02X%02X%02X' % (r(),r(),r()))
colors = np.array(random_colors)[individuals]
PCA
定义一个带有run_pca2个参数的函数:data&dimensions,并返回结果数据:
from sklearn.decomposition import PCA
def pca(data, dimensions):
pca = PCA(n_components=dimensions)
pca.fit(data)
pca_results = pca.transform(data)
return pca_results
如果我们使用上面的faces数据集并通过dimensions=3,我们得到的是来自我们拥有的10304维数据集的三维数据集。
pca_results = run_pca(faces, 3)
我们来看一下3D图:
from mpl_toolkits.mplot3d import Axes3D
def plot_3d(data, colors):
x, y, z = data.T
fig = plt.figure(figsize=(10, 5.5/8*10))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, z, color=colors);
plot_3d(pca_results, colors)
上面的每一种颜色都对应着一个独特的个体,并且看上面的情节,很难看出它们之间的清晰分离。
T-SNE
考虑到它们是如何实现的,当您有非常多的维度时,PCA是推荐的技术,当维度的数量很小(例如- 50)时,就会发光。
现在,我们确实有大量的维度(10304),但这并没有限制我们只使用PCA——如何使用PCA将维数降低到50,然后用t-SNE来在三维空间中出最好的结果?
让我们试一试。
与run_pca()上面的函数类似,定义一个run_tsne():
from sklearn.manifold import TSNE
def run_tsne(data, components):
tsne = TSNE(n_components=components,
verbose=1,
perplexity=15,
learning_rate=75.0)
tsne_results = tsne.fit_transform(data)
return tsne_results
我们首先使用run_pca()降至50,然后run_tsne()进一步使用它将其降至3维数据集 - 我们最终绘制该数据集。
pca_results = run_pca(faces, 50)
results = run_tsne(pca_results, 3)
plot_3d(results, colors)