2014-11-16 13 views
12

Mi piacerebbe implementare il mio kernel gaussiano in Python, solo per l'esercizio. Sto usando: sklearn.svm.SVC(kernel=my_kernel) ma davvero non capisco cosa sta succedendo.Come utilizzare un kernel SVM personalizzato?

Mi aspetto che la funzione my_kernel venga chiamata con le colonne della matrice X come parametri, invece l'ho chiamata con X, X come argomenti. Guardando gli esempi le cose non sono più chiare.

Cosa mi manca?

Questo è il mio codice:

''' 
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) 

risposta

6

Per ragioni di efficienza, SVC presuppone che il kernel è una funzione che accetta two matrices of samples, X e Y (userà due più identici solo durante l'allenamento) e si dovrebbe tornare una matriceG dove:

G_ij = K(X_i, Y_j) 

e K è la funzione del kernel "a livello di punti".

Quindi, o implementano un kernel gaussiano che funziona in modo così generico, o di aggiungere una funzione di "proxy", come:

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 

e utilizzarlo come:

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

Scusami ma non capisco, probabilmente perché sono un principiante in ML. Non dovrebbe essere sufficiente restituire una matrice quadrata con n = n_rows (X), gli elementi sono tutte le combinazioni tra X [:, 0] e X [:, 1]? –

+0

Come ho detto, non sarà sempre chiamato con due X come argomenti, quindi no. Inoltre i tuoi dati sono multidimensionali, quindi X [:, 0] è solo la prima dimensione di ogni vettore che non ha nulla da fare qui. – lejlot

+0

E cosa dovrei restituire? –

11

Dopo aver letto la risposta sopra, e alcune altre domande e siti (1, 2, 3, 4, 5), l'ho messo insieme per un kernel gaussiano in svm.SVC().

Chiama svm.SVC() con kernel=precomputed.

Quindi calcolare una Matrice Grammatica a.k.a. Matrice del Kernel (spesso abbreviata come K).

Quindi utilizzare questa matrice Gram come primo argomento (, ad es. X) per svm.SVC().fit():

comincio con il following code:

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

che chiama sklearn.svm.SVC() in svmTrain(), e poi 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) 

il calcolo Gram Matrix - usato come parametro per sklearn.svm.SVC().fit() - è fatto in 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 

che utilizza gaussianKernel() per ottenere un kernel radiale funzione di base tra X1 e X2 (a measure of similarity based on a gaussian distribution centered on x1 with 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 

Poi, una volta che il modello è allenato con questo kernel personalizzato, si prevede con "the [custom] kernel between the test data and the training data":

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

Insomma, per usare un costume SVM kernel gaussiano, è possibile utilizzare questo frammento:

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)) 
+0

Ottima risposta, alzerei questo due volte se possibile. – Archie

+0

dovrebbe essere accettato come risposta – dada

Problemi correlati