2D data clustering: Python simple Nonlinear SVM classification code

Now the classification was performed by nonlinear Support Vector Machine (SVM) – using Gaussian Kernel.
Goal here is to replace previous Linear SVM with Gaussian Kernel, then again compare the results with the one obtained from python scipy plugin – Sklern.

#%%
import numpy as np
from scipy.linalg import norm
import cvxopt
import cvxopt.solvers
from pylab import *

N = 500        # Data Amount
C = 20         # Slack variable
GAMMA = 5.0    # Parameter for Gaussian Kernel


# Gaussian Kernel
def gaussian_kernel(x, y):
    return np.exp(-norm(x-y)**2 / (2 * (GAMMA ** 2)))

# Calculate Descriminalt using only Support Vectors (since a[i] = 0 for non-support vectors)
def f(x, a, t, X, b):
    sum = 0.0
    for n in range(N):
        sum += a[n] * t[n] * gaussian_kernel(x, X[n])
    return sum + b


cls1 = []
cls2 = []

mean1 = [1,  4]
mean2 = [1, -3]
mean3 = [3, -2]
mean4 = [-2, 3]
cov = [[1.0,0.1], [0.5, 0.8]]

cls1.extend(np.random.multivariate_normal(mean1, cov, int(N/4)))
cls1.extend(np.random.multivariate_normal(mean3, cov, int(N/4)))
cls2.extend(np.random.multivariate_normal(mean2, cov, int(N/4)))
cls2.extend(np.random.multivariate_normal(mean4, cov, int(N/4)))

# Create Training Data Matrix X
X = vstack((cls1, cls2))

# Create Lavel t
t = np.array([1.0] * int(N/2) + [-1.0] * int(N/2))


# Calculate Lagrange Multiplier by using Quadratic Programming
K = np.zeros((N, N))
for i in range(N):
    for j in range(N):
        K[i, j] = t[i] * t[j] * gaussian_kernel(X[i], X[j])

Q = cvxopt.matrix(K)
p = cvxopt.matrix(-np.ones(N))
temp1 = np.diag([-1.0]*N)
temp2 = np.identity(N)
G = cvxopt.matrix(np.vstack((temp1, temp2)))
temp1 = np.zeros(N)
temp2 = np.ones(N) * C
h = cvxopt.matrix(np.hstack((temp1, temp2)))
A = cvxopt.matrix(t, (1,N))
b = cvxopt.matrix(0.0)
sol = cvxopt.solvers.qp(Q, p, G, h, A, b)
a = array(sol['x']).reshape(N)
#  print a

# Collect Support Vectors (Indexing)
S = []
M = []
for n in range(len(a)):
    if a[n] < 1e-5: continue
    S.append(n)
    if a[n] < 1e-5: continue
    if a[n] < C:
        M.append(n)


# Calculate bias parameter
sum = 0
for n in M:
    temp = 0
    for m in S:
        temp += a[m] * t[m] * gaussian_kernel(X[n], X[m])
    sum += (t[n] - temp)
b = sum / len(M)



# Show Training Data
plt.figure(figsize=(8, 6))
plt.rcParams.update({'font.size': 18})
x1, x2 = np.array(cls1).transpose()
plot(x1, x2, 'rx')

x1, x2 = np.array(cls2).transpose()
plot(x1, x2, 'bx')

# Show Support Vectors
for n in S:
    scatter(X[n,0], X[n,1], s=80, c='c', marker='o')

# Show Discriminant Boundary
X1, X2 = meshgrid(linspace(-6.3,6.3,100), linspace(-6.3,6.3,100))
w, h = X1.shape
X1.resize(X1.size)
X2.resize(X2.size)
Z = array([f(array([x1, x2]), a, t, X, b) for (x1, x2) in zip(X1, X2)])
X1.resize((w, h))
X2.resize((w, h))
Z.resize((w, h))
CS = contour(X1, X2, Z, [0.0], colors='g', linewidths=2, origin='lower')


# -----------------------------------------------------------------------------------------------------------
# Try same thing with sklearn!
from sklearn import svm

clf = svm.SVC(kernel='rbf', C=40, gamma=5)
X_train = np.vstack((cls1, cls2))
t = [-1] * int(N/2) + [1] * int(N/2)

clf.fit(X_train, t)

X1, X2 = meshgrid(linspace(-6,6,100), linspace(-6,6,100))
ZZ = clf.decision_function(np.c_[X1.ravel(), X2.ravel()])

ZZ.resize(X1.shape)
CS = contour(X1, X2, ZZ, [0.0], colors='k', linewidths=2, origin='lower')


xlim(-6, 7)
ylim(-7, 7)

Green line shows the separation (counter line) from own code extended from the Linear SVM.
Black line shows the separation counter line from sklern – rbf that supposed to be closed to the Gaussian kernel.

Leave a Reply

Your email address will not be published. Required fields are marked *