数据挖掘:python实战多因子分析

1,130 阅读8分钟

公众号:尤而小屋
作者:Peter
编辑:Peter

大家好,我是Peter~

最近看了很多的关于因子分析的资料,整理出这篇理论+实战文章分享给大家。后续会出一篇PCA主成分分析的文章,将主成分分析和因子分析两种降维的方法进行对比。

因子分析

作为多元统计分析里的降维方法之一,因子分析可以应用于多个场景,如调研、数据建模等场景之中。

起源

因子分析的起源是这样的:1904年英国的一个心理学家发现学生的英语、法语和古典语成绩非常有相关性,他认为这三门课程背后有一个共同的因素驱动,最后将这个因素定义为“语言能力”。

基于这个想法,发现很多相关性很高的因素背后有共同的因子驱动,从而定义了**因子分析,这便是因子分析的由来。

基本思想

我们再通过一个更加实际的例子来理解因子分析的基本思想:

现在假设一个同学的数学、物理、化学、生物都考了满分,那么我们可以认为这个学生的理性思维比较强,在这里理性思维就是我们所说的一个因子。在这个因子的作用下,偏理科的成绩才会那么高。

到底什么是因子分析?就是假设现有全部自变量x的出现是因为某个潜在变量的作用,这个潜在的变量就是我们说的因子。在这个因子的作用下,x能够被观察到。

因子分析就是将存在某些相关性的变量提炼为较少的几个因子,用这几个因子去表示原本的变量,也可以根据因子对变量进行分类

因子分子本质上也是降维的过程,和主成分分析(PCA)算法比较类似。

2种因子分析

因子分析又分为两种:

  • 探索性因子分析:不确定在现有的自变量背后到底有几个因子在起作用,我们通过需要这种方法试图寻找到这几个因子
  • 验证性因子分析:已经假设自变量背后有几个因子,试图通过这种方法去验证一下这种假设是否正确。

模型推导

假设有p个原始的变量xii=1,2,px_i(i=1,2,…p),它们之间可能独立也可能相关。将xix_i标准化后得到新的变量ziz_i,我们可以建立如下的因子分析模型:

zi=ai1F1+ai2F2++aimFm+ciUi(i=1,2,,p)z_{i}=a_{i 1} F_{1}+a_{i 2} F_{2}+\cdots+a_{i m} F_{m}+c_{i} U_{i} (i=1,2, \cdots, p)

其中,我们可以定义以下几个术语:公共因子、特殊因子、载荷因子、载荷矩阵

1、第一点:Fj(j=1,2,m)F_j(j=1,2,…m)出现在每个变量的式子中且m<p,称之为公共因子

2、第二点:Ui(i=1,2,p)U_i(i=1,2,…p)仅仅与变量ziz_i相关,称之为特殊因子

3、第三点:系数aijci(i=1,2pj=1,2,m)a_{ij}、c_i(i=1,2…p,j=1,2,…m)称之为载荷因子

4、第四点:A=(aij)A={(a_{ij})}称之为载荷矩阵

上面的式子可以表示为:z=AF+CUz=AF+CU

同时也就满足:

A=\left(a_{i j}\right)_{p \times m}, \quad C=\operatorname{diag}\left(c_{1}, c_{2}, \cdots, c_{p}\right)$$ 我们通常需要对上述模型的进行假设: 1.各个特殊因子以及特殊因子和公共因子之间相互独立,即满足: $$\left\{\begin{array}{l}\operatorname{Cov}(U)=\operatorname{diag}\left(\sigma_{1}^{2}, \sigma_{2}^{2}, \cdots, \sigma_{p}^{2}\right) \\ \operatorname{Cov}(F, U)=0\end{array}\right.$$ 2、各公共因子都是均值为0、方差为1的独立正态随机变量,其协方差矩阵为单位矩阵$I_m$,即$F-N(0,I_m)$ 3、m个公共因子对第i个变量方差的贡献称之为第i**贡献度**,记为$h_i^2$ $$h_{i}^{2}=a_{i 1}^{2}+a_{i 2}^{2}+\cdots+a_{i m}^{2}$$ 4、特殊因子的方差称之为**特殊方差**或者**特殊值**($\sigma_{i}^{2},i=1,2,3…p$) 5、第i个变量的方差分解为:$\operatorname{Var} z_{i}=h_{i}^{2}+\sigma_{i}^{2}, i=1,2, \cdots, p$ 具体的模型推导过程:https://blog.csdn.net/qq_29831163/article/details/88901245 ### 因子载荷矩阵的重要性质 关于因子载荷矩阵的几个重要性质: 1、因子载荷$a_{ij}$是第i个变量与第j个公共因子的相关系数,反映的是第i个变量和第j个公共因子之间的重要性。**绝对值越大,表示相关性的密切程度越高**。 2、贡献度的统计意义 $$h_{i}^{2}=a_{i 1}^{2}+a_{i 2}^{2}+\cdots+a_{i m}^{2}=\sum_{i=1}^ma_{ij}^2$$ 说明:变量$X_i$的贡献度就是因子载荷矩阵的第i行的元素的平方和 上式两边同时求方差: $$\operatorname{Var}\left(X_{i}\right)=a_{i 1}^{2} \operatorname{Var}\left(F_{1}\right)+\cdots+a_{i m}^{2} \operatorname{Var}\left(F_{m}\right)+\operatorname{Var}\left(\varepsilon_{i}\right)$$ 也就是:$1=\sum_{j=1}^{m} a_{i j}^{2}+\sigma_{i}^{2}$ 可以看出来:公共因子和特殊因子对变量$X_i$的贡献度之和为1。如果$\sum_{i=1}^ma_{ij}^2$非常接近1,则$\sigma^2$非常小,则因子分析的效果非常好。 3、公共因子$F_{j}$方差贡献的统计意义 因子载荷矩阵中各列元素的平方和 $S_j=\sum_{i=1}^p a_{ij}^2$成为$F_(j)$对所有的$X_j$的方差贡献和,衡量$F_j$的相对重要性。 ## 因子分析步骤 应用因子分析法的主要步骤如下: - 对所给的数据样本进行**标准化处理** - 计算样本的**相关矩阵R** - 求相关矩阵R的**特征值、特征向量** - 根据系统要求的**累积贡献度**确定主因子的个数 - 计算因子**载荷矩阵A** - 最终确定因子模型 ## factor_analyzer库 利用Python进行因子分析的核心库是:factor_analyzer ```python pip install factor_analyzer ``` 这个库主要有两个主要的模块需要学习: - factor_analyzer.analyze(重点) - factor_analyzer.factor_analyzer 官网学习地址:https://factor-analyzer.readthedocs.io/en/latest/factor_analyzer.html ## 案例实战 下面通过一个案例来讲解如何进行因子分析。 ### 导入数据 本文中使用的数据是公开的数据集,下面是数据的介绍和下载地址: - 数据集介绍: [https://vincentarelbundock.github.io/Rdatasets/doc/psych/bfi.](https://vincentarelbundock.github.io/Rdatasets/doc/psych/bfi.html)[html](https://vincentarelbundock.github.io/Rdatasets/doc/psych/bfi.html) - 数据集下载: https://vincentarelbundock.github.io/Rdatasets/datasets.html 这个数据集收集了2800个人关于人格的25个问题。同时这些数据和隐藏的5个特征相关, > Big Five Model is widely used nowadays, the five factors include: **neuroticism,extraversion,openness to experience,agreeableness and conscientiousness.** 特征之间的对应关系为: - 认同性:agree=c(“-A1”,“A2”,“A3”,“A4”,“A5”) - 勤奋的、有责任的:conscientious=c(“C1”,“C2”,“C3”,“-C4”,“-C5”) - 外向的:extraversion=c(“-E1”,“-E2”,“E3”,“E4”,“E5”) - 神经质、不稳定性:neuroticism=c(“N1”,“N2”,“N3”,“N4”,“N5”) - 开放的:openness = c(“O1”,“-O2”,“O3”,“O4”,“-O5”) 事先我们并不知道这些隐形变量的对应关系,所以想要通过因子分析来找到25个变量后面的隐藏变量。下面开始进行因子分析的实战过程: ## 导入库 导入数据处理和分析所需要的库: ```python # 数据处理 import pandas as pd import numpy as np # 绘图 import seaborn as sns import matplotlib.pyplot as plt # 因子分析 from factor_analyzer import FactorAnalyzer ``` ## 数据探索 ### 数据信息 首先我们先导进数据:总共是2800条数据,28个特征属性 ```python df = pd.read_csv("bfi.csv", index_col=0).reset_index(drop=True) df ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/764cef4318c647ecab0cc394d66606e9~tplv-k3u1fbpfcp-zoom-1.image) 查看下数据的缺失值情况:**大部分的字段都是存在缺失值的** ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6ac5564d90404759b20d506f3b264e46~tplv-k3u1fbpfcp-zoom-1.image) ### 数据预处理 数据预处理包含去除3个无效的字段(对分析没有任何作用:age、gender、education),同时去掉存在空值的数据: ```python # 去掉无效字段 df.drop(["gender","education","age"],axis=1,inplace=True) # 去掉空值 df.dropna(inplace=True) ``` ## 充分性检测 在进行因子分析之前,需要先进行充分性检测,主要是检验相关特征阵中各个变量间的相关性,是否为单位矩阵,也就是检验各个变量是否各自独立。通常是两种方法: - Bartlett's球状检验(巴特利球形检验) - KMO检验 ### Bartlett's球状检验 检验总体变量的相关矩阵是否是单位阵(相关系数矩阵对角线的所有元素均为1,所有非对角线上的元素均为零);即检验各个变量是否各自独立。 如果不是单位矩阵,说明原变量之间存在相关性,可以进行因子分子;反之,原变量之间不存在相关性,数据不适合进行主成分分析 ```python from factor_analyzer.factor_analyzer import calculate_bartlett_sphericity chi_square_value, p_value = calculate_bartlett_sphericity(df) chi_square_value, p_value # 结果 (18170.96635086924, 0.0) ``` 我们发现统计量p-value的值为0,表明变量的相关矩阵不是单位矩阵,即各个变量之间是存在一定的相关性,我们就可以进行因子分析。 ### KMO检验 检查变量间的相关性和偏相关性,取值在0-1之间;KOM统计量越接近1,变量间的相关性越强,偏相关性越弱,因子分析的效果越好。 > **Kaiser-Meyer-Olkin (KMO) Test** measures the suitability of data for factor analysis. It determines the adequacy for each observed variable and for the complete model. > > KMO estimates the proportion of variance among all the observed variable. Lower proportion id more suitable for factor analysis. KMO values range between 0 and 1. Value of KMO less than 0.6 is considered inadequate. 通常取值从0.6开始进行因子分析 ```python from factor_analyzer.factor_analyzer import calculate_kmo kmo_all,kmo_model=calculate_kmo(df) kmo_all ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4ddcf54fcf94c5fa71f8ba44bcb2381~tplv-k3u1fbpfcp-zoom-1.image) KMO大于0.6,也说明变量之间存在相关性,可以进行分析。 ## 选择因子个数 在数据说明中,我们已经知道了这些变量是和5个隐藏的因子相关。但是很多情况下,我们并不知道这个个数,需要自己进行探索。 方法:**计算相关矩阵的特征值,进行降序排列** ### 特征值和特征向量 ```python faa = FactorAnalyzer(25,rotation=None) faa.fit(df) # 得到特征值ev、特征向量v ev,v=faa.get_eigenvalues() ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cc4e4d6d8616426193a95baae204e233~tplv-k3u1fbpfcp-zoom-1.image) ### 可视化展示 我们将特征值和因子个数的变化绘制成图形: ```python # 同样的数据绘制散点图和折线图 plt.scatter(range(1, df.shape[1] + 1), ev) plt.plot(range(1, df.shape[1] + 1), ev) # 显示图的标题和xy轴的名字 # 最好使用英文,中文可能乱码 plt.title("Scree Plot") plt.xlabel("Factors") plt.ylabel("Eigenvalue") plt.grid() # 显示网格 plt.show() # 显示图形 ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cdb882f69cf3450b99afc683e536f9e0~tplv-k3u1fbpfcp-zoom-1.image) 从上面的图形中,我们明确地看到:选择5个因子是最合适的 ## 建模 ### 因子分析-fit 我们选择5个因子来进行因子分子的建模过程,同时指定矩阵旋转方式为:**方差最大化** ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2754e3135f58495c9130b1bfa696e874~tplv-k3u1fbpfcp-zoom-1.image) ratation参数的其他取值情况: - varimax (orthogonal rotation) - promax (oblique rotation) - oblimin (oblique rotation) - oblimax (orthogonal rotation) - quartimin (oblique rotation) - quartimax (orthogonal rotation) - equamax (orthogonal rotation) ### 查看因子方差-get_communalities() 上面执行fit建模后,我们查看每个因子的方差,使用方法:get_communalities() ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4c511e807206458da6e95f39ef81bb91~tplv-k3u1fbpfcp-zoom-1.image) ### 查看特征值-get_eigenvalues 查看变量的特征值: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bad000efb31c447f9e44368395ee57b5~tplv-k3u1fbpfcp-zoom-1.image) ### 查看成分矩阵-loadings 现在有25个变量,5个隐藏变量(因子),查看它们构成的成分矩阵: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/91f79c21b3ce4a0fb8111af70ecb6999~tplv-k3u1fbpfcp-zoom-1.image) 如果转成DataFrame格式,index就是我们的25个变量,columns就是指定的5个因子factor。转成DataFrame格式后的数据: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/935f9e2d71ae4a96b8241a867ca15f6f~tplv-k3u1fbpfcp-zoom-1.image) ### 查看因子贡献率-get_factor_variance() 通过理论部分的解释,我们发现每个因子都对变量有一定的贡献,存在某个贡献度的值,在这里查看3个和贡献度相关的指标: - 总方差贡献:variance (numpy array) – The factor variances - 方差贡献率:proportional_variance (numpy array) – The proportional factor variances - 累积方差贡献率:cumulative_variances (numpy array) – The cumulative factor variances ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d1dd98a87ca1400182d60193949403cc~tplv-k3u1fbpfcp-zoom-1.image) ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3d0330bab2124894bf3759a649aa3852~tplv-k3u1fbpfcp-zoom-1.image) ## 隐藏变量可视化 为了更直观地观察每个隐藏变量和哪些特征的关系比较大,进行可视化展示,为了方便取上面相关系数的绝对值: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7b1650a674c0408287d2e43d87e7ebf5~tplv-k3u1fbpfcp-zoom-1.image) 然后我们通过热力图将系数矩阵绘制出来: ```python # 绘图 plt.figure(figsize = (14,14)) ax = sns.heatmap(df1, annot=True, cmap="BuPu") # 设置y轴字体大小 ax.yaxis.set_tick_params(labelsize=15) plt.title("Factor Analysis", fontsize="xx-large") # 设置y轴标签 plt.ylabel("Sepal Width", fontsize="xx-large") # 显示图片 plt.show() # 保存图片 # plt.savefig("factorAnalysis", dpi=500) ``` ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/045b011bcade49209053a4296445f357~tplv-k3u1fbpfcp-zoom-1.image) ## 转成新变量-transformn 上面我们已经知道了5个因子比较合适,可以将原始数据转成5个新的特征,具体转换方式为: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/28d9d619d1f04ae69af8198ecf55b3a1~tplv-k3u1fbpfcp-zoom-1.image) 转成DataFrame格式后数据展示效果更好:仍然是2436条数据,5个特征(新特征) ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/55a1a0af84c34a79940cf4fc1d114098~tplv-k3u1fbpfcp-zoom-1.image) 至此,我们完成了如下的工作: 1. 原数据的相关性检测 2. 因子个数的探索 3. 因子分析的建模过程 4. 隐藏变量的可视化 5. 转成基于5个新变量的数据 ## 参考资料 1、Factor Analysis:https://www.datasklr.com/principal-component-analysis-and-factor-analysis/factor-analysis 2、多因子分析:https://mathpretty.com/10994.html 3、`factor_analyzer package`的官网使用手册:https://factor-analyzer.readthedocs.io/en/latest/factor_analyzer.html 4、浅谈主成分分析和因子分析:https://zhuanlan.zhihu.com/p/37755749