跳至主要内容

Python 因子分析入门

在本教程中,您将学习因子分析的基础知识以及如何在 Python 中实现。
· 10分钟 阅读

使用 AI 探索

因子分析(FA)是一种探索性数据分析方法,用于从一组观测变量中寻找具有影响力的潜在因素或潜变量。它通过减少变量数量来帮助数据解读。因子分析从所有变量中提取最大共同方差,并将其汇总为公共得分。

因子分析广泛应用于市场研究、广告、心理学、金融和运筹学。市场研究人员使用因子分析来识别价格敏感型客户、找出影响消费者选择的品牌特征,并有助于理解分销渠道的选择标准。

因子分析

因子分析是一个线性统计模型。它用于解释观测变量之间的方差,并将一组观测变量压缩为称为“因子”的不可观测变量。观测变量被建模为因子和误差项的线性组合(来源)。因子或潜变量与多个具有共同响应模式的观测变量相关。每个因子解释观测变量中的特定方差量。它通过减少变量数量来帮助数据解释。

因子分析是一种研究若干感兴趣变量 X1、X2、……、Xl 是否与更少数量的不可观测因子 F1、F2、……、Fk 线性相关的方法。

来源:该图片由我根据因子分析笔记中的一张图片重绘。图片给出了因子分析的整体视图。

基本假设:

  1. 数据中没有离群点。
  2. 样本量应大于因子数量。
  3. 不应存在完全多重共线性。
  4. 变量之间不应存在同方差性。

因子分析的类型

  • 探索性因子分析(EFA):这是社会和管理研究者中最流行的因子分析方法。其基本假设是任何观测变量都可以直接与任何因子相关。
  • 验证性因子分析(CFA):其基本假设是每个因子与一组特定的观测变量相关。CFA 用于在基础设定上进行验证。

因子分析如何工作?

因子分析的主要目标是减少观测变量的数量并找到不可观测的变量。这些不可观测变量有助于市场研究人员对调查做出结论。将观测变量转换为不可观测变量可通过两个步骤实现:

  • 因子提取:此步骤使用方差分解方法(如主成分分析和共同因子分析)选择因子数量和提取方法。
  • 因子旋转:此步骤尝试将因子转换为不相关的因子——其主要目标是提升整体可解释性。常见的旋转方法包括:Varimax(方差最大化)旋转、Quartimax 旋转和 Promax 旋转。

术语

什么是因子?

因子是描述若干观测变量之间关联的潜在变量。因子数量的最大值等于观测变量的数量。每个因子解释观测变量中的一定方差量。方差最小的因子会被舍弃。因子也称为潜变量、隐藏变量、不可观测变量或假设变量。

什么是因子载荷?

因子载荷是一个矩阵,显示每个变量与潜在因子的关系。它给出观测变量与因子之间的相关系数,反映观测变量所解释的方差。

什么是特征值(Eigenvalues)?

特征值表示各因子从总方差中所解释的方差量,也称为特征根。

什么是共同度(Communalities)?

共同度是每个变量的载荷平方和,表示共同方差。范围为 0–1,越接近 1 表示解释的方差越多。

什么是因子旋转?

旋转是改进因子分析解释性的工具。旋转可以是正交或斜交。它通过更清晰的载荷模式重新分配共同度。

选择因子数量

Kaiser 准则是一种分析方法,基于“解释更大方差比例的因子将被选取”。特征值是确定因子数量的良好依据。一般而言,特征值大于 1 的因子会被选中。

图形法基于因子特征值的可视化表示,也称为碎石图(scree plot)。碎石图帮助我们在曲线出现“肘部”的地方确定因子数量。

来源

因子分析 vs. 主成分分析

  • PCA 成分解释的是最大方差,而因子分析解释的是数据中的协方差。
  • PCA 成分彼此完全正交,而因子分析不要求因子正交。
  • PCA 成分是观测变量的线性组合;而在 FA 中,观测变量是不可观测变量(因子)的线性组合。
  • PCA 成分通常难以解释;在 FA 中,潜在因子可被命名并具有可解释性。
  • PCA 属于降维方法,而因子分析是潜变量方法。
  • PCA 是因子分析的一种。PCA 偏观察性,而 FA 是一种建模技术。

来源

使用 factor_analyzer 包在 Python 中进行因子分析

导入所需库

# Import required libraries
import pandas as pd
from sklearn.datasets import load_iris
from factor_analyzer import FactorAnalyzer
import matplotlib.pyplot as plt

加载数据

让我们对 BFI(基于人格评估项目的数据集)进行因子分析,该数据集使用 6 点量表收集:1 非常不准确,2 较不准确,3 稍微不准确,4 稍微准确,5 较准确,6 非常准确。您也可以通过以下链接下载该数据集:https://vincentarelbundock.github.io/Rdatasets/datasets.html

df= pd.read_csv("bfi.csv")

预处理数据

df.columns
Index(['A1', 'A2', 'A3', 'A4', 'A5', 'C1', 'C2', 'C3', 'C4', 'C5', 'E1', 'E2',
       'E3', 'E4', 'E5', 'N1', 'N2', 'N3', 'N4', 'N5', 'O1', 'O2', 'O3', 'O4',
       'O5', 'gender', 'education', 'age'],
      dtype='object')
# Dropping unnecessary columns
df.drop(['gender', 'education', 'age'],axis=1,inplace=True)
# Dropping missing values rows
df.dropna(inplace=True)
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 2436 entries, 0 to 2799
Data columns (total 25 columns):
A1    2436 non-null float64
A2    2436 non-null float64
A3    2436 non-null float64
A4    2436 non-null float64
A5    2436 non-null float64
C1    2436 non-null float64
C2    2436 non-null float64
C3    2436 non-null float64
C4    2436 non-null float64
C5    2436 non-null float64
E1    2436 non-null float64
E2    2436 non-null float64
E3    2436 non-null float64
E4    2436 non-null float64
E5    2436 non-null float64
N1    2436 non-null float64
N2    2436 non-null float64
N3    2436 non-null float64
N4    2436 non-null float64
N5    2436 non-null float64
O1    2436 non-null float64
O2    2436 non-null int64
O3    2436 non-null float64
O4    2436 non-null float64
O5    2436 non-null float64
dtypes: float64(24), int64(1)
memory usage: 494.8 KB
df.head()
 A1A2A3A4A5C1C2C3C4C5...N1N2N3N4N5O1O2O3O4O5
02.04.03.04.04.02.03.03.04.04.0...3.04.02.02.03.03.063.04.03.0
12.04.05.02.05.05.04.04.03.04.0...3.03.03.05.05.04.024.03.03.0
25.04.05.04.04.04.05.04.02.05.0...4.05.04.02.03.04.025.05.02.0
34.04.06.05.05.04.04.03.05.05.0...2.05.02.04.01.03.034.03.05.0
42.03.03.04.05.04.04.05.03.02.0...2.03.04.04.03.03.034.03.03.0

5 行 × 25 列

适用性检验

在执行因子分析之前,您需要评估数据集的“可因子化性”。可因子化性意味着“我们能在数据集中找到因子吗?”。有两种方法来检验因子化或抽样适度:

  • Bartlett 球形度检验
  • Kaiser-Meyer-Olkin(KMO)检验

Bartlett 球形度检验使用观测相关矩阵与单位矩阵进行比较,检查观测变量之间是否存在相互相关性。如果检验结果在统计上不显著,则不应进行因子分析。

from factor_analyzer.factor_analyzer import calculate_bartlett_sphericity
chi_square_value,p_value=calculate_bartlett_sphericity(df)
chi_square_value, p_value
(18146.065577234807, 0.0)

在此 Bartlett 检验中,p 值为 0。检验在统计上显著,表明观测相关矩阵不是单位矩阵。

Kaiser-Meyer-Olkin(KMO)检验衡量数据是否适合进行因子分析。它既评估每个观测变量的适度性,也评估完整模型的适度性。KMO 估计所有观测变量之间的方差比例。比例越低越适合进行因子分析。KMO 取值范围为 0 到 1,若小于 0.6 则被认为不适合。

from factor_analyzer.factor_analyzer import calculate_kmo
kmo_all,kmo_model=calculate_kmo(df)
kmo_model
0.8486452309468382

我们数据的整体 KMO 为 0.84,表现非常好。这表明您可以继续进行计划中的因子分析。

选择因子数量

在选择因子数量时,您可以使用 Kaiser 准则和碎石图。两者都基于特征值。

# Create factor analysis object and perform factor analysis
fa = FactorAnalyzer()
fa.analyze(df, 25, rotation=None)
# Check Eigenvalues
ev, v = fa.get_eigenvalues()
ev
 Original_Eigenvalues
05.134311
12.751887
22.142702
31.852328
41.548163
51.073582
60.839539
70.799206
80.718989
90.688089
100.676373
110.651800
120.623253
130.596563
140.563091
150.543305
160.514518
170.494503
180.482640
190.448921
200.423366
210.400671
220.387804
230.381857
240.262539

这里可以看到,只有 6 个因子的特征值大于 1。这意味着我们只需选择 6 个因子(或不可观测变量)。

# Create scree plot using matplotlib
plt.scatter(range(1,df.shape[1]+1),ev)
plt.plot(range(1,df.shape[1]+1),ev)
plt.title('Scree Plot')
plt.xlabel('Factors')
plt.ylabel('Eigenvalue')
plt.grid()
plt.show()

碎石图方法为每个因子及其特征值绘制折线。特征值大于 1 的数量被视为因子数量。

这里可以看到,只有 6 个因子的特征值大于 1。这意味着我们只需选择 6 个因子(或不可观测变量)。

执行因子分析

# Create factor analysis object and perform factor analysis
fa = FactorAnalyzer()
fa.analyze(df, 6, rotation="varimax")
fa.loadings
 Factor1Factor2Factor3Factor4Factor5Factor6
A10.0407830.0952200.048734-0.113057-0.5309870.161216
A20.2355380.0331310.1337140.0637340.661141-0.006244
A30.343008-0.0096210.1213530.0339900.6059330.160106
A40.219717-0.0815180.235140-0.1253380.4045940.086356
A50.414458-0.1496160.1063820.0309770.4696980.236519
C10.077248-0.0043580.5545820.1901240.0075110.095035
C20.0383700.0683300.6745450.0875930.0570550.152775
C30.031867-0.0399940.551164-0.0113380.1012820.008996
C4-0.0662410.216283-0.638475-0.143846-0.1026170.318359
C5-0.1808120.284187-0.5448380.025837-0.0599550.132423
E1-0.5904510.0222800.053915-0.071205-0.1308510.156583
E2-0.6845780.233624-0.088497-0.045561-0.1167160.115065
E30.556774-0.0008950.1033900.2411800.1793960.267291
E40.658395-0.1367880.113798-0.1078080.2411430.158513
E50.5075350.0344900.3098130.2008210.0788040.008747
N10.0680110.805806-0.051264-0.074977-0.174849-0.096266
N20.0229580.789832-0.0374770.006726-0.141134-0.139823
N3-0.0656870.725081-0.059039-0.010664-0.0191840.062495
N4-0.3450720.578319-0.1621740.0629160.0004030.147551
N5-0.1616750.523097-0.025305-0.1618920.0901250.120049
O10.225339-0.0200040.1332010.4794770.0051780.218690
O2-0.0019820.156230-0.086047-0.4966400.0439890.134693
O30.3259540.0118510.0938800.5661280.0766420.210777
O4-0.1777460.207281-0.0056710.3492270.1336560.178068
O5-0.0142210.063234-0.047059-0.576743-0.0575610.135936
  • 因子 1 对 E1、E2、E3、E4 和 E5 的载荷较高(外向性)
  • 因子 2 对 N1、N2、N3、N4 和 N5 的载荷较高(神经质)
  • 因子 3 对 C1、C2、C3、C4 和 C5 的载荷较高(尽责性)
  • 因子 4 对 O1、O2、O3、O4 和 O5 的载荷较高(开放性)
  • 因子 5 对 A1、A2、A3、A4 和 A5 的载荷较高(宜人性)
  • 因子 6 在任何变量上都没有较高载荷,且不易解释。若仅取五个因子会更好。

让我们对 5 个因子执行因子分析。

# Create factor analysis object and perform factor analysis using 5 factors
fa = FactorAnalyzer()
fa.analyze(df, 5, rotation="varimax")
fa.loadings
 Factor1Factor2Factor3Factor4Factor5
A10.0404650.1111260.022798-0.077931-0.428166
A20.2137160.0295880.1390370.0621390.626946
A30.3178480.0093570.1093310.0561960.650743
A40.204566-0.0664760.230584-0.1127000.435624
A50.393034-0.1221130.0878690.0667080.537087
C10.0701840.0104160.5458240.2095840.038878
C20.0332700.0895740.6487310.1154340.102782
C30.023907-0.0308550.557036-0.0051830.111578
C4-0.0649840.240410-0.633806-0.107535-0.037498
C5-0.1763950.290318-0.5624670.036822-0.047525
E1-0.5748350.0428190.033144-0.058795-0.104813
E2-0.6787310.244743-0.102483-0.042010-0.112517
E30.5368160.0241800.0830100.2808770.257906
E40.646833-0.1156140.102023-0.0734220.306101
E50.5040690.0361450.3128990.2137390.090354
N10.0789230.786807-0.045997-0.084704-0.216363
N20.0273010.754109-0.030568-0.010304-0.193744
N3-0.0614300.731721-0.067084-0.004217-0.027712
N4-0.3453880.590602-0.1789020.0752250.005886
N5-0.1612910.537858-0.037309-0.1497690.100931
O10.213005-0.0022240.1150800.5049070.061550
O20.0045600.175788-0.099729-0.4689250.081809
O30.3109560.0267360.0768730.5960070.126889
O4-0.1911960.220582-0.0219060.3690120.155475
O5-0.0053470.085401-0.062730-0.533778-0.010384
# Get variance of each factors
fa.get_factor_variance()
 Factor1Factor2Factor3Factor4Factor5
SS Loadings2.4730902.7096332.0411061.5221531.844498
Proportion Var0.0989240.1083850.0816440.0608860.073780
Cumulative Var0.0989240.2073090.2889530.3498390.423619

5 个因子累计解释了总方差的 42%。

因子分析的优缺点

因子分析可探索大型数据集并发现相互关联的关系。它将观测变量归纳为少数不可观测变量,或识别相互关联变量的分组,帮助市场研究人员简化市场情境,并找出消费者口味、偏好与文化影响之间的隐藏关系。同时,它也有助于改进未来调查问卷。因子使数据解释更为自然。

因子分析的结果可能存在争议。其解释具有可辩性,因为同一组数据因子可能有不止一种解释。在识别因子并命名之后,仍需要相关领域知识。

结论

恭喜您读到本教程的最后!

在本教程中,您学习了什么是因子分析、因子分析的不同类型、因子分析如何工作、因子分析的基本术语、如何选择因子数量、主成分分析与因子分析的比较、如何在 Python 中使用 FactorAnalyzer 包实现因子分析,以及因子分析的优缺点。

期待您的反馈或问题。您可以留言提问,我会尽力回答。

如果您想进一步学习 Python 中的因子分析,请参加 DataCamp 的《Python 无监督学习》课程。

主题