[Week 11] Facing Unlabeled Data: Unsupervised Learning πŸ”

English translation

Hello! Welcome to Week 11.
So far, we have covered learning with given 'answers (y)',
namely Supervised Learning (e.g., Linear/Logistic Regression and Decision Trees).

Today, we study another major branch of Machine Learning: Unsupervised Learning.
Given data without correct answers (labels),
it discovers hidden structure or patterns within the data itself.

Today, two representative Unsupervised Learning techniques,

  1. K-Means Clustering: A technique for finding hidden groups in data\
  2. We will study PCA, a technique for reducing data dimensionality for visualization,
    and implement it using scikit-learn.

🧺 Module 1: K-Means Clustering

What Is Clustering?

An Intuitive Understanding of K-Means:

K-Means Exercise 1: Exploring the Principle with Synthetic Data

Apply K-Means using scikit-learn.
First, generate synthetic data for clustering practice using make_blobs.

# Import required libraries
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs # Data generator for clustering exercises
from sklearn.cluster import KMeans # K-Means model
from sklearn.decomposition import PCA # PCA
from sklearn.preprocessing import StandardScaler # Data scaler
from sklearn.datasets import load_iris # Iris dataset

# 1. Prepare data (generate unlabeled data)
# n_samples=300: Generate 300 samples
# centers=3: Generate 3 groups (centers)
# cluster_std=2.0: How spread out the groups are
# random_state=42: Fix the seed for reproducibility
# X is 2D data with shape (300, 2); y_true is the ground truth (0,1,2)
X, y_true = make_blobs(n_samples=300, centers=3,
                       cluster_std=2.0, random_state=42)

# 2. Explore data (visualization)
# For unsupervised learning, assume the ground truth (y_true) is unknown
# and display all data in gray (c='gray').
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c='gray', s=50, alpha=0.7)
plt.title("Unlabeled Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.grid(True)
plt.show()

print("우리의 λͺ©ν‘œ: 이 νšŒμƒ‰ 점듀을 3개의 그룹으둜 λΆ„λ₯˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.")
<Figure size 640x480 with 1 Axes>
μ‹€ν–‰ κ²°κ³Ό
우리의 λͺ©ν‘œ: 이 νšŒμƒ‰ 점듀을 3개의 그룹으둜 λΆ„λ₯˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

K-Means Exercise 2: Training the Model and Checking Results

Now create and train the KMeans model.
The key parameter is n_clusters (K).

# 1. Create a K-Means model
# n_clusters=3 : Set the desired number of groups (K) to 3
# random_state=42 : Fix the leaders' initial random positions
model_kmeans = KMeans(n_clusters=3, random_state=42)

# 2. Train the model (fit)
# For unsupervised learning, provide only X without ground truth (y)!
# The 'assignment' and 'update' steps repeat internally during this process.
model_kmeans.fit(X)

# 3. Inspect training results
# model.labels_ : Group number (0, 1, 2) assigned to each data point
y_pred = model_kmeans.labels_
# model.cluster_centers_ : Final positions of the 3 leaders (Centroids) after training
centroids = model_kmeans.cluster_centers_

print("K-Means ν•™μŠ΅ μ™„λ£Œ!")
print(f"예츑된 κ·Έλ£Ή 라벨 (μ•ž 10개): {y_pred[:10]}")
print(f"μ΅œμ’… 쀑심점 μœ„μΉ˜:\n{centroids}")
K-Means ν•™μŠ΅ μ™„λ£Œ!
예츑된 κ·Έλ£Ή 라벨 (μ•ž 10개): [1 1 0 2 1 2 0 2 0 0]
μ΅œμ’… 쀑심점 μœ„μΉ˜:
[[-2.75726773  9.07285344]
 [-6.88811639 -7.0878587 ]
 [ 4.85432791  2.04801886]]

Visualize how the trained model grouped the data
using model.labels_.

# Visualize K-Means clustering results
plt.figure()
# Plot the data with colors (c) set to the predicted groups (y_pred)
plt.scatter(X[:, 0], X[:, 1],
            c=y_pred, s=50, cmap='viridis', alpha=0.7)

# Overlay final centroids as red 'x' markers
plt.scatter(centroids[:, 0], centroids[:, 1],
            c='red', s=200, marker='X', label='Centroids')

plt.title("K-Means Clustering Result (K=3)")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.legend()
plt.grid(True)
plt.show()

print("μ •λ‹΅(λ ˆμ΄λΈ”) 없이도 λ°μ΄ν„°μ˜ λΆ„ν¬λ§ŒμœΌλ‘œ 그룹을 μ„±κ³΅μ μœΌλ‘œ μ°Ύμ•„λƒˆμŠ΅λ‹ˆλ‹€.")
<Figure size 640x480 with 1 Axes>
μ‹€ν–‰ κ²°κ³Ό
μ •λ‹΅(λ ˆμ΄λΈ”) 없이도 λ°μ΄ν„°μ˜ λΆ„ν¬λ§ŒμœΌλ‘œ 그룹을 μ„±κ³΅μ μœΌλ‘œ μ°Ύμ•„λƒˆμŠ΅λ‹ˆλ‹€.

🧐 Module 2: Finding the Best K (Elbow Method)

We set n_clusters=3 because we knew there were 3 true groups.
In real Unsupervised Learning, however, we do not know the appropriate K.

How Do We Choose K?

Elbow Method:

# List for storing Inertia while varying K from 1 to 10
inertia_list = []
k_range = range(1, 11)

for k in k_range:
    # 1. Create and train K-Means with the current k
    model = KMeans(n_clusters=k, random_state=42)
    model.fit(X)
    # 2. Append the trained model's Inertia to the list
    # The model.inertia_ attribute stores the trained Inertia value.
    inertia_list.append(model.inertia_)
print("K값에 λ”°λ₯Έ Inertia 계산 μ™„λ£Œ!")

# Plot Inertia (y-axis) against K (x-axis) as a line plot
plt.figure()
plt.plot(k_range, inertia_list, marker='o', linestyle='--')
plt.title("Elbow Method")
plt.xlabel("K")
plt.ylabel("Inertia")
plt.grid(True)
plt.show()

print("κ²°κ³Ό 해석:")
print("- K=1μ—μ„œ 2둜, 2μ—μ„œ 3으둜 갈 λ•ŒλŠ” Inertiaκ°€ κΈ‰κ²©νžˆ κ°μ†Œν•©λ‹ˆλ‹€.")
print("- K=3μ—μ„œ 4둜 갈 λ•ŒλΆ€ν„°λŠ” κ°μ†Œν­μ΄ μ™„λ§Œν•΄μ§‘λ‹ˆλ‹€.")
print("=> λ”°λΌμ„œ, 이 κ·Έλž˜ν”„μ˜ 'νŒ”κΏˆμΉ˜(Elbow)' 지점은 K=3이며,")
print("   졜적의 ν΄λŸ¬μŠ€ν„° κ°œμˆ˜λŠ” 3개라고 νŒλ‹¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€.")
K값에 λ”°λ₯Έ Inertia 계산 μ™„λ£Œ!
<Figure size 640x480 with 1 Axes>
μ‹€ν–‰ κ²°κ³Ό
κ²°κ³Ό 해석:
- K=1μ—μ„œ 2둜, 2μ—μ„œ 3으둜 갈 λ•ŒλŠ” Inertiaκ°€ κΈ‰κ²©νžˆ κ°μ†Œν•©λ‹ˆλ‹€.
- K=3μ—μ„œ 4둜 갈 λ•ŒλΆ€ν„°λŠ” κ°μ†Œν­μ΄ μ™„λ§Œν•΄μ§‘λ‹ˆλ‹€.
=> λ”°λΌμ„œ, 이 κ·Έλž˜ν”„μ˜ 'νŒ”κΏˆμΉ˜(Elbow)' 지점은 K=3이며,
   졜적의 ν΄λŸ¬μŠ€ν„° κ°œμˆ˜λŠ” 3개라고 νŒλ‹¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“‰ Module 3: Dimensionality Reduction and PCA

Now we move to the second Unsupervised Learning topic: Dimensionality Reduction.

What Is Dimensionality?

Why reduce dimensions?

  1. Visualization: Humans can perceive up to 3 dimensions.\
  1. Curse of Dimensionality: As dimensionality increases (too many features),
    the space containing the data grows very large while the data become sparse,
    which can reduce model performance (e.g., unnecessary noise features).

Principal Component Analysis (PCA):

[Important] Data Preprocessing for PCA: Scaling

PCA works based on the data's variance.
If features (columns) have different measurement scales (e.g., height (150~190) vs. weight (40~100)),
the higher-variance 'height' feature will have an excessively large influence on PCA.

Therefore, before PCA, to treat all features as equally important,
use Standardization (Standard Scaling) to give all features mean 0 and variance 1.
This preprocessing is essential.

Use StandardScaler from scikit-learn.

# 1. Load the Iris data
iris = load_iris()
# Use all 4 features (4D)
X_iris = iris.data
y_iris = iris.target

print(f"원본 데이터 Shape: {X_iris.shape}")

# 2. Scale data using StandardScaler
# Create a StandardScaler object
scaler = StandardScaler()

# In one step, have scaler learn the mean and standard deviation (fit)
# and transform the data using those values (transform)
X_scaled = scaler.fit_transform(X_iris)

print(f"\nμŠ€μΌ€μΌλ§ ν›„ 데이터 (μ•ž 5쀄):\n{np.round(X_scaled[:5], 2)}")
print(f"\nμŠ€μΌ€μΌλ§ ν›„ 전체 평균 (β‰ˆ0): {X_scaled.mean():.4f}")
print(f"μŠ€μΌ€μΌλ§ ν›„ 전체 ν‘œμ€€νŽΈμ°¨ (β‰ˆ1): {X_scaled.std():.4f}")
원본 데이터 Shape: (150, 4)

μŠ€μΌ€μΌλ§ ν›„ 데이터 (μ•ž 5쀄):
[[-0.9   1.02 -1.34 -1.32]
 [-1.14 -0.13 -1.34 -1.32]
 [-1.39  0.33 -1.4  -1.32]
 [-1.51  0.1  -1.28 -1.32]
 [-1.02  1.25 -1.34 -1.32]]

μŠ€μΌ€μΌλ§ ν›„ 전체 평균 (β‰ˆ0): -0.0000
μŠ€μΌ€μΌλ§ ν›„ 전체 ν‘œμ€€νŽΈμ°¨ (β‰ˆ1): 1.0000

PCA Exercise 1: Reduce Dimensionality from 4D β†’ 2D

Now reduce the scaled, 4-dimensional Iris data
to 2 dimensions using PCA.

# 1. Create a PCA model
# n_components=2 : Compress 4 features into 2 principal components (2D)
pca = PCA(n_components=2)

# 2. Train the PCA model (fit) and transform the data (transform)
# Take scaled 4D data (X_scaled) as input
# and return data transformed into 2D principal component space (X_pca)
X_pca = pca.fit_transform(X_scaled)

print("PCA λ³€ν™˜ μ™„λ£Œ!")
print(f"원본 데이터 Shape: {X_scaled.shape}")
print(f"PCA λ³€ν™˜ ν›„ Shape: {X_pca.shape}")
PCA λ³€ν™˜ μ™„λ£Œ!
원본 데이터 Shape: (150, 4)
PCA λ³€ν™˜ ν›„ Shape: (150, 2)

PCA Exercise 2: Interpreting Results

Reducing dimensions with PCA causes information loss.
Check how much information is retained.

explained_variance_ratio_:

# Inspect PCA's 'explained variance' ratios
variance_ratio = pca.explained_variance_ratio_

print(f"μ„€λͺ…λœ λΆ„μ‚° λΉ„μœ¨ (PC1, PC2): {variance_ratio}")

# Total variance (information) explained by the two principal components
total_variance = np.sum(variance_ratio)
print(f"\n총 λΆ„μ‚° λΉ„μœ¨: {total_variance * 100:.2f}%")

print("\n=> 4차원 데이터λ₯Ό 2μ°¨μ›μœΌλ‘œ μ••μΆ•ν–ˆμ§€λ§Œ,")
print(f"   μ•½ {total_variance * 100:.2f}%λ₯Ό λ³΄μ‘΄ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€!")
μ„€λͺ…λœ λΆ„μ‚° λΉ„μœ¨ (PC1, PC2): [0.72962445 0.22850762]

총 λΆ„μ‚° λΉ„μœ¨: 95.81%

=> 4차원 데이터λ₯Ό 2μ°¨μ›μœΌλ‘œ μ••μΆ•ν–ˆμ§€λ§Œ,
   μ•½ 95.81%λ₯Ό λ³΄μ‘΄ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€!

PCA Exercise 3: 2D Visualization

Plot the 2-dimensional data transformed by PCA (X_pca) as a scatter plot.
Color the points by their original Iris species (y_iris)
to check whether the species remain distinguishable in 2-dimensional space.

# Visualize the 2D data transformed by PCA
plt.figure()

# Use column 0 of X_pca for the x-axis and column 1 for the y-axis
# Use the original ground truth (y_iris) for colors (c)
plt.scatter(X_pca[:, 0], X_pca[:, 1],
            c=y_iris, cmap='viridis', alpha=0.7)

plt.title("PCA Result")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.colorbar(label='Iris Species')
plt.grid(True)
plt.show()

print("κ²°κ³Ό 해석:")
print("- λ°μ΄ν„°μ˜ 뢄포가 2차원 평면에도 κ½€ 잘 λ‚˜νƒ€λ‚©λ‹ˆλ‹€.")
print("- 각 뢓꽃 ν’ˆμ’…(색깔)이 2차원 κ³΅κ°„μ—μ„œλ„",
      "λšœλ ·ν•˜κ²Œ κ΅¬λΆ„λ˜λŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.")
print("=> PCAκ°€ λ°μ΄ν„°μ˜ 핡심 ꡬ쑰λ₯Ό 잘 λ³΄μ‘΄ν•˜λ©°",
      "차원을 μΆ•μ†Œν–ˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.")
<Figure size 640x480 with 2 Axes>
μ‹€ν–‰ κ²°κ³Ό
κ²°κ³Ό 해석:
- λ°μ΄ν„°μ˜ 뢄포가 2차원 평면에도 κ½€ 잘 λ‚˜νƒ€λ‚©λ‹ˆλ‹€.
- 각 뢓꽃 ν’ˆμ’…(색깔)이 2차원 κ³΅κ°„μ—μ„œλ„ λšœλ ·ν•˜κ²Œ κ΅¬λΆ„λ˜λŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
=> PCAκ°€ λ°μ΄ν„°μ˜ 핡심 ꡬ쑰λ₯Ό 잘 λ³΄μ‘΄ν•˜λ©° 차원을 μΆ•μ†Œν–ˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

✨ Wrap-up

Today we learned to handle data without ground truth using Unsupervised Learning.

Next time, we will work with MLP (Multilayer Perceptron), the foundation of the models learned so far
and a basic Deep Learning model.