数据降维在机器学习中非常有用,可以用来舍弃数据中一些区分度较小的特征,转化数据的观察视角,使其在更少量的特征维度上也有较好的表现。数据降维也可以用在将高维数据可视化的操作中,这都是不可或缺的重要算法,
PCA(Principal Components Analysis)主成分分析法,是一种常用的数据降维算法。
PCA的主要思路,是选取数据特征中一些较低维度的空间,让数据在这些空间上的方差比较大,这个时候我们可以认为数据是比较分散的,我们在这个低维度空间依然还能表现出数据的离散性。
在正式介绍PCA的步骤之前,有一些重要的数学知识能够极大的帮助我们计算。如果你读完了本节还是不清楚,下面两篇文章或许可以帮到你。
假设矩阵的每一行表示一组数据,每一列表示一维特征,即$$A_{n \times m}$$。
协方差矩阵可以表示为:
其中$$n$$是数据组数。
反之,若用行表示每组特征,则
Cov = \frac{1}{n} A A^T
显然,协方差矩阵$$Cov$$是实对称矩阵。
对于矩阵$$A$$,如果存在$$\lambda$$和向量$$v$$满足
A v = \lambda v
那么称$$\lambda$$为$$A$$的特征值,$$v$$为$$A$$的特征向量。
求解(2)式就可以算出所有的特征值与特征向量。
将矩阵按照特征值可以分解为
其中$$Q$$是特征向量按列排列成的矩阵,$$\Sigma$$是特征值构成的对角阵。
证明
由于不同的特征值对应的两个特征向量(任意两个不同的特征向量)是正交的,所以对特征向量做归一化后我们得到
Q Q^T = I = Q^T = Q^{-1}
所以也可以像下面这样分解
将上面(3)式变形
从矩阵的层面上讲,左乘一个矩阵相当于作初等行变换,右乘矩阵相当于初等列变换。如果把矩阵乘法理解为对矩阵的行和列作一些操作,下面理解PCA对数据特征的操作或许会更方便一些。
下面所讲的都是按照行为一组数据,每一列是一个特征。
下面详细的阐述主成分分析算法的每一个步骤,涉及到许多线性代数的知识,需要对上面的内容有一定了解。
首先拿到数据之后统计平均值$$\mu$$,然后每一列特征都减去均值,使得数据以$$0$$为中心。
利用式(1),计算协方差矩阵,我们这时候得到的协方差矩阵是一个实对称矩阵,对角线上分布的是$$m$$个特征的方差,其他位置是协方差。我们希望得到的是尽量少的、正交的、能表现全面的特征平面。那么这个矩阵应该长下面这个样子。
这意味着,这些特征的协方差都是零,即他们两两正交;每个特征自己有一个方差,我们选择前$$k$$大的方差,就得到了我们要形成怎样的特征,从而完成降维。下面我们向上面这个矩阵前进,也就是矩阵对角化。
在数学上,矩阵对角化已经不是什么难事了。
想象一下PCA最后剩下的那些特征,可以理解为现有的那些特征做了一些线性变换得到的,在这些维度中方差表现得更大,对特征做线性变换对应于基础操作中的列变换,于是我们可以为数据矩阵$$A$$右乘一个矩阵$$P$$之后得到我们要的正交的特征。
变换之后协方差可以写成
现在有没有觉得(5)和(6)有些神似了呢?
数学家告诉我们,特征向量矩阵有很好的性质,刚好可以满足我们对$$P$$的要求,所以我们计算出$$A^T A$$的特征向量和特征值就可以实现对角化了。
我们选择特征值的时候要选取前$$k$$大,因为方差越大,我们能保留下来的信息越多,选取的越是主要成分。
对这几个特征值排序然后选出前$$k$$大,这个时候由对应的矩阵$$P$$我们就可以知道选择的那些维度是怎么线性变换来的了。
我用fastNLP
中的预训练glove embedding
构建除了几个单词的词嵌入向量,是50维的,为了比较我们的 embedding 是否成功,nlp中经常用可视化来估计一下。
我在下面的代码中使用sklearn.decomposition.PCA
分别尝试了将50维降到2维和3维。一起来看一下效果吧。
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
from fastNLP.embeddings import StaticEmbedding
from fastNLP import Vocabulary
import torch
word_list = [‘he‘, ‘she‘, ‘right‘, ‘black‘, ‘work‘, ‘evening‘, ‘his‘, ‘do‘, ‘left‘, ‘white‘, ‘green‘, ‘job‘, ‘it‘, ‘her‘, ‘morning‘, ‘afternoon‘]
vocab = Vocabulary()
vocab.add_word_lst(
# msg.split(‘ ‘)
word_list
)
embeded = StaticEmbedding(vocab=vocab, model_dir_or_name="en-glove-6b-50d")
words_idx = torch.LongTensor(list(vocab.idx2word.keys()))
word_embedding = embeded(words_idx)
word_embedding = word_embedding.detach().numpy()
pca = PCA(n_components=3)
pca.fit(word_embedding)
data = pca.transform(word_embedding)
plt.scatter(data[:, 0], data[:, 1], alpha=0.6)
for i in range(len(data)):
plt.text(x=data[i][0], y=data[i][1], s=vocab.to_word(words_idx[i].item()))
# plt.text()
plt.show()
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
from fastNLP.embeddings import StaticEmbedding
from fastNLP import Vocabulary
import torch
word_list = [‘he‘, ‘she‘, ‘right‘, ‘black‘, ‘work‘, ‘evening‘, ‘his‘, ‘do‘, ‘left‘, ‘white‘, ‘green‘, ‘job‘, ‘it‘, ‘her‘, ‘morning‘, ‘afternoon‘]
vocab = Vocabulary()
vocab.add_word_lst(
# msg.split(‘ ‘)
word_list
)
embeded = StaticEmbedding(vocab=vocab, model_dir_or_name="en-glove-6b-50d")
words_idx = torch.LongTensor(list(vocab.idx2word.keys()))
word_embedding = embeded(words_idx)
word_embedding = word_embedding.detach().numpy()
pca = PCA(n_components=3)
pca.fit(word_embedding)
data = pca.transform(word_embedding)
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(data[:, 0], data[:, 1], data[:, 2], alpha=0.6)
for i, datai in enumerate(data):
ax.text3D(x=datai[0], y=datai[1], z=datai[2] , s=vocab.to_word(words_idx[i].item()), fontsize=5, horizontalalignment="center")
plt.show()
可以看到,相似的词汇确实还能在降维后的图中表现出关联。
原文:https://www.cnblogs.com/TABball/p/12727342.html