🤖 AI/ML

Unsupervised Learning

비지도 학습

레이블 없이 데이터의 숨겨진 패턴과 구조를 학습하는 머신러닝 기법. 클러스터링, 차원 축소, 이상 탐지에 활용.

📖 상세 설명

비지도 학습(Unsupervised Learning)은 정답 레이블이 없는 데이터로부터 숨겨진 패턴, 구조, 관계를 자동으로 발견하는 머신러닝 기법입니다. 지도 학습(Supervised Learning)이 "이 이미지는 고양이다"라는 명시적인 답을 제공받아 학습하는 반면, 비지도 학습은 데이터만 주어지고 스스로 "이 데이터들은 비슷한 특성을 공유한다"와 같은 구조를 찾아냅니다. 레이블링 비용이 높거나 불가능한 실제 산업 데이터에서 특히 유용합니다.

비지도 학습의 주요 유형에는 클러스터링(Clustering), 차원 축소(Dimensionality Reduction), 밀도 추정(Density Estimation), 이상 탐지(Anomaly Detection)가 있습니다. 클러스터링은 K-Means, DBSCAN, 계층적 클러스터링 등의 알고리즘으로 유사한 데이터를 그룹화합니다. 차원 축소는 PCA, t-SNE, UMAP 등으로 고차원 데이터를 저차원으로 압축하면서 핵심 정보를 보존합니다. 이상 탐지는 정상 패턴에서 벗어난 데이터를 식별합니다.

실무에서 비지도 학습은 고객 세분화, 추천 시스템의 아이템 그룹화, 유전체 데이터 분석, 사기 탐지, 네트워크 침입 탐지 등 다양한 분야에 적용됩니다. 예를 들어, 이커머스 회사는 구매 패턴을 기반으로 고객을 자동 분류하여 맞춤형 마케팅 전략을 수립합니다. 금융 기관은 거래 데이터에서 비정상적인 패턴을 탐지하여 사기를 예방합니다.

비지도 학습의 발전은 자기지도 학습(Self-Supervised Learning)과 대조 학습(Contrastive Learning)으로 이어졌습니다. BERT, GPT와 같은 대형 언어 모델의 사전 학습(Pre-training)도 넓은 의미의 비지도 학습에 해당합니다. 레이블 없이 대규모 텍스트에서 언어의 구조와 의미를 학습하기 때문입니다. 데이터는 많지만 레이블은 부족한 현실에서, 비지도 학습은 AI 시스템의 핵심 학습 패러다임 중 하나입니다.

💻 코드 예제

K-Means 클러스터링과 PCA를 활용한 비지도 학습 예제:

Python
# 비지도 학습: 클러스터링과 차원 축소 예제
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs, load_iris
from sklearn.cluster import KMeans, DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
from sklearn.manifold import TSNE

# ========================
# 1. K-Means 클러스터링
# ========================
print("=== K-Means Clustering ===")

# 샘플 데이터 생성 (레이블 없이 사용)
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)

# 스케일링
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 최적의 k 찾기 (Elbow Method)
inertias = []
silhouettes = []
k_range = range(2, 10)

for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    kmeans.fit(X_scaled)
    inertias.append(kmeans.inertia_)
    silhouettes.append(silhouette_score(X_scaled, kmeans.labels_))

# 최적의 k 선택 (Silhouette 기준)
optimal_k = k_range[np.argmax(silhouettes)]
print(f"Optimal k (by silhouette): {optimal_k}")
print(f"Best silhouette score: {max(silhouettes):.3f}")

# 최적 k로 클러스터링 수행
kmeans_final = KMeans(n_clusters=optimal_k, random_state=42, n_init=10)
clusters = kmeans_final.fit_predict(X_scaled)

print(f"Cluster sizes: {np.bincount(clusters)}")


# ========================
# 2. DBSCAN 클러스터링
# ========================
print("\n=== DBSCAN Clustering ===")

# DBSCAN은 클러스터 수를 자동으로 결정
dbscan = DBSCAN(eps=0.5, min_samples=5)
dbscan_clusters = dbscan.fit_predict(X_scaled)

n_clusters_dbscan = len(set(dbscan_clusters)) - (1 if -1 in dbscan_clusters else 0)
n_noise = list(dbscan_clusters).count(-1)

print(f"DBSCAN clusters found: {n_clusters_dbscan}")
print(f"Noise points: {n_noise}")


# ========================
# 3. PCA 차원 축소
# ========================
print("\n=== PCA Dimensionality Reduction ===")

# Iris 데이터 (4D -> 2D)
iris = load_iris()
X_iris = iris.data  # 레이블 없이 특성만 사용

# PCA 적용
pca = PCA(n_components=2)
X_pca = pca.fit_transform(StandardScaler().fit_transform(X_iris))

print(f"Original dimensions: {X_iris.shape[1]}")
print(f"Reduced dimensions: {X_pca.shape[1]}")
print(f"Explained variance ratio: {pca.explained_variance_ratio_}")
print(f"Total variance explained: {sum(pca.explained_variance_ratio_):.3f}")


# ========================
# 4. 클러스터링 + 시각화
# ========================
class UnsupervisedAnalyzer:
    """비지도 학습 분석 클래스"""

    def __init__(self, random_state=42):
        self.random_state = random_state
        self.scaler = StandardScaler()

    def cluster_analysis(self, X, max_k=10):
        """최적 클러스터 수 분석"""
        X_scaled = self.scaler.fit_transform(X)

        results = {
            'k': [],
            'inertia': [],
            'silhouette': []
        }

        for k in range(2, max_k + 1):
            kmeans = KMeans(n_clusters=k, random_state=self.random_state, n_init=10)
            labels = kmeans.fit_predict(X_scaled)

            results['k'].append(k)
            results['inertia'].append(kmeans.inertia_)
            results['silhouette'].append(silhouette_score(X_scaled, labels))

        return results

    def reduce_and_cluster(self, X, n_clusters=3, reduction='pca'):
        """차원 축소 후 클러스터링"""
        X_scaled = self.scaler.fit_transform(X)

        # 차원 축소
        if reduction == 'pca':
            reducer = PCA(n_components=2, random_state=self.random_state)
        else:  # t-SNE
            reducer = TSNE(n_components=2, random_state=self.random_state,
                          perplexity=30, n_iter=300)

        X_reduced = reducer.fit_transform(X_scaled)

        # 클러스터링
        kmeans = KMeans(n_clusters=n_clusters, random_state=self.random_state, n_init=10)
        labels = kmeans.fit_predict(X_scaled)

        return X_reduced, labels

    def anomaly_detection(self, X, contamination=0.1):
        """이상치 탐지 (Isolation Forest)"""
        from sklearn.ensemble import IsolationForest

        X_scaled = self.scaler.fit_transform(X)

        iso_forest = IsolationForest(
            contamination=contamination,
            random_state=self.random_state
        )

        # -1: anomaly, 1: normal
        predictions = iso_forest.fit_predict(X_scaled)
        anomalies = X[predictions == -1]

        return predictions, anomalies


# 사용 예제
analyzer = UnsupervisedAnalyzer()

# 클러스터 분석
print("\n=== Cluster Analysis ===")
results = analyzer.cluster_analysis(X)
best_k = results['k'][np.argmax(results['silhouette'])]
print(f"Best k: {best_k}, Silhouette: {max(results['silhouette']):.3f}")

# 차원 축소 + 클러스터링
X_2d, labels = analyzer.reduce_and_cluster(X_iris, n_clusters=3)
print(f"\nIris data clustered into {len(set(labels))} groups")
print(f"2D representation shape: {X_2d.shape}")

# 이상치 탐지
predictions, anomalies = analyzer.anomaly_detection(X)
print(f"\nDetected {len(anomalies)} anomalies out of {len(X)} samples")

🗣️ 실무에서 이렇게 말해요

데이터 분석 회의에서
"고객 데이터에 레이블이 없어서 비지도 학습으로 세분화해봤어요. K-Means로 5개 그룹이 나왔는데 실루엣 스코어가 0.6 정도 나옵니다."
이상 탐지 시스템 논의에서
"정상 거래 패턴만 있으니까 비지도 학습 기반 이상 탐지를 적용해야 할 것 같아요. Isolation Forest나 Autoencoder 써볼까요?"
데이터 전처리 단계에서
"모델 학습 전에 PCA로 차원 축소해서 노이즈 줄이고, 클러스터링 결과를 피처로 추가하면 성능이 좋아질 것 같아요."
ML 엔지니어 대화에서
"레이블 수집 비용이 너무 높아서, 먼저 비지도로 클러스터링 하고 대표 샘플만 레이블링하는 게 효율적일 거예요."

⚠️ 흔한 실수 & 주의사항

클러스터 수를 임의로 결정
K-Means에서 k를 그냥 3이나 5로 정하면 안 됩니다. Elbow Method, Silhouette Score, Gap Statistic 등을 활용해 데이터에 적합한 클러스터 수를 결정하세요.
스케일링 없이 클러스터링
거리 기반 알고리즘(K-Means, DBSCAN)은 피처 스케일에 민감합니다. StandardScaler나 MinMaxScaler로 정규화하지 않으면 특정 피처가 결과를 지배하게 됩니다.
결과의 정답을 기대
비지도 학습은 "발견"이지 "예측"이 아닙니다. 클러스터링 결과가 비즈니스적으로 의미 있는지는 도메인 전문가의 해석이 필요하며, 반드시 유용한 그룹이 나온다는 보장은 없습니다.
고차원 데이터에 바로 클러스터링
차원이 높으면 거리 개념이 무의미해지는 "차원의 저주"가 발생합니다. 수백 개 이상의 피처가 있다면 PCA 등으로 차원을 축소한 후 클러스터링하는 것이 좋습니다.

🔗 관련 용어

📚 더 배우기