# Source: content/notes/ml/svm-and-kernels.md
# Independent CPU example; use the curriculum environment.
# See /notes/ml/#example-environment or /notes/deep-learning/#example-environment.

import numpy as np
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score
from sklearn.kernel_approximation import RBFSampler
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = make_moons(n_samples=360, noise=0.18, random_state=7)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, stratify=y, random_state=11)
grid = {"svc__C": [0.1, 1.0, 10.0], "svc__gamma": [0.1, 1.0, 10.0]}
search = GridSearchCV(make_pipeline(StandardScaler(), SVC(kernel="rbf")),
                      grid, cv=3, scoring="roc_auc", n_jobs=1)
search.fit(X_train, y_train)
exact_accuracy = accuracy_score(y_test, search.predict(X_test))
approx = make_pipeline(StandardScaler(),
    RBFSampler(gamma=search.best_params_["svc__gamma"],
               n_components=256, random_state=3),
    LinearSVC(C=search.best_params_["svc__C"], dual=False,
              max_iter=5000, random_state=3))
approx.fit(X_train, y_train)
approx_accuracy = accuracy_score(y_test, approx.predict(X_test))
assert exact_accuracy > 0.85
assert approx_accuracy > 0.80
assert search.best_estimator_.named_steps["svc"].support_vectors_.shape[1] == 2
print("best", search.best_params_, "exact", exact_accuracy,
      "random features", approx_accuracy)
for params, mean, std in zip(search.cv_results_["params"],
        search.cv_results_["mean_test_score"], search.cv_results_["std_test_score"]):
    print("C/gamma response", params, "mean AUC", mean, "fold spread", std)
print("exact support vectors", search.best_estimator_.named_steps["svc"].n_support_.sum(),
      "approximation width", approx.named_steps["rbfsampler"].n_components)
