차원축소
| 기법 | 설명 | 장점 | 단점 및 한계 |
|---|---|---|---|
| PCA (주성분 분석) | 고차원 데이터를 서로 직교하는 주성분(PC)으로 변환하여 데이터의 분산(Variance) 을 최대화함. 고차원 데이터를 저차원으로 변환해 데이터의 분산을 최대화하는 새로운 축을 찾음. 주로 차원 축소와 데이터 시각화에 활용 | 정보 손실 최소화, 다중공선성 제거, 노이즈 감소 효율적. | 주성분의 통계적 해석이 어려움, 선형 관계만 포착 가능, 스케일링에 민감. |
| 대응분석 (CA) | 범주형 데이터(분할표)의 행과 열 사이의 연관성 을 시각화하고 차원을 축소함. | 범주형 데이터 간 상관관계 시각화 우수, 비선형 관계 포착 가능. | 희귀 범주(Outlier)에 민감, 빈도수 기반 데이터에만 적용 가능. |
| 요인분석 (FA) | 관측된 변수들 이면에 존재하는 잠재 요인(Latent Factor) 을 찾아 변수 간 상관관계를 설명함. 차원을 축소해 구조 파악, 변수를 요인으로 묶어 해석력 UP | 결과 해석 용이(회전 기법 활용), 데이터 생성 원인 파악 가능, 데이터 구조 해석력 UP | 요인 개수 설정의 주관성, 정규분포 가정 필요, 계산 복잡도 높음, 결과의 의미 판단 난해, 모든 변수의 관계 완벽하게 설명하지 못할 위험 |
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris(as_frame=True).frame; df = iris
y=df.pop('target'); X=df단순 차원축소 (변수선택)
- 지도학습
변수를 단순히 줄이는 방식의 차원축소도 있다.
다중공선성이 의심되는 경우, 모델의 성능을 해칠 불필요한 정보가 다수 들어있는 경우
PCA
if 'PCA':
v1=np.random.uniform(-5, 5, 100)
v2=np.random.uniform(-3, 3, 100)
v3=0.5*v1 - 0.2*v2 + np.random.normal(0, 0.5, 100)
X = pd.DataFrame({'col1': v1,'col2': v2,'col3': v3})
# PCA 는 정규화 필수 (특히 feature의 단위가 다를 때)
from sklearn.preprocessing import StandardScaler
stdscaler = StandardScaler()
X_scaled = stdscaler.fit_transform(X)
from sklearn.decomposition import PCA
# 2개의 주성분으로 압축
# n=2; pca = PCA(n_components = n)
pca = PCA() # n을 설정하지 않으면 feature 숫자만큼 주성분 추출
pca.fit(X_scaled)
# 요인 회전(Rotation) 같은 과정이 없음. 계산이 매우 빠르지만 해석이 어려울 수 있음.
pd.DataFrame(
pca.components_ # 주성분 벡터
, columns=X.columns
, index=[f'PC{i+1}' for i in range(pca.n_components_)]
)
# pca.explained_variance_ # 각 주성분 고유값
# pca.explained_variance_ratio_ # 각 주성분 분산 비율
pca_vals_top2 = pca.transform(X_scaled)[:,:2]
X_reduced = pca.transform(X_scaled) # 변환된 데이터
X_scaled = pca.inverse_transform(X_reduced) # 원본 데이터
if 'loadings':
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# df2_solve의 원본 컬럼명 리스트 저장 (PCA 적용 전 상태)
original_columns = df2_solve.columns
# pca.components_ 는 (n_components, n_features) 형태의 배열을 반환한다.
loadings = pd.DataFrame(
pca.components_,
columns=original_columns,
index=[f'PC{i+1}' for i in range(pca.n_components_)]
)
# 1. 수치로 기여도 확인
print("주성분별 원본 변수 적재량(Loadings):")
print(loadings)
# 2. 히트맵을 통한 직관적 시각화 (해석 시 매우 유용)
plt.figure(figsize=(12, 6))
# cmap='RdBu'를 통해 양의 상관관계는 파란색, 음의 상관관계는 빨간색으로 시각화
sns.heatmap(loadings, annot=True, cmap='RdBu', center=0, fmt='.2f')
plt.title('PCA Component Loadings')
plt.tight_layout()
plt.show()요인분석
| 구분 | 세부 항목 | 설명 및 기준 |
|---|---|---|
| 분석 목적 | 데이터 축소 | 다수의 변수를 소수의 요인으로 압축하여 다중공선성 방지 및 모델 단순화 |
| 구조 파악 및 타당성 | 변수 간 내재적 패턴 발견 및 측정도구의 구성타당도(Construct Validity) 검증 | |
| 파생 변수 생성 | 추출된 요인 점수를 새로운 독립 변수로 활용 (회귀분석, 군집분석 등) | |
| 분석 종류 | 탐색적 요인분석 (EFA) | 사전 정보 없이 데이터 자체의 패턴을 탐색하여 숨겨진 요인 구조 도출 |
| 확인적 요인분석 (CFA) | 선행 연구나 가설을 바탕으로 설정한 요인 구조가 실제 데이터와 부합하는지 검증 | |
| 핵심 지표 | 요인 적재량 (Factor Loading) | 변수와 요인 간의 상관계수 (일반적으로 절대값 이상 유의미) |
| 고유값 (Eigenvalue) | 한 요인이 설명하는 전체 분산의 크기 (Kaiser 규칙에 따라 보통 이상 추출) | |
| 공통성 (Communality) | 변수가 추출된 전체 요인에 의해 설명되는 분산 비율 ( 미만 시 변수 제거 고려) | |
| 요인 회전 | 직각 회전 (Orthogonal) | 요인 간 상관관계가 없다고 가정 (대표적으로 Varimax 사용) |
| 사각 회전 (Oblique) | 요인 간 상관관계가 있다고 가정 (대표적으로 Promax 사용) | |
| PCA와의 차이 | 해석의 초점 | PCA는 단순 분산 보존 및 차원 축소 목적, FA는 숨겨진 인과적 원인(의미) 규명 목적 |
고객의 이탈율(Churn)이나 행동 지표를 분석하시는 업무를 가정해보겠습니다. 앱 내에서 수집되는 10개의 세부 행동 지표가 있다고 해봅시다.
- 로그인 횟수, 체류 시간, 게시글 작성 수, 댓글 작성 수, ‘좋아요’ 클릭 수, etc
이 10개 지표를 모두 예측 모델에 넣으면 다중공선성 문제가 발생하거나 모델이 복잡해질 수 있습니다. 이때 요인분석을 돌려보면 다음과 같이 묶일 수 있습니다.
- 요인 1 (참여도 요인): 게시글 작성 수, 댓글 작성 수, ‘좋아요’ 클릭 수가 높게 적재됨.
- 요인 2 (접속성 요인): 로그인 횟수, 체류 시간이 높게 적재됨.
결과적으로 10개의 개별 지표를 **‘참여도’**와 **‘접속성’**이라는 2개의 핵심 요인(새로운 변수)으로 축소하여 고객 이탈 예측 모델의 입력값으로 훨씬 깔끔하게 활용할 수 있습니다.
| 구분 | 주성분 분석 (PCA) | 요인 분석 (Factor Analysis) |
|---|---|---|
| 핵심 비유 | 믹서기 (재료를 섞어 하나의 주스로 압축) | 탐정 (증상들을 통해 숨겨진 질병 원인 규명) |
| 인과 방향 | 관측 데이터 주성분 (데이터의 선형 결합) | 잠재 요인 관측 데이터 (요인이 데이터를 발현시킴) |
| 분석 목적 | 정보(분산) 손실을 최소화한 차원 축소 (데이터 압축) | 변수들 이면에 존재하는 숨겨진 구조와 의미 파악 |
| 분석 목적 | 숨겨진 원인에는 관심 없음, 단순 압축 | 전체 정보량 (분산) 을 보전하는 효율적인 슈퍼 변수 제작 |
| 분산 취급 방식 | 전체 분산 (공통 분산 + 고유 분산 + 에러 모두 포함) | 공통 분산 (고유 분산과 에러는 배제하고 교집합만 추출) |
| 결과물의 해석 | 생성된 주성분(PC)에 구체적인 의미를 부여하기 어려움 | 추출된 잠재 요인에 명확한 개념적 ‘이름표’ 부여 가능 |
| 주요 사용처 | 머신러닝 전처리, 다중공선성 제거, 이미지 압축 | 설문조사 문항 검증, 유저 심리 지표 개발, 세그먼테이션 |
-
FA:
-
“유저들의 내면에는 **‘충성도(Loyalty)‘**와 **‘구매력(Purchasing Power)‘**이라는 숨겨진 심리적 요인이 있을 거야.”
-
분석 결과: 충성도가 높기 때문에 ‘로그인 횟수’와 ‘체류 시간’이 높게 나타나고, 구매력이 높기 때문에 ‘결제 금액’과 ‘장바구니 담기’가 높게 나타난다고 해석합니다.
-
주요 타겟: “이 지표들이 도대체 무슨 의미로 묶이는 걸까?” (의미와 구조 파악)
-
-
PCA:
-
“머신러닝(예: 이탈 예측 모델)을 돌려야 하는데 변수가 4개나 되네? 연산량이 많아지고 과적합(Overfitting) 우려가 있으니 변수를 줄이자.”
-
분석 결과: 4개의 변수를 수학적으로 지지고 볶아서 원래 데이터의 특성을 90% 이상 설명하는 2개의 새로운 축(PC1, PC2)을 만들어냅니다. PC1이 정확히 무슨 의미인지는 사람이 딱 잘라 말하기 모호할 수 있습니다. (예: PC1 = 0.5로그인 + 0.3체류시간 + 0.1*결제…)
-
주요 타겟: “의미는 잘 몰라도 좋으니, 모델에 넣기 좋게 데이터 용량만 빵빵하게 압축해 줘!” (머신러닝 전처리)
-
수학적/통계적 관점에서의 결정적 차이 (분산):
-
FA (공통 분산만 취급): 변수들끼리 **‘서로 겹치는 부분(공통 분산)‘**만 가지고 분석합니다. 즉, 자신만의 고유한 특성(오차)은 불순물로 보고 버립니다. 그래서 결과가 더 깔끔하고 해석하기 좋습니다.
- 어떤 현상의 **‘이유와 의미’**를 설명하여 리포팅하거나 인사이트를 도출해야 한다면 **FA(요인분석)**를,
-
PCA (전체 분산 다 취급): 변수들이 가진 **‘모든 정보(공통 분산 + 고유 분산 + 오차)‘**를 다 때려 넣고 압축합니다. 정보의 유실을 막는 것이 최우선이기 때문입니다.
- 단순히 데이터 크기를 줄여서 예측 모델이나 분류 모델의 **‘인풋 데이터’**로 깔끔하게 넣고 싶다면 **PCA(주성분분석)**를 사용하시면 됩니다.
| 구분 | 주성분 분석 (PCA) | 요인 분석 (FA) |
|---|---|---|
| 분석 철학 | 전체 분산(Variance) 극대화 및 차원 압축 | 공통 분산(Common Variance) 추출 및 잠재 요인 규명 |
| 공분산/상관행렬 대각원소 | 1 (자기 자신의 모든 분산 포함) | 공통성 (Communality, SMC 등) 추정치 |
| 분산의 취급 | 고유 분산(Unique Variance)과 오차 포함 | 고유 분산 및 오차 제외, 공유하는 정보만 사용 |
| 핵심 알고리즘 | 고유값 분해 (Eigen Decomposition) | 최대우도법(ML), 주축요인추출(PAF) 등 |
| 축 회전 (Rotation) | 데이터 투영 목적의 직교 축 변환 | 해석력 확보를 위한 축 회전 필수 (Varimax, Promax 등) |
| 결과물 및 목적 | 데이터 압축을 위한 주성분(PC) 도출 | 변수 간의 숨겨진 구조(Latent Factor) 파악 |
PCA의 수학적 한계:
- PCA 고유값 분해:
- PCA에서 얻은 주성분은 단순히 원본 변수들의 선형 결합(Linear Combination)이므로, 측정 오차(Measurement Error)를 분리하지 못한다.
- 머신러닝의 전처리(다중공선성 제거, 노이즈 감소) 목적으로 주로 활용된다.
- FA는 공통 분산만 발라내고 사람이 해석하기 좋게 축을 돌리는 통계적 추정(모델링).
- 따라서 행렬의 대각선에 1이 들어감.
FA의 인과적 모델링:
- FA 기본 모델:
- FA의 기본 모델 수식에서 보듯, 관측 가능한 변수 X는 잠재 요인 F와 요인 적재량 Λ, 그리고 고유 오차 e로 구성된다고 가정한다.
- 즉, 변수들 이면에 존재하는 근본적인 원인을 찾는 통계적 모델링이다.
- 설문지 문항 분석이나 심리 측정에서 주로 사용된다.
- FA와 달리, FA는 행렬의 대각선에 1 대신, 다른 변수들과 겹치는 분산인 공통성(SMC: Squared Multiple Correlation 등) 추정치를 넣는다.
- 즉, 나만의 고유한 에러(Unique Variance)는 계산에서 제외하고 **순수하게 남들과 공유하는 정보만 모아놓은 축소된 상관행렬(Reduced Correlation Matrix)**을 만듬.
요인분석(FA)에서 가장 오묘하고 통계학적으로 흥미로운 부분이 바로 질문하신 ‘공통성(Communality, 보통 로 표기) 추정’ 단계입니다.
이를 이해하기 위해서는 요인분석이 직면한 “닭이 먼저냐, 알이 먼저냐”의 딜레마를 먼저 아셔야 합니다.
딜레마: 요인(Factor)을 정확히 뽑아내려면 상관행렬의 대각선에 들어갈 ‘정확한 공통성’을 알아야 합니다. 그런데, ‘정확한 공통성’을 계산하려면 요인을 먼저 뽑아내야만 합니다.
이 모순을 해결하기 위해 통계학자들은 1) 초기 추정치를 먼저 대각선에 집어넣고, 2) 요인을 뽑은 뒤, 3) 공통성을 다시 계산하여 업데이트하는 ‘반복(Iteration)’ 과정을 고안했습니다.
이때 ‘초기 추정치’로 무엇을 쓸 것인가에 대한 대표적인 추정 방법들을 설명해 드리겠습니다.
| 구분 | 기법 명칭 | 원리 및 특징 | 통계적/수학적 의미 |
|---|---|---|---|
| 초기 추정 (고전적 방법) | SMC (다중상관제곱) | 특정 변수를 종속 변수()로, 나머지를 독립 변수()로 둔 다중선형회귀의 결정계수() 활용 | 타 변수들로 설명 가능한 분산의 비율을 공통성으로 간주 (주축요인추출법의 표준) |
| 초기 추정 (고전적 방법) | 최대 절대 상관계수 | 타 변수와의 상관계수 중 절댓값이 가장 큰 값을 대각원소로 사용 | 최소한 가장 강한 상관관계를 가진 변수와의 교집합만큼은 공통성이 존재한다는 보수적 가정 |
| 최적화 알고리즘 | 반복 갱신 (Iteration) | 초기 추정치 삽입 요인 추출 새로운 공통성 계산 대각원소 갱신 과정을 수렴(Convergence) 시까지 반복 | 요인과 공통성의 추정 오차를 최소화하여 최종 요인을 확정하는 수치해석적 과정 |
| 현대적 추출 방법 | 최대우도법 (ML) | 관측 데이터의 다변량 정규성 가정 하에, 현재의 표본 상관행렬이 관찰될 우도(Likelihood)를 극대화하는 파라미터 탐색 | 대각원소 사전 추정 단계 없이, 미적분 최적화를 통해 요인 적재량과 고유 분산을 직접 동시 추정 |
- 요인성 분석 (적합성 확인) 요인 분석이 가능한지 확인하기 위해 **Bartlett의 구형성 검정(Sphericity Test)**과 KMO(Kaiser-Meyer-Olkin) 검정을 실시한다.
(1) Bartlett의 구형성 검정
-
귀무가설(H0): 상관관계 행렬이 단위 행렬(Identity Matrix)이다. (요인 분석 부적합)
-
대립가설(H1): 상관관계 행렬이 단위 행렬이 아니다. (요인 분석 적합)
(2) KMO 검정
변수들 간의 상관관계가 다른 변수들에 의해 얼마나 잘 설명되는지 나타내는 지표이다.
- 일반적으로 0.6 이상이면 요인 분석을 수행하기에 적합하다고 판단한다.
결정된 요인 수(예: 6개)를 바탕으로 요인 회전(Rotation)을 적용하여 분석을 수행한다. 보통 변수 간 독립성을 가정하면 Varimax(직각회전), 상관성을 가정하면 Promax(사선회전)를 사용한다.
if '정규성체크?':
import pingouin as pg
# df: 요인분석에 사용할 데이터프레임
result = pg.multivariate_normality(df)
print(result) # (HZ 통계량, p-value, 정규성 여부)
if '사전':
from factor_analyzer.factor_analyzer import calculate_kmo, calculate_bartlett_sphericity
# 1. Bartlett's Test
chi_square_value, p_value = calculate_bartlett_sphericity(df)
print(f"Bartlett's Test: Chi-square={chi_square_value:.4f}, p-value={p_value:.4f}")
# 2. KMO Test
kmo_all, kmo_model = calculate_kmo(df)
print(f"KMO Measure: {kmo_model:.4f}")
if 'n지정':
# 고유값 확인을 위한 초기 분석
fa = FactorAnalyzer(rotation=None)
fa.fit(df)
ev, v = fa.get_eigenvalues()
# Scree Plot 시각화
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.axhline(y=1, color='r', linestyle='--') # Kaiser Rule 기준선
plt.grid()
plt.show()
# 고유값 1 이상인 개수 확인
n_factors = sum(ev > 1)
print(f"Number of factors with Eigenvalue > 1: {n_factors}")
if 'FA':
from factor_analyzer import FactorAnalyzer
# 2개의 요인을 추출하고, Varimax 방식으로 회전(rotation)시킴
# 보통 변수 간 독립성을 가정하면 Varimax(직각회전),
# 상관성을 가정하면 Promax(사선회전)를 사용한다.
fa = FactorAnalyzer(n_factors=2, rotation='varimax', method='minres')
fa.fit(df) # 데이터에 적합
# 요인 적재량(Factor Loadings) 확인: 어떤 변수가 어떤 요인에 강하게 묶였는지 해석
loadings = fa.loadings_
fa_result = fa.transform(df) # 새로운 요인 점수 획득
fa.get_eigenvalues()
display(pd.DataFrame(fa.loadings_, columns=['Factor1', 'Factor2'], index=df.columns))| Factor1 | Factor2 | |
|---|---|---|
| sepal length (cm) | 0.901205 | 0.017890 |
| sepal width (cm) | -0.150413 | 0.986195 |
| petal length (cm) | 0.964153 | -0.284619 |
| petal width (cm) | 0.921401 | -0.233245 |
대응분석 (CA)
대응분석(Correspondence Analysis, CA)은 두 개 이상의 범주형 변수 간의 관계를 저차원 공간에 시각화하는 다변량 통계 기법이다. 주성분 분석(PCA)이 연속형 변수를 대상으로 한다면, 대응분석은 교차표(Contingency Table)를 바탕으로 카이제곱 거리(χ2 distance)를 사용하여 범주 간의 유사성을 측정한다.
Python에서는 prince 라이브러리가 대응분석을 수행하는 데 가장 표준적으로 사용된다.
import pandas as pd
import prince
import matplotlib.pyplot as plt
# 1. 데이터 생성 (교차표 형태)
# 예: 지역(Rows)과 선호하는 음료(Columns) 간의 관계
data = {
'Coffee': [100, 120, 30, 50],
'Tea': [40, 50, 100, 80],
'Soda': [20, 30, 40, 120]
}
df = pd.DataFrame(data, index=['Seoul', 'Busan', 'Jeju', 'Gwangju'])
# 2. CA 모델 객체 생성 및 학습
# n_components: 추출할 차원의 수 (보통 시각화를 위해 2차원 선택)
ca = prince.CA(n_components=2, n_iter=10, copy=True, check_input=True, engine='sklearn')
ca = ca.fit(df)
# 3. 행(Row)과 열(Column)의 좌표값 확인
print("Row Coordinates:\n", ca.row_coordinates(df))
print("\nColumn Coordinates:\n", ca.column_coordinates(df))
# 4. 설명력(Inertia) 확인
print("\nExplained Inertia (Eigenvalues):", ca.eigenvalues_summary)
# 5. 시각화 (Biplot)
ax = ca.plot_coordinates(
X=df,
ax=None,
figsize=(8, 8),
x_component=0,
y_component=1,
show_row_labels=True,
show_col_labels=True
)
plt.show()| 구분 | 해석 방법 |
|---|---|
| 점들 사이의 거리 | 원점(Origin)에서 같은 방향에 위치한 행과 열 범주는 서로 강한 연관성이 있음. |
| 차원의 설명력 | 각 차원(Dimension)이 총 관성(Inertia)을 얼마나 설명하는지 확인. 보통 1, 2차원 합계가 70~80% 이상이면 신뢰할 만함. |
| 범주의 위치 | 원점에 가까운 범주는 전체적인 평균 특성을 보이며, 원점에서 먼 범주일수록 해당 데이터셋에서 독특한 특성을 가짐. |