¿Cómo usar un kernel SVM personalizado?

Me gustaría implementar mi propio kernel gaussiano en Python, solo para hacer ejercicio. Estoy usando: sklearn.svm.SVC(kernel=my_kernel) pero realmente no entiendo lo que está pasando.

Espero que la función my_kernel sea llamada con las columnas de la matriz X como parámetros, en lugar de eso, la llamé con X , X como argumentos. Mirando los ejemplos las cosas no son más claras.

¿Qué me estoy perdiendo?

Este es mi código:

 ''' Created on 15 Nov 2014 @author: Luigi ''' import scipy.io import numpy as np from sklearn import svm import matplotlib.pyplot as plt def svm_class(fileName): data = scipy.io.loadmat(fileName) X = data['X'] y = data['y'] f = svm.SVC(kernel = 'rbf', gamma=50, C=1.0) f.fit(X,y.flatten()) plotData(np.hstack((X,y)), X, f) return def plotData(arr, X, f): ax = plt.subplot(111) ax.scatter(arr[arr[:,2]==0][:,0], arr[arr[:,2]==0][:,1], c='r', marker='o', label='Zero') ax.scatter(arr[arr[:,2]==1][:,0], arr[arr[:,2]==1][:,1], c='g', marker='+', label='One') h = .02 # step size in the mesh # create a mesh to plot in 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, h), np.arange(y_min, y_max, h)) # Plot the decision boundary. For that, we will assign a color to each # point in the mesh [x_min, m_max]x[y_min, y_max]. Z = f.predict(np.c_[xx.ravel(), yy.ravel()]) # Put the result into a color plot Z = Z.reshape(xx.shape) plt.contour(xx, yy, Z) plt.xlim(np.min(arr[:,0]), np.max(arr[:,0])) plt.ylim(np.min(arr[:,1]), np.max(arr[:,1])) plt.show() return def gaussian_kernel(x1,x2): sigma = 0.5 return np.exp(-np.sum((x1-x2)**2)/(2*sigma**2)) if __name__ == '__main__': fileName = 'ex6data2.mat' svm_class(fileName) 

Después de leer la respuesta anterior y algunas otras preguntas y sitios ( 1 , 2 , 3 , 4 , 5 ), puse esto juntos para un kernel gaussiano en svm.SVC() .

Llame a svm.SVC() con kernel=precomputed .

Luego, calcule una Matriz de Gramo, también conocida como Matriz de Kernel (a menudo abreviada como K).

Luego use esta Matriz de Gram como el primer argumento ( es decir, X) para svm.SVC().fit() :

Comienzo con el siguiente código :

 C=0.1 model = svmTrain(X, y, C, "gaussian") 

que llama a sklearn.svm.SVC() en svmTrain() , y luego a sklearn.svm.SVC().fit() :

 from sklearn import svm if kernelFunction == "gaussian": clf = svm.SVC(C = C, kernel="precomputed") return clf.fit(gaussianKernelGramMatrix(X,X), y) 

El cálculo de la Matriz de Gram (utilizado como parámetro para sklearn.svm.SVC().fit() se realiza en gaussianKernelGramMatrix() :

 import numpy as np def gaussianKernelGramMatrix(X1, X2, K_function=gaussianKernel): """(Pre)calculates Gram Matrix K""" gram_matrix = np.zeros((X1.shape[0], X2.shape[0])) for i, x1 in enumerate(X1): for j, x2 in enumerate(X2): gram_matrix[i, j] = K_function(x1, x2) return gram_matrix 

que utiliza gaussianKernel() para obtener una función de base radial del núcleo entre x1 y x2 ( una medida de similitud basada en una distribución gaussiana centrada en x1 con sigma = 0.1 ):

 def gaussianKernel(x1, x2, sigma=0.1): # Ensure that x1 and x2 are column vectors x1 = x1.flatten() x2 = x2.flatten() sim = np.exp(- np.sum( np.power((x1 - x2),2) ) / float( 2*(sigma**2) ) ) return sim 

Luego, una vez que el modelo se entrena con este kernel personalizado, predecimos con “el kernel [personalizado] entre los datos de prueba y los datos de entrenamiento” :

 predictions = model.predict( gaussianKernelGramMatrix(Xval, X) ) 

En resumen, para usar un kernel gaussiano SVM personalizado, puede usar este fragmento de código:

 import numpy as np from sklearn import svm def gaussianKernelGramMatrixFull(X1, X2, sigma=0.1): """(Pre)calculates Gram Matrix K""" gram_matrix = np.zeros((X1.shape[0], X2.shape[0])) for i, x1 in enumerate(X1): for j, x2 in enumerate(X2): x1 = x1.flatten() x2 = x2.flatten() gram_matrix[i, j] = np.exp(- np.sum( np.power((x1 - x2),2) ) / float( 2*(sigma**2) ) ) return gram_matrix X=... y=... Xval=... C=0.1 clf = svm.SVC(C = C, kernel="precomputed") model = clf.fit( gaussianKernelGramMatrixFull(X,X), y ) p = model.predict( gaussianKernelGramMatrixFull(Xval, X) ) 

Por razones de eficiencia, SVC asume que su núcleo es una función que acepta dos matrices de muestras , X e Y (utilizará dos idénticas solo durante el entrenamiento) y debe devolver una matriz G donde:

 G_ij = K(X_i, Y_j) 

y K es su función de kernel de “nivel de punto”.

Entonces, o bien implementa un kernel gaussiano que funcione de una manera tan genérica, o agrega una función “proxy” como:

 def proxy_kernel(X,Y,K): gram_matrix = np.zeros((X.shape[0], Y.shape[0])) for i, x in enumerate(X): for j, y in enumerate(Y): gram_matrix[i, j] = K(x, y) return gram_matrix 

y utilízalo como:

 from functools import partial correct_gaussian_kernel = partial(proxy_kernel, K=gaussian_kernel)