本节为吴恩达教授机器学习课程笔记第十一部分,因子分析,针对样本数量少,特征维度高的数据建模,主要包括:样本数量远大于特征维度时使用高斯分布建模的问题,对协方差矩阵的两种限制条件,多元高斯联合分布的边缘分布和条件分布,因子分析模型的形式化定义和通俗理解,以及使用EM算法求解因子分析模型,最后附上使用因子分析解决实际问题的python代码实现。
如果我们有来自多个不同的高斯分布的数据混合而成的数据集,那么EM算法可以帮助我们很好的来拟合混合模型的参数。这种情况下我们通常假设有足够的数据来帮助模型识别出数据中多个高斯分布的结构,比如,样本数量远大于样本特征维度。
现在我们来考虑相反的情况即特征维度n远大于样本数量m( n > > m n >> m n>>m),这种问题中,即使假设数据为单个高斯分布,都很难对数据建模。而且因为 m m m个数据点分布再 R n R^n Rn得一个低维子空间上,如何我们使用高斯对数据建模,那么使用极大似然估计法得到得均值和协方差如下:
发现矩阵 Σ \Sigma Σ是一个奇异矩阵,也就是说, Σ − 1 \Sigma^{-1} Σ−1不存在且 1 / ∣ Σ ∣ 1 / 2 = 1 / 0 1/|\Sigma|^{1/2}=1/0 1/∣Σ∣1/2=1/0,但是这些项在计算多元高斯分布的密度中都是必须的。这个问题的另一种阐述方式:对参数的极大似然估计会产生一个高斯分布,其概率分布在由样本数据所成的仿射空间中对应着一个奇异的协方差矩阵。
仿射空间:没有原点的线性空间。在仿射空间中,点与点之间做差可以得到向量,点与向量做加法将得到另一个点,但是点与点之间不可以做加法。
想象你某天醒来发觉自己是在一个旅馆房间里,推门出去一看,外面是个无限长的走廊,走廊两边的房间都一模一样而且没有房间号,那么你就没法打电话让别人知道你的具体位置,因为你缺乏一个参照点。这就是一维仿射空间的例子(如果你把走廊看成线)。
但是这种情况我们仍然需要将数据拟合成一个合理的高斯模型,或者从数据中找到某种协方差结构,又该如何做呢?接下来的内容首先介绍对于协方差 Σ \Sigma Σ的两种限制,这两个限制可以使得我们能以较小的数据规模拟合 Σ \Sigma Σ,但是仍然不能得到满意的解;之后会介绍高斯分布一些性质;最后给出因子分析模型并对其应用EM算法。
如果我们没有足够的数据来得到一个完整的协方差矩阵,我们可能对我们要求的协方差矩阵设定一些限制条件,比如我们可以假定我们要拟合的协方差矩阵为对对角矩阵,这种情况下,极大似然估计给出的协方差矩阵,对角矩阵 Σ \Sigma Σ就可满足:
这样一来 Σ j j \Sigma_{jj} Σjj表示数据第 j j j个坐标的方差的经验估计。
参考高斯密度分布的等值线和轮廓,我们直到,协方差矩阵如果是对角阵 Σ \Sigma Σ,那么表明高斯分布的这些椭圆的主轴适合坐标轴平行的。
某些情况下,我们可以对协方差矩阵作进一步限制,即协方差矩阵不仅是对角矩阵,而且对角线上的元素都相等,也就是说 Σ = σ 2 I \Sigma=\sigma^2I Σ=σ2I,其中 σ 2 \sigma^2 σ2是我们设定的参数,可以通过如下的极大似然方法得到值:
这种限制条件下,高斯分布的等值线就是圆形(2维空间),更高维是球体。
如果我们不对数据的协方差矩阵 Σ \Sigma Σ作限制,那么必须满足 m ≥ n + 1 m \geq n+1 m≥n+1才能保证 Σ \Sigma Σ不为奇异矩阵;但是在上面两种限制中的任意一种,只需要满足 m ≥ 2 m \geq 2 m≥2就能保证协方差矩阵为非奇异矩阵。
然而这种假设也意味着对于数据不同的坐标 x i 、 x j x_i、x_j xi、xj的建模也变得不相关和独立,使用上面两种限制条件,可能对捕获数据内部的关系并没有有利条件。这时候就需要因子分析模型,它使用更多的参数以期捕获更多数据内部的结构,而且也不用拟合一个完整的协方差矩阵。
在学习因子分析之前,我们先讨论一下如何确定随机变量的联合多元高斯分布的条件分布和边缘分布。比如我们的随便变量使向量型的:
其中 x 1 ∈ R r , x 2 ∈ R s , x ∈ R r + s x_1\in R^r,x_2 \in R^s,x \in R^{r+s} x1∈Rr,x2∈Rs,x∈Rr+s,令 x ∼ N ( μ , Σ ) x \thicksim N(\mu,\Sigma) x∼N(μ,Σ),其中:
并且有 μ 1 ∈ R r , μ 2 ∈ R s , Σ 11 ∈ R r × r , Σ 12 ∈ R r + s \mu_1 \in R^r,\mu_2 \in R^s,\Sigma_{11} \in R^{r \times r},\Sigma_{12} \in R^{r+s} μ1∈Rr,μ2∈Rs,Σ11∈Rr×r,Σ12∈Rr+s,因为协方差矩阵是对称的,所以有 Σ 12 = Σ 21 T \Sigma_{12}=\Sigma_{21}^T Σ12=Σ21T。
在这种情况下, x 1 x_1 x1和 x 2 x_2 x2是联合多元高斯分布。且 E [ x 1 ] = μ 1 , C o v ( x 1 ) = E [ ( x 1 − μ 1 ) ( x 1 − μ 1 ) ] = Σ 11 E[x_1]=\mu_1,Cov(x_1)=E[(x_1-\mu_1)(x_1-\mu_1)]=\Sigma_{11} E[x1]=μ1,Cov(x1)=E[(x1−μ1)(x1−μ1)]=Σ11,并且有:
因为高斯分布的边缘分布也是高斯,所以有 x 1 ∼ N ( μ 1 , Σ 11 ) x_1 \thicksim N(\mu_1,\Sigma_{11}) x1∼N(μ1,Σ11)。
那么给定 x 2 x_2 x2时 x 1 x_1 x1的条件分布是多少呢?回归多元高斯分布的定义,我们有 x 1 ∣ x 2 ∼ N ( μ 1 ∣ 2 , Σ 1 ∣ 2 ) x_1|x_2 \thicksim N(\mu_{1|2},\Sigma_{1|2}) x1∣x2∼N(μ1∣2,Σ1∣2),其中:
假想 ( x , z ) (x,z) (x,z)的联合分布如下所示( z ∈ R k z \in R^k z∈Rk是一个潜在的随机变量):
其中,模型的参数是向量 μ ∈ R n \mu \in R^n μ∈Rn,矩阵 ∧ ∈ R n × k \wedge \in R^{n \times k} ∧∈Rn×k,对角阵 Ψ ∈ R n × n \Psi \in R^{n\times n} Ψ∈Rn×n,其中k的值一般要比n小。
这样我们假定数据点 x ( i ) x^{(i)} x(i)是由一个k维的多元高斯分布 z ( i ) z^{(i)} z(i)中取样生成的,那么 μ + ∧ z ( i ) \mu + \wedge z^{(i)} μ+∧z(i)就把 z ( i ) z^{(i)} z(i)映射到 R n R^n Rn,然后给 μ + ∧ z ( i ) \mu + \wedge z^{(i)} μ+∧z(i)加上随机噪音 Ψ \Psi Ψ得到最后的 x ( i ) x^{(i)} x(i)。
因此我们也可以按如下形式定义因子分析模型,其中 ϵ 和 z \epsilon和z ϵ和z互相独立:
随 机 变 量 z 和 x 的 联 合 高 斯 分 布 如 下 随机变量z和x的联合高斯分布如下 随机变量z和x的联合高斯分布如下:
因 为 E [ z ] = 0 , 根 据 z ∼ N ( 0 , 1 ) , 我 们 可 以 得 到 : 因为E[z]=0,根据z \thicksim N(0,1),我们可以得到: 因为E[z]=0,根据z∼N(0,1),我们可以得到:
下 来 确 定 Σ , 我 们 需 要 计 算 : 下来确定\Sigma,我们需要计算: 下来确定Σ,我们需要计算:
因 为 z ∼ N ( 0 , 1 ) , 则 有 Σ z z = C o v ( z ) = I 因为z \thicksim N(0,1),则有\Sigma_{zz}=Cov(z)=I 因为z∼N(0,1),则有Σzz=Cov(z)=I,有:
最 后 一 步 是 因 为 E [ z z T ] = C o v ( z ) 【 z 的 均 值 为 0 】 , 并 且 E [ z ϵ T ] = E [ z ] E [ ϵ T ] 【 z 和 ϵ 互 相 独 立 】 , 这 样 我 们 可 以 得 到 Σ x x 最后一步是因为E[zz^T]=Cov(z)【z的均值为0】,并且E[z\epsilon^T]=E[z]E[\epsilon^T]【z和\epsilon互相独立】,这样我们可以得到\Sigma_{xx} 最后一步是因为E[zzT]=Cov(z)【z的均值为0】,并且E[zϵT]=E[z]E[ϵT]【z和ϵ互相独立】,这样我们可以得到Σxx:
这 样 x 的 边 缘 分 布 即 为 : x ∼ N ( μ , ∧ ∧ T + Ψ ) , 这 样 给 定 一 个 训 练 集 { x ( i ) ; i = 1 , . . . , m } , 我 们 可 以 得 到 参 数 的 对 数 似 然 函 数 : 这样x的边缘分布即为:x\thicksim N(\mu,\wedge\wedge^T+\Psi),这样给定一个训练集\{x^{(i)};i=1,...,m\},我们可以得到参数的对数似然函数: 这样x的边缘分布即为:x∼N(μ,∧∧T+Ψ),这样给定一个训练集{x(i);i=1,...,m},我们可以得到参数的对数似然函数:
为了进行极大似然估计,那么我们需要对应个参数来最大化对数似然函数,但是最大化这个公式显然很麻烦,所以我们再次求助于EM算法。
因子分析更通俗的理解,就是用更少的为观测到的变量描述观测到的、相关的边练,即假设观测到的变量间存在某种相关关系,从观测变量的矩阵内部相关关系出发找到潜变量,从而使得潜变量和观测变量之间的关系成立。
换一种说法,即因子分析是从变量群中提取共性因子的统计技术,共性因子也就是上一段提到的变量之间的潜藏因子,比如一个学生各科成绩都很好,那潜在的共性因子就可能是智力高。所以因子分析的过程就是寻找共性因子和个性因子并得到最优解释的过程,分为四个基本步骤:
第一步:确定若干变量是否适合因子分析,即选取的几个观测变量是否具有较强的相关性。
第二步:构造因子变量。常用的方法是基于主成分模型的主成分分析法。
第三步:利用旋转使得因子变量具有可解释性
第四步:计算因子变量的得分
对于E步的推导非常简单,我们需要计算 Q i ( z ( i ) ) = p ( z ( i ) ∣ x ( i ) ; μ , ∧ , Ψ ) Q_i(z^{(i)})=p(z^{(i)}|x^{(i)};\mu,\wedge,\Psi) Qi(z(i))=p(z(i)∣x(i);μ,∧,Ψ),通过上面几节的推导,有 z ( i ) ∣ x ( i ) ; μ , ∧ , Ψ ∼ N ( μ z ( i ) ∣ x ( i ) , Σ z ( i ) ∣ x ( i ) ) z^{(i)}|x^{(i)};\mu,\wedge,\Psi \thicksim N(\mu_{z^{(i)}|x^{(i)}},\Sigma_{z^{(i)}|x^{(i)}}) z(i)∣x(i);μ,∧,Ψ∼N(μz(i)∣x(i),Σz(i)∣x(i)),其中:
根据 μ z ( i ) ∣ x ( i ) 和 Σ z ( i ) ∣ x ( i ) 的 定 义 , 我 们 有 : \mu_{z^{(i)}|x^{(i)}}和\Sigma_{z^{(i)}|x^{(i)}}的定义,我们有: μz(i)∣x(i)和Σz(i)∣x(i)的定义,我们有:
然 后 看 M 步 , 我 们 需 要 根 据 参 数 μ , ∧ , Ψ 来 最 大 化 : 然后看M步,我们需要根据参数\mu ,\wedge ,\Psi来最大化: 然后看M步,我们需要根据参数μ,∧,Ψ来最大化:
这 里 只 给 出 ∧ 的 推 导 , 我 们 先 将 上 式 化 简 得 到 : 这里只给出\wedge的推导,我们先将上式化简得到: 这里只给出∧的推导,我们先将上式化简得到:
把 式 子 中 与 待 优 化 参 数 无 关 的 项 去 掉 , 我 们 只 需 优 化 : 把式子中与待优化参数无关的项去掉,我们只需优化: 把式子中与待优化参数无关的项去掉,我们只需优化:
这 个 式 子 中 也 只 有 最 后 一 项 依 赖 ∧ , 求 导 然 后 利 用 : 这个式子中也只有最后一项依赖\wedge,求导然后利用: 这个式子中也只有最后一项依赖∧,求导然后利用:
为了完成M步的参数更新,根据分布Q_i的定义【均值 μ z ( i ) ∣ x ( i ) 、 协 方 差 Σ z ( i ) ∣ x ( i ) 的 高 斯 分 布 】 , 我 们 可 以 得 到 : \mu_{z^{(i)}|x^{(i)}}、协方差\Sigma_{z^{(i)}|x^{(i)}}的高斯分布】,我们可以得到: μz(i)∣x(i)、协方差Σz(i)∣x(i)的高斯分布】,我们可以得到:
并且令 Ψ i i = Φ i i \Psi_{ii}=\Phi_{ii} Ψii=Φii。
采用因子分析的方法根据27个面试者的十五项指标得分中选出最优秀的6名,原始数据如下:
进行相关稀疏矩阵检验-KMO测度和巴特利球形检验【KMO值,0.9以上非常好,0.5以下不能接受;巴特利球形检验越接近1效果越好,接近0,效果越差】:
通过观察,确定这个问题可以使用因子分析,然后求解特征值和特征向量,使用前m个特征值比重大于85%的标准选出公共因子五个。
计算因子载荷阵【表示第 i 个变量在第 j 个公共因子上的负荷】:
可以看出从方差贡献率可以看出,第一个公因子解释了总体方差的50.092%,五个公共因子贡献了86.42%,可以较好的解释总体方差。
因子旋转【由于因子载荷阵是不唯一的,所以应该对因子载荷阵进行旋转。目的是使因子载荷阵的结构简化,使载荷矩阵每列或行的元素平方值向0和1 两级分化。有三种主要的正交旋转法,四次方最大法、方差最大法和等量最大法。】:
排序选择即可,代码如下:
import pandas as pd
import numpy as np
import math as math
import numpy as np
from numpy import *
from scipy.stats import bartlett
from factor_analyzer import *
import numpy.linalg as nlg
from sklearn.cluster import KMeans
from matplotlib import cm
import matplotlib.pyplot as plt
def main():
df=pd.read_csv("./data/applicant.csv")
# print(df)
df2=df.copy()
print("\n原始数据:\n",df2)
del df2['ID']
# print(df2)
# 皮尔森相关系数
df2_corr=df2.corr()
print("\n相关系数:\n",df2_corr)
#热力图
cmap = cm.Blues
# cmap = cm.hot_r
fig=plt.figure()
ax=fig.add_subplot(111)
map = ax.imshow(df2_corr, interpolation='nearest', cmap=cmap, vmin=0, vmax=1)
plt.title('correlation coefficient--headmap')
ax.set_yticks(range(len(df2_corr.columns)))
ax.set_yticklabels(df2_corr.columns)
ax.set_xticks(range(len(df2_corr)))
ax.set_xticklabels(df2_corr.columns)
plt.colorbar(map)
plt.show()
# KMO测度
def kmo(dataset_corr):
corr_inv = np.linalg.inv(dataset_corr)
nrow_inv_corr, ncol_inv_corr = dataset_corr.shape
A = np.ones((nrow_inv_corr, ncol_inv_corr))
for i in range(0, nrow_inv_corr, 1):
for j in range(i, ncol_inv_corr, 1):
A[i, j] = -(corr_inv[i, j]) / (math.sqrt(corr_inv[i, i] * corr_inv[j, j]))
A[j, i] = A[i, j]
dataset_corr = np.asarray(dataset_corr)
kmo_num = np.sum(np.square(dataset_corr)) - np.sum(np.square(np.diagonal(A)))
kmo_denom = kmo_num + np.sum(np.square(A)) - np.sum(np.square(np.diagonal(A)))
kmo_value = kmo_num / kmo_denom
return kmo_value
print("\nKMO测度:", kmo(df2_corr))
# 巴特利特球形检验
df2_corr1 = df2_corr.values
print("\n巴特利特球形检验:", bartlett(df2_corr1[0], df2_corr1[1], df2_corr1[2], df2_corr1[3], df2_corr1[4],
df2_corr1[5], df2_corr1[6], df2_corr1[7], df2_corr1[8], df2_corr1[9],
df2_corr1[10], df2_corr1[11], df2_corr1[12], df2_corr1[13], df2_corr1[14]))
# 求特征值和特征向量
eig_value, eigvector = nlg.eig(df2_corr) # 求矩阵R的全部特征值,构成向量
eig = pd.DataFrame()
eig['names'] = df2_corr.columns
eig['eig_value'] = eig_value
eig.sort_values('eig_value', ascending=False, inplace=True)
print("\n特征值\n:",eig)
eig1=pd.DataFrame(eigvector)
eig1.columns = df2_corr.columns
eig1.index = df2_corr.columns
print("\n特征向量\n",eig1)
# 求公因子个数m,使用前m个特征值的比重大于85%的标准,选出了公共因子是五个
for m in range(1, 15):
if eig['eig_value'][:m].sum() / eig['eig_value'].sum() >= 0.85:
print("\n公因子个数:", m)
break
# 因子载荷阵
A = np.mat(np.zeros((15, 5)))
i = 0
j = 0
while i < 5:
j = 0
while j < 15:
A[j:, i] = sqrt(eig_value[i]) * eigvector[j, i]
j = j + 1
i = i + 1
a = pd.DataFrame(A)
a.columns = ['factor1', 'factor2', 'factor3', 'factor4', 'factor5']
a.index = df2_corr.columns
print("\n因子载荷阵\n", a)
fa = FactorAnalyzer(n_factors=5)
fa.loadings_ = a
# print(fa.loadings_)
print("\n特殊因子方差:\n", fa.get_communalities()) # 特殊因子方差,因子的方差贡献度 ,反映公共因子对变量的贡献
var = fa.get_factor_variance() # 给出贡献率
print("\n解释的总方差(即贡献率):\n", var)
# 因子旋转
rotator = Rotator()
b = pd.DataFrame(rotator.fit_transform(fa.loadings_))
b.columns = ['factor1', 'factor2', 'factor3', 'factor4', 'factor5']
b.index = df2_corr.columns
print("\n因子旋转:\n", b)
# 因子得分
X1 = np.mat(df2_corr)
X1 = nlg.inv(X1)
b = np.mat(b)
factor_score = np.dot(X1, b)
factor_score = pd.DataFrame(factor_score)
factor_score.columns = ['factor1', 'factor2', 'factor3', 'factor4', 'factor5']
factor_score.index = df2_corr.columns
print("\n因子得分:\n", factor_score)
fa_t_score = np.dot(np.mat(df2), np.mat(factor_score))
print("\n应试者的五个因子得分:\n",pd.DataFrame(fa_t_score))
# 综合得分
wei = [[0.50092], [0.137087], [0.097055], [0.079860], [0.049277]]
fa_t_score = np.dot(fa_t_score, wei) / 0.864198
fa_t_score = pd.DataFrame(fa_t_score)
fa_t_score.columns = ['综合得分']
fa_t_score.insert(0, 'ID', range(1, 49))
print("\n综合得分:\n", fa_t_score)
print("\n综合得分:\n", fa_t_score.sort_values(by='综合得分', ascending=False).head(6))
plt.figure()
ax1=plt.subplot(111)
X=fa_t_score['ID']
Y=fa_t_score['综合得分']
plt.bar(X,Y,color="#87CEFA")
# plt.bar(X, Y, color="red")
plt.title('result00')
ax1.set_xticks(range(len(fa_t_score)))
ax1.set_xticklabels(fa_t_score.index)
plt.show()
fa_t_score1=pd.DataFrame()
fa_t_score1=fa_t_score.sort_values(by='综合得分',ascending=False).head()
ax2 = plt.subplot(111)
X1 = fa_t_score1['ID']
Y1 = fa_t_score1['综合得分']
plt.bar(X1, Y1, color="#87CEFA")
# plt.bar(X1, Y1, color='red')
plt.title('result01')
plt.show()
if __name__ == '__main__':
main()
BB了这么多,引用大佬的一句话:
“因子分析和以高斯混合模型为代表的聚类分析以及PCA为代表的降维算法都有关系。FA就好似住在GMM和PCA之间的一位邻居。从GMM这边看,FA可以像GMM一样进行聚类,同时利用降维解决了GMM方法无法处理的n大于m导致的协方差矩阵奇异/不满秩情况。从PCA这边看,FA和PCA均可以有效降维,“因子”和“主成分”有相似性,但FA需要提前确定降维后的维度数k。最后用一句话概括,PCA是用原始特征线性组成主成分,而FA是以潜在的“因子”线性表示原始特征。”
欢迎扫描二维码关注微信公众号 深度学习与数学 [每天获取免费的大数据、AI等相关的学习资源、经典和最新的深度学习相关的论文研读,算法和其他互联网技能的学习,概率论、线性代数等高等数学知识的回顾]