파이썬으로 탐색적 요인분석, 신뢰도 분석하기
그동안 심리학을 비롯한 사회과학 분야에서 연구할 때 가장 많이 쓰던 통계 프로그램은 SPSS였다.
최근에 회사에서 심리검사 결과를 가지고 이게 잘 만들어진 검사인지 검증하기 위한 통계분석, 구체적으로는 탐색적 요인분석(EFA: Exploratory Factor Analysis)과 신뢰도 계수(Cronbach’s alpha)를 확인하는 작업을 할 일이 있었는데, 난 SPSS가 없어서 파이썬으로 해결했다.
코드 예시를 간략히 메모 차원에서 남겨봐야겠다.
준비
파이썬으로 데이터 분석 좀 해본 사람들이라면 numpy, pandas, matplotlib, seaborn까지는 대부분 설치했을 거다. 아, 그리고 jupyter notebook도.
이번에는 ‘요인분석’을 위한 패키지 factor-analyzer까지 설치해주자.
설치 방법은 늘상 그렇듯.
1
pip install factor-analyzer
분석 코드 예시
데이터 살펴보기
일단 필요한 라이브러리 불러오고, 엑셀로 저장된 파일을 pandas 데이터프레임 형태로 불러왔다.
1
2
3
4
5
6
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_excel("data.xlsx")
문항 리스트 준비하기
각 문항들은 모두 1~5점 리커트 척도로 구성되었다.
분석에 앞서 문항들을 내가 애초에 설계한 요인 구조에 따라 좀 묶어놓을 필요가 있다.
일단 열(컬럼) 이름을 뽑아보면
1
df.columns
1
Index(['respondent-id', 'sex', 'a-1', 'b-1', 'c-1', 'd-1', 'e-1', 'f-1', 'g-1', 'h-1', 'a-2', 'b-2', 'c-2', 'd-2', 'e-2', 'f-2', 'g-2', 'h-2', 'a-3', 'b-3', 'c-3', 'd-3', 'e-3', 'f-3', 'g-3', 'h-3'], dtype='object')
이런 모양새다. 앞에 수검자 번호와 성별 빼고 뒷 부분 24개가 문항이다.
애초에 a부터 h까지 총 8개의 요인, 요인당 3개 문항으로 구성되도록 해놓았다.
이걸 리스트 형태로 변환해서 items라는 변수에 담아주고 정렬을 해놓자.
1
2
items = df.columns.tolist()[2:]
items.sort()
1
['a-1', 'a-2', 'a-3', 'b-1', 'b-2', 'b-3', 'c-1', 'c-2', 'c-3', 'd-1', 'd-2', 'd-3', 'e-1', 'e-2', 'e-3', 'f-1', 'f-2', 'f-3', 'g-1', 'g-2', 'g-3', 'h-1', 'h-2', 'h-3']
이제 원래 데이터프레임 df에서 items에 있는 컬럼들의 값을 가져와 요인분석을 돌릴 거다.
탐색적 요인분석(EDA) 수행하기
일단 아까 설치했던 라이브러리를 한 번 불러와보자.
1
from factor_analyzer import FactorAnalyzer
그리고 요인분석 모델을 불러온다. 불러올 때 요인 개수, 회전 방법 등을 선택할 수 있는데, 일단 요인 개수는 8개, 최대우도방법, promax 회전으로 돌려볼 거다. (파라미터 설정에 대해 좀 더 자세히 알고 싶다면 FactorAnalyzer github를 참고하자.)
1
2
fa = FactorAnalyzer(n_factors=8, method="ml", rotation="promax")
fa.fit(df[items])
그리고 방금 데이터 넣고 돌릴 때 .fit()
이라는 이름의 메서드를 사용했는데, 파이썬의 머신러닝 scikit-learn 라이브러리 사용해본 사람은 익숙할 거다.
아무튼 이게 끝이다.
요인 부하량은 fa.loadings_
를 출력해보면 확인할 수 있는데…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
array([[ 1.24276282e-01, 3.95265985e-01, 1.87318076e-01,
-3.12377289e-02, -9.95634664e-02, -6.82004265e-02,
1.74049220e-01, -2.75130028e-04],
[-4.15189606e-03, 9.03954874e-01, -4.94827334e-02,
-4.43622592e-03, -2.98582932e-02, -4.33654049e-02,
-5.24262732e-02, -4.18444548e-02],
[-7.78104868e-02, 8.85572048e-01, -8.07603310e-02,
7.47079191e-02, 1.21708537e-03, 9.08425871e-02,
-9.51157387e-02, -9.78357663e-02],
... (중략) ...
[-1.10158523e-01, 1.63145065e-01, 1.33565470e-01,
1.10847724e-02, 2.22950841e-01, 5.53432143e-02,
-3.05526090e-02, 1.73291420e-01]])
이걸 어떻게 봐… 그러니 pandas 데이터프레임 형태로 바꿔보자. 이때 index는 아까 정리한 items(문항 번호 리스트)를 넣어주면 된다.
1
efa_result= pd.DataFrame(fa.loadings_, index=items)
이걸 깔끔하게 시각화 하고 싶다면 seaborn으로 히트맵을 그리면 된다. (숫자는 소숫점 두 번째 자리까지만 표기되도록 했다.)
1
2
plt.figure(figsize=(6,10))
sns.heatmap(efa_result, cmap="Blues", annot=True, fmt='.2f')
일단 탐색적 요인분석 방법은 여기까지.
신뢰도 계수(Cronbach’s alpha) 확인하기
각 요인에 할당해놓은 문항들을 묶어서 신뢰도 계수(Cronbach’s alpha)도 한 번 확인해보자.
이건 뭐 별도의 라이브러리를 설치할 필요 없이 numpy로 바로 계산이 가능하다. 누군가가 신뢰도를 구하는 함수를 만들어서 이렇게 올려놓았더라.
1
2
3
4
5
6
def CronbachAlpha(itemscores):
itemscores = np.asarray(itemscores)
itemvars = itemscores.var(axis=0, ddof=1)
tscores = itemscores.sum(axis=1)
nitems = itemscores.shape[1]
return (nitems / (nitems-1)) * (1 - (itemvars.sum() / tscores.var(ddof=1)))
이 함수는 각 문항들의 점수를 세트(리스트의 리스트 혹은 다차원 배열)로 넣어줘야 하는 거라… 아까 준비해놓았던 문항 번호 리스트 items를 가지고 준비해보자.
1
2
3
4
5
factors = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
factors_items_dict = {}
for factor in factors:
factors_items_dict[factor] = [x for x in items if x[0] == factor]
일단 factors_items_dict라는 딕셔너리에다가 a부터 h까지 요인에 해당하는 문항을 담았다. 이런 모양새다.
1
2
3
4
5
6
7
8
{'a': ['a-1', 'a-2', 'a-3'],
'b': ['b-1', 'b-2', 'b-3'],
'c': ['c-1', 'c-2', 'c-3'],
'd': ['d-1', 'd-2', 'd-3'],
'e': ['e-1', 'e-2', 'e-3'],
'f': ['f-1', 'f-2', 'f-3'],
'g': ['g-1', 'g-2', 'g-3'],
'h': ['h-1', 'h-2', 'h-3']}
이제 여기서 하나씩 불러와서 신뢰도를 찍어보자.
1
2
3
4
for key, value in factors_items_dict.items():
print(key)
print(CronbachAlpha(df[value]))
print()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a
0.7405101159919194
b
0.6434213337169863
c
0.7722376346207973
d
0.8132146902628883
e
0.6025806790180286
f
0.7797227511940578
g
0.7797358204347294
h
0.6488698703179792
요인 b, e, h는 0.7이 안 되는 수준이다. 나머지 요인들은 꽤 준수하네.
일단 오늘은 여기까지.
통계분석은 파이썬으로 합시다.