Journal-based Case Study

PCA & LDA untuk Deteksi Kanker Payudara

Studi kasus reduksi dimensi pada Wisconsin Breast Cancer Data untuk memahami bagaimana PCA dan LDA membantu model klasifikasi.

Mulai TutorialDownload Notebook
PCA & LDA untuk Deteksi Kanker Payudara
ScienceDirect / Procedia Computer Science · Enhancing Breast Cancer Detection with Dimensionality Reduction Techniques: A Study Using PCA and LDA on Wisconsin Breast Cancer Data

Banyak dataset medis memiliki puluhan fitur numerik. Sebagian fitur membawa pola penting, sebagian lain bisa membuat model lebih sulit dibaca. Di studi kasus ini, kita akan melihat bagaimana PCA dan LDA dapat digunakan untuk menyederhanakan representasi data sebelum klasifikasi.

Catatan penting

Materi ini hanya untuk edukasi machine learning, bukan alat diagnosis medis.

Ringkasan Paper

Dari paper ke workflow praktik.

Paper sumber membahas reduksi dimensi untuk membantu deteksi kanker payudara pada data terstruktur. Di tutorial ini, kita membangun ulang workflow yang mudah dijalankan: baseline model, transformasi PCA, transformasi LDA, lalu perbandingan metrik.

Masalah machine learning-nya adalah binary classification. Input berupa fitur numerik dari dataset breast cancer, output berupa kelas diagnosis atau label target. PCA tidak memakai label saat mencari komponen utama, sedangkan LDA memakai label untuk mencari proyeksi pemisah kelas.

Apa yang akan dibangun?

Alur eksperimen dari data sampai insight.

  • Load dataset breast cancer dari URL publik
  • Membersihkan kolom ID atau unnamed
  • Mendeteksi target secara fleksibel
  • Scaling fitur numerik
  • Baseline Logistic Regression
  • PCA dua komponen dan visualisasi 2D
  • LDA satu komponen dan visualisasi distribusi kelas
  • Membandingkan baseline, PCA, dan LDA dengan metrik evaluasi
Problem Framing

Ubah masalah nyata menjadi task machine learning.

Tujuannya bukan membuat alat diagnosis, tetapi memahami kapan reduksi dimensi membantu workflow klasifikasi. Kita akan melihat data fitur asli, data setelah PCA, dan data setelah LDA sebagai tiga jalur eksperimen yang dibandingkan secara transparan.

setup

Setup Environment

Kita tetap memakai dependency ringan: pandas, numpy, matplotlib, dan scikit-learn.

Python
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.metrics import (
    accuracy_score,
    precision_score,
    recall_score,
    f1_score,
    classification_report,
    confusion_matrix
)

import warnings
warnings.filterwarnings("ignore")
Output preview

Environment siap untuk data tabular, transformasi dimensi, training model, dan evaluasi.

load dataset

Load Dataset

Dataset dibaca langsung dari URL publik. Jika kamu memakai file lokal, cukup ganti DATA_URL menjadi path CSV di komputermu.

Python
import pandas as pd

DATA_URL = "https://autotrain.app/opendata92bd.html?file=breast-cancer.csv"

df = pd.read_csv(DATA_URL)
df.head()
Output preview

Output awal biasanya berisi banyak fitur numerik dan satu kolom target seperti diagnosis, target, class, label, atau kolom terakhir.

data understanding

Data Understanding dan Target Detection

Karena dataset dari sumber berbeda bisa memakai nama target yang berbeda, kode ini mencari target secara fleksibel.

Python
print("Shape:", df.shape)
df.info()

df.isnull().sum().sort_values(ascending=False).head(20)

possible_targets = ["diagnosis", "target", "class", "label"]

target_col = None
for col in possible_targets:
    if col in df.columns:
        target_col = col
        break

if target_col is None:
    target_col = df.columns[-1]

print("Target column:", target_col)
df[target_col].value_counts()
Output preview

Output Target column memastikan kita tidak salah memilih label. Jika fallback ke kolom terakhir, cek lagi secara manual sebelum lanjut.

Project Access

Bagian praktik lengkap: preprocessing, training, evaluasi, interpretasi, dan file download.

Ringkasan, problem framing, dataset overview, dan preview kode awal tetap bisa dibaca gratis. Untuk mengikuti workflow penuh seperti notebook praktik, gunakan Project Access.

Buka Project Access
cleaning

Clean Unnecessary Columns

Kolom ID atau unnamed biasanya tidak membawa sinyal prediktif. Kita hapus agar model fokus pada fitur numerik yang relevan.

Python
df_clean = df.copy()

for col in df_clean.columns:
    if "unnamed" in col.lower() or col.lower() == "id":
        df_clean = df_clean.drop(columns=[col])

df_clean.head()
Output preview

Dataset menjadi lebih bersih. Jika ada kolom non-fitur lain, kamu dapat menambahkannya ke aturan drop.

split target

Split X dan y

PCA dan LDA bekerja pada data numerik, jadi X dibuat hanya dari kolom integer dan float.

Python
X = df_clean.drop(columns=[target_col])
y = df_clean[target_col]

X = X.select_dtypes(include=["int64", "float64"])

print("X shape:", X.shape)
print("y shape:", y.shape)

target_encoder = LabelEncoder()
y_encoded = target_encoder.fit_transform(y.astype(str))

print("Target classes:")
for idx, label in enumerate(target_encoder.classes_):
    print(idx, "->", label)
Output preview

Target classes membantu membaca kembali label asli setelah model mengeluarkan angka prediksi.

scaling

Train Test Split dan Scaling

Scaling wajib terasa di sini karena PCA, LDA, dan Logistic Regression sensitif terhadap skala fitur.

Python
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y_encoded,
    test_size=0.2,
    random_state=42,
    stratify=y_encoded
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
Output preview

Scaler hanya fit pada data training untuk menghindari data leakage dari test set.

baseline

Baseline Model tanpa PCA/LDA

Baseline dibutuhkan supaya kita tahu apakah reduksi dimensi benar-benar membantu atau justru mengurangi informasi penting.

Python
from sklearn.linear_model import LogisticRegression

baseline_model = LogisticRegression(max_iter=1000, random_state=42)
baseline_model.fit(X_train_scaled, y_train)

baseline_preds = baseline_model.predict(X_test_scaled)

baseline_scores = {
    "model": "Baseline Logistic Regression",
    "accuracy": accuracy_score(y_test, baseline_preds),
    "precision": precision_score(y_test, baseline_preds, zero_division=0),
    "recall": recall_score(y_test, baseline_preds, zero_division=0),
    "f1": f1_score(y_test, baseline_preds, zero_division=0)
}

baseline_scores
Output preview

baseline_scores menjadi pembanding utama untuk PCA dan LDA.

pca

PCA Transformation

PCA mencari dua arah variasi terbesar. Karena tidak melihat label, PCA cocok untuk eksplorasi struktur data.

Python
from sklearn.decomposition import PCA

pca = PCA(n_components=2, random_state=42)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.transform(X_test_scaled)

print("Explained variance ratio:", pca.explained_variance_ratio_)
print("Total explained variance:", pca.explained_variance_ratio_.sum())

plt.figure(figsize=(8, 6))
plt.scatter(
    X_train_pca[:, 0],
    X_train_pca[:, 1],
    c=y_train,
    alpha=0.7
)
plt.title("PCA Projection - Training Data")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.tight_layout()
plt.show()
Output preview

Explained variance menunjukkan seberapa banyak informasi variasi data yang ditangkap dua komponen utama.

pca classification

Classification After PCA

Setelah data diproyeksikan menjadi dua komponen, kita latih Logistic Regression pada ruang PCA.

Python
pca_model = LogisticRegression(max_iter=1000, random_state=42)
pca_model.fit(X_train_pca, y_train)

pca_preds = pca_model.predict(X_test_pca)

pca_scores = {
    "model": "Logistic Regression + PCA",
    "accuracy": accuracy_score(y_test, pca_preds),
    "precision": precision_score(y_test, pca_preds, zero_division=0),
    "recall": recall_score(y_test, pca_preds, zero_division=0),
    "f1": f1_score(y_test, pca_preds, zero_division=0)
}

pca_scores
Output preview

Jika skor turun sedikit tetapi visualisasi jauh lebih mudah dibaca, PCA tetap bisa berguna untuk eksplorasi.

lda

LDA Transformation

LDA memakai label untuk mencari proyeksi yang memisahkan kelas. Untuk binary classification, LDA menghasilkan satu komponen.

Python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

lda = LinearDiscriminantAnalysis(n_components=1)
X_train_lda = lda.fit_transform(X_train_scaled, y_train)
X_test_lda = lda.transform(X_test_scaled)

print("LDA train shape:", X_train_lda.shape)

plt.figure(figsize=(8, 4))

for class_id in np.unique(y_train):
    plt.hist(
        X_train_lda[y_train == class_id, 0],
        bins=20,
        alpha=0.6,
        label=str(target_encoder.inverse_transform([class_id])[0])
    )

plt.title("LDA Projection - Training Data")
plt.xlabel("Linear Discriminant 1")
plt.ylabel("Frequency")
plt.legend()
plt.tight_layout()
plt.show()
Output preview

Jika histogram antar kelas semakin terpisah, LDA menemukan proyeksi yang informatif untuk klasifikasi.

lda classification

Classification After LDA

Kita pakai Logistic Regression lagi agar perbandingan baseline, PCA, dan LDA tetap adil.

Python
lda_model = LogisticRegression(max_iter=1000, random_state=42)
lda_model.fit(X_train_lda, y_train)

lda_preds = lda_model.predict(X_test_lda)

lda_scores = {
    "model": "Logistic Regression + LDA",
    "accuracy": accuracy_score(y_test, lda_preds),
    "precision": precision_score(y_test, lda_preds, zero_division=0),
    "recall": recall_score(y_test, lda_preds, zero_division=0),
    "f1": f1_score(y_test, lda_preds, zero_division=0)
}

lda_scores
Output preview

Karena LDA supervised, performanya bisa sangat baik jika kelas memang terpisah pada kombinasi linear fitur.

comparison

Compare Results

Sekarang semua jalur eksperimen dibaca di satu tabel dan satu plot.

Python
comparison_df = pd.DataFrame([
    baseline_scores,
    pca_scores,
    lda_scores
]).sort_values(by="f1", ascending=False)

comparison_df

comparison_df.set_index("model")[["accuracy", "precision", "recall", "f1"]].plot(
    kind="bar",
    figsize=(10, 5)
)

plt.title("Model Performance Comparison")
plt.ylabel("Score")
plt.ylim(0, 1)
plt.xticks(rotation=30, ha="right")
plt.tight_layout()
plt.show()
Output preview

Bandingkan metrik secara utuh. Pada konteks medis, recall sering perlu dibaca serius, tetapi keputusan metrik tetap bergantung tujuan eksperimen.

confusion matrix

Confusion Matrix Model Terbaik

Confusion matrix memperjelas jumlah prediksi benar dan salah pada tiap kelas.

Python
best_row = comparison_df.iloc[0]
best_model_name = best_row["model"]

if best_model_name == "Baseline Logistic Regression":
    best_preds = baseline_preds
elif best_model_name == "Logistic Regression + PCA":
    best_preds = pca_preds
else:
    best_preds = lda_preds

cm = confusion_matrix(y_test, best_preds)

fig, ax = plt.subplots(figsize=(6, 5))
ax.imshow(cm)

ax.set_title(f"Confusion Matrix - {best_model_name}")
ax.set_xlabel("Predicted Label")
ax.set_ylabel("True Label")

ax.set_xticks(range(len(target_encoder.classes_)))
ax.set_yticks(range(len(target_encoder.classes_)))
ax.set_xticklabels(target_encoder.classes_)
ax.set_yticklabels(target_encoder.classes_)

for i in range(cm.shape[0]):
    for j in range(cm.shape[1]):
        ax.text(j, i, cm[i, j], ha="center", va="center")

plt.tight_layout()
plt.show()
Output preview

Diagonal utama adalah prediksi benar. Kesalahan di luar diagonal harus dilihat dengan hati-hati karena konteks dataset medis.

Interpretasi

Insight akhir dan batasan eksperimen.

  • PCA tidak melihat label dan fokus mencari variasi terbesar, sehingga bagus untuk eksplorasi struktur data.
  • LDA memakai label dan fokus mencari proyeksi yang memisahkan kelas, sehingga sering menarik untuk klasifikasi.
  • Performa dapat berubah karena dataset, preprocessing, model, dan train-test split.
  • Dalam konteks medis, model ML tidak boleh dianggap sebagai diagnosis final. Tujuan tutorial ini adalah memahami workflow eksperimen.
Download

File pendukung studi kasus.

Gunakan notebook untuk belajar bertahap, atau pakai source code jika ingin langsung menjalankan eksperimen di environment sendiri.