본문 바로가기
개발/Python

주성분 분석 Biplot

by 피로물든딸기 2026. 1. 18.
반응형

전체 링크

 

Biplot

- 데이터는 어디에 모여 있고, 그 원인이 되는 변수는 무엇인가를 한 번에 보여주는 그래프

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# 샘플 데이터 생성
np.random.seed(0)
X = pd.DataFrame({
    "Length": np.random.normal(10, 2, 50),
    "Width": np.random.normal(5, 1, 50),
    "Height": np.random.normal(7, 1.5, 50),
    "Weight": np.random.normal(20, 3, 50),
})

# 표준화
X_scaled = StandardScaler().fit_transform(X)

# PCA
pca = PCA(n_components=2)
scores = pca.fit_transform(X_scaled)
loadings = pca.components_.T

# Biplot
plt.figure()
plt.scatter(scores[:, 0], scores[:, 1])
for i, feature in enumerate(X.columns):
    plt.arrow(0, 0, loadings[i, 0]*3, loadings[i, 1]*3, 
              head_width=0.05, length_includes_head=True)
    plt.text(loadings[i, 0]*3.2, loadings[i, 1]*3.2, feature)

plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("PCA Biplot Example")
plt.axhline(0)
plt.axvline(0)
plt.show()

- 각 점은 관측치(sample) 를 의미

- PC1, PC2 공간에서 데이터가 어떻게 분포하는지 보여줌

 

- 각 화살표는 원 변수(feature)를 의미

- 방향 : 해당 변수가 어떤 주성분에 영향을 주는지

- 길이 : 해당 변수가 주성분에 기여하는 정도

 

 

- Weight, Width → PC1 방향 영향 큼

- Length → PC2 음의 방향으로 강한 영향

- Height → PC2 양의 방향 영향

 

 

- 화살표 간 각도가 작음 → 양의 상관

- 90도 근처 → 거의 무상관

- 180도 → 음의 상관


USArrests 데이터 셋

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import statsmodels.api as sm

# 데이터 로딩
data = sm.datasets.get_rdataset("USArrests", "datasets").data
states = data.index

# PCA
X = StandardScaler().fit_transform(data)
pca = PCA(n_components=2)
scores = pca.fit_transform(X)
loadings = pca.components_.T

# 그룹 정의 (질문 번호 기준)
group1 = ["Georgia", "Maryland", "New Mexico"]
group2 = ["Michigan", "Texas"]
group3 = ["Colorado", "California", "New Jersey"]
group4 = ["Idaho", "New Hampshire", "Iowa"]

groups = {
    "1. High Murder & Assault": (group1, "red"),
    "2. High Rape": (group2, "purple"),
    "3. High UrbanPop": (group3, "blue"),
    "4. Low Crime & Urban": (group4, "green")
}

# 전체 점 (연한 회색)
plt.figure(figsize=(11, 9))
plt.scatter(scores[:, 0], scores[:, 1], alpha=0.3)

# 그룹별 색상 표시
for label, (states_list, color) in groups.items():
    idx = [i for i, s in enumerate(states) if s in states_list]
    plt.scatter(scores[idx, 0], scores[idx, 1], label=label, color=color, s=80)
    for i in idx:
        plt.text(scores[i, 0], scores[i, 1], states[i], fontsize=9)

# 변수 화살표
for i, var in enumerate(data.columns):
    plt.arrow(0, 0, loadings[i, 0]*3, loadings[i, 1]*3, head_width=0.05)
    plt.text(loadings[i, 0]*3.2, loadings[i, 1]*3.2, var, fontsize=11)

plt.axhline(0)
plt.axvline(0)
plt.xlabel(f"PC1 ({pca.explained_variance_ratio_[0]*100:.1f}%)")
plt.ylabel(f"PC2 ({pca.explained_variance_ratio_[1]*100:.1f}%)")
plt.title("PCA Biplot of USArrests (Grouped Interpretation)")
plt.legend()
plt.show()

 

조지아, 메릴랜드, 뉴멕시코

- 폭행과 살인의 비율이 상대적으로 높은 지역

- Georgia, Maryland → PC1 양수

- Murder / Assault 화살표 방향과 가까움

- New Mexico는 Assault보다는 Rape 영향이 더 큼

 

미시간, 텍사스

- 강간의 비율이 높은 지역

- Rape 화살표는 PC1 양수 + PC2 약간 음수

 

콜로라도, 캘리포니아, 뉴저지

- 도시에 거주하는 인구의 비율이 높음

- UrbanPop 화살표 방향과 매우 가까움

- PC2 양수 쪽에 위치

 

아이다호, 뉴햄프셔, 아이오와

- 도시 인구 비율이 낮고 3대 강력범죄도 낮은 지역

- PC1 음수, PC2 음수

 

참고

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import statsmodels.api as sm

# 1. 데이터 로딩
data = sm.datasets.get_rdataset("USArrests", "datasets").data
states = data.index

# 2. 표준화
scaler = StandardScaler()
X_scaled = scaler.fit_transform(data)

# 3. PCA
pca = PCA(n_components=2)
scores = pca.fit_transform(X_scaled)
loadings = pca.components_.T

# 4. Biplot
plt.figure(figsize=(10, 8))

# 관측치(주)
plt.scatter(scores[:, 0], scores[:, 1])
for i, state in enumerate(states):
    plt.text(scores[i, 0], scores[i, 1], state, fontsize=8)

# 변수(화살표)
for i, var in enumerate(data.columns):
    plt.arrow(
        0, 0,
        loadings[i, 0] * 3,
        loadings[i, 1] * 3,
        head_width=0.05
    )
    plt.text(
        loadings[i, 0] * 3.2,
        loadings[i, 1] * 3.2,
        var,
        fontsize=10
    )

plt.xlabel(f"PC1 ({pca.explained_variance_ratio_[0]*100:.1f}%)")
plt.ylabel(f"PC2 ({pca.explained_variance_ratio_[1]*100:.1f}%)")
plt.title("PCA Biplot of USArrests")
plt.axhline(0)
plt.axvline(0)
plt.show()

반응형

'개발 > Python' 카테고리의 다른 글

데이터 분석 기획  (2) 2026.01.01
데이터 처리 기술  (1) 2025.12.28
데이터 이해  (0) 2025.12.23
데이터 시각화  (0) 2025.12.18
확률분포  (0) 2025.12.12

댓글