¿Cómo arreglar la tasa de falsos positivos de un SVM lineal?

Soy un novato en SVM y este es mi caso de uso: tengo una gran cantidad de datos no balanceados para ser clasificados en binario utilizando un SVM lineal. Necesito corregir la tasa de falsos positivos en ciertos valores y medir los falsos negativos correspondientes para cada valor. Estoy usando algo como el siguiente código que usa la implementación de scikit-learn svm:

# define training data X = [[0, 0], [1, 1]] y = [0, 1] # define and train the SVM clf = svm.LinearSVC(C=0.01, class_weight='auto') #auto for unbalanced distributions clf.fit(X, y) # compute false positives and false negatives predictions = [clf.predict(ex) for ex in X] false_positives = [(a, b) for (a, b) in zip(predictions,y) if a != b and b == 0] false_negatives = [(a, b) for (a, b) in zip(predictions,y) if a != b and b == 1] 

¿Hay una manera de jugar con un parámetro (o unos pocos parámetros) del clasificador de tal manera que una de las métricas de medición sea efectivamente arreglada?

El método de predicción para LinearSVC en sklearn se ve así

 def predict(self, X): """Predict class labels for samples in X. Parameters ---------- X : {array-like, sparse matrix}, shape = [n_samples, n_features] Samples. Returns ------- C : array, shape = [n_samples] Predicted class label per sample. """ scores = self.decision_function(X) if len(scores.shape) == 1: indices = (scores > 0).astype(np.int) else: indices = scores.argmax(axis=1) return self.classes_[indices] 

Así que además de lo que mbatchkarov sugirió que puede cambiar las decisiones tomadas por el clasificador (cualquier clasificador realmente) cambiando el límite en el que el clasificador dice que algo es de una clase u otra.

 from collections import Counter import numpy as np from sklearn.datasets import load_iris from sklearn.svm import LinearSVC data = load_iris() # remove a feature to make the problem harder # remove the third class for simplicity X = data.data[:100, 0:1] y = data.target[:100] # shuffle data indices = np.arange(y.shape[0]) np.random.shuffle(indices) X = X[indices, :] y = y[indices] decision_boundary = 0 print Counter((clf.decision_function(X[50:]) > decision_boundary).astype(np.int8)) Counter({1: 27, 0: 23}) decision_boundary = 0.5 print Counter((clf.decision_function(X[50:]) > decision_boundary).astype(np.int8)) Counter({0: 39, 1: 11}) 

Puede optimizar el límite de decisión para ser cualquier cosa dependiendo de sus necesidades.

El parámetro class_weights permite subir o bajar esta tasa de falsos positivos. Permítame usar un ejemplo cotidiano para ilustrar cómo funciona esto. Supongamos que usted es dueño de un club nocturno y opera bajo dos restricciones:

  1. Desea que ingresen al club tantas personas como sea posible (clientes que pagan)
  2. No quiere que ingresen personas menores de edad, ya que esto le traerá problemas con el estado

En un día promedio, (digamos) solo el 5% de las personas que intentan ingresar al club serán menores de edad. Te enfrentas a una elección: ser indulgente o ser estricto. Lo primero boostá sus ganancias hasta en un 5%, pero usted corre el riesgo de una demanda costosa. Esto último inevitablemente significará que a algunas personas que están justo por encima de la edad legal se les negará la entrada, lo que también le costará dinero. Desea ajustar el relative cost de la clemencia frente a la rigurosidad. Nota: no puede controlar directamente la cantidad de personas menores de edad que ingresan al club, pero puede controlar qué tan estrictos son sus gorilas.

Aquí hay un poco de Python que muestra lo que sucede a medida que cambia la importancia relativa.

 from collections import Counter import numpy as np from sklearn.datasets import load_iris from sklearn.svm import LinearSVC data = load_iris() # remove a feature to make the problem harder # remove the third class for simplicity X = data.data[:100, 0:1] y = data.target[:100] # shuffle data indices = np.arange(y.shape[0]) np.random.shuffle(indices) X = X[indices, :] y = y[indices] for i in range(1, 20): clf = LinearSVC(class_weight={0: 1, 1: i}) clf = clf.fit(X[:50, :], y[:50]) print i, Counter(clf.predict(X[50:])) # print clf.decision_function(X[50:]) 

Que salidas

 1 Counter({1: 22, 0: 28}) 2 Counter({1: 31, 0: 19}) 3 Counter({1: 39, 0: 11}) 4 Counter({1: 43, 0: 7}) 5 Counter({1: 43, 0: 7}) 6 Counter({1: 44, 0: 6}) 7 Counter({1: 44, 0: 6}) 8 Counter({1: 44, 0: 6}) 9 Counter({1: 47, 0: 3}) 10 Counter({1: 47, 0: 3}) 11 Counter({1: 47, 0: 3}) 12 Counter({1: 47, 0: 3}) 13 Counter({1: 47, 0: 3}) 14 Counter({1: 47, 0: 3}) 15 Counter({1: 47, 0: 3}) 16 Counter({1: 47, 0: 3}) 17 Counter({1: 48, 0: 2}) 18 Counter({1: 48, 0: 2}) 19 Counter({1: 48, 0: 2}) 

Observe cómo el número de puntos de datos clasificados como disminuciones de 0 es el peso relativo de los aumentos de clase 1 . Suponiendo que tiene los recursos computacionales y el tiempo para entrenar y evaluar 10 clasificadores, puede trazar la precisión y el recuerdo de cada uno y obtener una cifra como la que se muestra a continuación (robada descaradamente de Internet). Luego puede usar eso para decidir cuál es el valor correcto de class_weights para su caso de uso.

Compensación de recuerdo de precisión