Przejdź do głównej zawartości

svm

czym są Support Vector Machines (SVM)? ⭐

  • SVM to potężny algorytm uczenia maszynowego używany do klasyfikacji i regresji.
  • Znajduje optymalną hiperpłaszczyznę (lub krzywą) dzielącą dane na klasy.
  • Działa poprzez maksymalizację marginesu (odległości) między klasami.
  • Może obsługiwać dane liniowo i nieliniowo separowalne dzięki kernel trick.
  • Jest szczególnie skuteczny w przestrzeniach wielowymiarowych.

jak działają SVM? ⭐

Klasyfikacja liniowa:

  1. Znajdowanie hiperpłaszczyzny: SVM znajduje linię (2D) lub płaszczyznę (3D+) dzielącą dane.
  2. Maksymalizacja marginesu: Wybiera hiperpłaszczyznę z największym marginesem.
  3. Support vectors: Używa tylko najbliższych punktów (support vectors) do definiowania granicy.

Kernel trick:

  • Linear kernel: Dla danych liniowo separowalnych.
  • RBF kernel: Dla danych nieliniowo separowalnych.
  • Polynomial kernel: Dla złożonych wzorców nieliniowych.

przykładowy kod (SVM)

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC, SVR
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns

# Generowanie danych
np.random.seed(42)
n_samples = 300

# Generowanie dwóch klas
class_0 = np.random.multivariate_normal([0, 0], [[1, 0], [0, 1]], n_samples//2)
class_1 = np.random.multivariate_normal([3, 3], [[1, 0], [0, 1]], n_samples//2)

# Łączenie danych
X = np.vstack([class_0, class_1])
y = np.hstack([np.zeros(n_samples//2), np.ones(n_samples//2)])

# Tworzenie DataFrame
data = pd.DataFrame(X, columns=['feature1', 'feature2'])
data['target'] = y

print("Rozkład klas:")
print(data['target'].value_counts())

# Wizualizacja danych
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.scatter(data[data['target'] == 0]['feature1'],
data[data['target'] == 0]['feature2'],
alpha=0.6, label='Klasa 0')
plt.scatter(data[data['target'] == 1]['feature1'],
data[data['target'] == 1]['feature2'],
alpha=0.6, label='Klasa 1')
plt.title('Oryginalne dane')
plt.legend()
plt.grid(True, alpha=0.3)

1. podstawowy SVM z różnymi kernelami

# Podział danych
X = data[['feature1', 'feature2']]
y = data['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Skalowanie danych (ważne dla SVM)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Różne kernel'e
kernels = ['linear', 'rbf', 'poly']
svm_models = {}

for kernel in kernels:
print(f"\nTrenowanie SVM z kernel '{kernel}'...")

# Tworzenie modelu
if kernel == 'poly':
svm = SVC(kernel=kernel, degree=3, random_state=42)
else:
svm = SVC(kernel=kernel, random_state=42)

# Trenowanie
svm.fit(X_train_scaled, y_train)

# Przewidywanie
y_pred = svm.predict(X_test_scaled)

# Ocena
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.3f}")

svm_models[kernel] = {
'model': svm,
'accuracy': accuracy,
'predictions': y_pred
}

2. wizualizacja granic decyzyjnych

def plot_decision_boundary(model, X, y, title):
"""Funkcja do wizualizacji granic decyzyjnych"""
# Tworzenie siatki punktów
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))

# Przewidywanie dla każdego punktu siatki
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# Wizualizacja
plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8)
plt.title(title)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.grid(True, alpha=0.3)

# Wizualizacja granic decyzyjnych
for i, (kernel, model_info) in enumerate(svm_models.items()):
plt.subplot(1, 3, i+2)
plot_decision_boundary(model_info['model'], X_train_scaled, y_train, f'SVM - {kernel.upper()}')

plt.tight_layout()
plt.show()

3. tuning hiperparametrów SVM

from sklearn.model_selection import GridSearchCV

# Definicja przestrzeni parametrów
param_grid = {
'C': [0.1, 1, 10, 100],
'gamma': ['scale', 'auto', 0.1, 0.01],
'kernel': ['rbf', 'linear']
}

# Grid search
grid_search = GridSearchCV(
SVC(random_state=42),
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1
)

grid_search.fit(X_train_scaled, y_train)

print(f"Najlepsze parametry: {grid_search.best_params_}")
print(f"Najlepszy score: {grid_search.best_score_:.3f}")

# Ocena najlepszego modelu
best_svm = grid_search.best_estimator_
y_pred_best = best_svm.predict(X_test_scaled)
print(f"Test accuracy (best model): {accuracy_score(y_test, y_pred_best):.3f}")

# Macierz pomyłek dla najlepszego modelu
cm = confusion_matrix(y_test, y_pred_best)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix - Best SVM')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.show()

4. SVM dla danych nieliniowo separowalnych

# Generowanie danych nieliniowo separowalnych (XOR-like)
np.random.seed(42)
n_samples = 400

# Klasa 0: dwa skupiska
class_0_1 = np.random.multivariate_normal([0, 0], [[0.5, 0], [0, 0.5]], n_samples//4)
class_0_2 = np.random.multivariate_normal([3, 3], [[0.5, 0], [0, 0.5]], n_samples//4)

# Klasa 1: dwa inne skupiska
class_1_1 = np.random.multivariate_normal([0, 3], [[0.5, 0], [0, 0.5]], n_samples//4)
class_1_2 = np.random.multivariate_normal([3, 0], [[0.5, 0], [0, 0.5]], n_samples//4)

# Łączenie danych
X_nonlinear = np.vstack([class_0_1, class_0_2, class_1_1, class_1_2])
y_nonlinear = np.hstack([np.zeros(n_samples//2), np.ones(n_samples//2)])

# Podział danych
X_train_nl, X_test_nl, y_train_nl, y_test_nl = train_test_split(
X_nonlinear, y_nonlinear, test_size=0.2, random_state=42, stratify=y_nonlinear
)

# Skalowanie
scaler_nl = StandardScaler()
X_train_nl_scaled = scaler_nl.fit_transform(X_train_nl)
X_test_nl_scaled = scaler_nl.transform(X_test_nl)

# Porównanie kernel'i dla danych nieliniowych
kernels_nl = ['linear', 'rbf', 'poly']
results_nl = {}

for kernel in kernels_nl:
if kernel == 'poly':
svm_nl = SVC(kernel=kernel, degree=3, random_state=42)
else:
svm_nl = SVC(kernel=kernel, random_state=42)

svm_nl.fit(X_train_nl_scaled, y_train_nl)
y_pred_nl = svm_nl.predict(X_test_nl_scaled)

accuracy_nl = accuracy_score(y_test_nl, y_pred_nl)
results_nl[kernel] = {
'model': svm_nl,
'accuracy': accuracy_nl,
'predictions': y_pred_nl
}

print(f"SVM {kernel}: Accuracy = {accuracy_nl:.3f}")

# Wizualizacja dla danych nieliniowych
plt.figure(figsize=(15, 4))

plt.subplot(1, 4, 1)
plt.scatter(X_nonlinear[y_nonlinear == 0][:, 0], X_nonlinear[y_nonlinear == 0][:, 1],
alpha=0.6, label='Klasa 0')
plt.scatter(X_nonlinear[y_nonlinear == 1][:, 0], X_nonlinear[y_nonlinear == 1][:, 1],
alpha=0.6, label='Klasa 1')
plt.title('Dane nieliniowo separowalne')
plt.legend()
plt.grid(True, alpha=0.3)

for i, (kernel, result) in enumerate(results_nl.items()):
plt.subplot(1, 4, i+2)
plot_decision_boundary(result['model'], X_train_nl_scaled, y_train_nl, f'SVM {kernel.upper()}')

plt.tight_layout()
plt.show()

5. SVM dla regresji (SVR)

# Generowanie danych dla regresji
np.random.seed(42)
X_reg = np.sort(5 * np.random.rand(100, 1), axis=0)
y_reg = np.sin(X_reg).ravel() + np.random.normal(0, 0.1, X_reg.shape[0])

# Podział danych
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(
X_reg, y_reg, test_size=0.2, random_state=42
)

# Różne kernel'e dla regresji
kernels_reg = ['linear', 'rbf', 'poly']
svr_models = {}

for kernel in kernels_reg:
if kernel == 'poly':
svr = SVR(kernel=kernel, degree=3)
else:
svr = SVR(kernel=kernel)

svr.fit(X_train_reg, y_train_reg)
y_pred_reg = svr.predict(X_test_reg)

# Ocena (R² score)
from sklearn.metrics import r2_score
r2 = r2_score(y_test_reg, y_pred_reg)

svr_models[kernel] = {
'model': svr,
'r2': r2,
'predictions': y_pred_reg
}

print(f"SVR {kernel}: R² = {r2:.3f}")

# Wizualizacja regresji
plt.figure(figsize=(15, 4))

plt.subplot(1, 4, 1)
plt.scatter(X_reg, y_reg, alpha=0.6, label='Dane')
plt.title('Dane regresyjne')
plt.legend()
plt.grid(True, alpha=0.3)

for i, (kernel, result) in enumerate(svr_models.items()):
plt.subplot(1, 4, i+2)
plt.scatter(X_test_reg, y_test_reg, alpha=0.6, label='Rzeczywiste')
plt.scatter(X_test_reg, result['predictions'], alpha=0.8, label='Przewidywane')
plt.title(f'SVR {kernel.upper()} (R² = {result["r2"]:.3f})')
plt.legend()
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

praktyczne ćwiczenia

  1. Eksperymentuj z kernelami - przetestuj różne kernel'e na swoich danych.

  2. Tuning parametrów - znajdź optymalne wartości C i gamma.

  3. Feature scaling - porównaj wyniki z i bez skalowania.

  4. Support vectors - przeanalizuj, które punkty są support vectors.

  5. Real-world data - zastosuj SVM do rzeczywistych problemów.

dobre praktyki

  • Skalowanie: Zawsze skaluj dane przed użyciem SVM.
  • Wybór kernel'a: Linear dla danych liniowych, RBF dla nieliniowych.
  • Parametr C: Kontroluje trade-off między bias a variance.
  • Parametr gamma: Kontroluje wpływ pojedynczego punktu treningowego.

wady i zalety

Zalety:

  • Skuteczny w przestrzeniach wielowymiarowych
  • Elastyczny dzięki różnym kernelom
  • Dobrze radzi sobie z overfitting
  • Dostarcza support vectors

Wady:

  • Wolny dla dużych zbiorów danych
  • Wrażliwy na skalowanie
  • Trudny do interpretacji
  • Wymaga tuning parametrów

polecane źródła