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:
- Znajdowanie hiperpłaszczyzny: SVM znajduje linię (2D) lub płaszczyznę (3D+) dzielącą dane.
- Maksymalizacja marginesu: Wybiera hiperpłaszczyznę z największym marginesem.
- 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
-
Eksperymentuj z kernelami - przetestuj różne kernel'e na swoich danych.
-
Tuning parametrów - znajdź optymalne wartości C i gamma.
-
Feature scaling - porównaj wyniki z i bez skalowania.
-
Support vectors - przeanalizuj, które punkty są support vectors.
-
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
- SVM Tutorial – scikit-learn
- SVM Guide – Towards Data Science
- SVM – StatQuest (YouTube)
- SVM Tutorial – Machine Learning Mastery