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를 활용한 비지도 학습 예제:
# 비지도 학습: 클러스터링과 차원 축소 예제
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")