Ich habe einen Datensatz mit zwei überlappenden Klassen, sieben Punkte in jeder Klasse, Punkte liegen im zweidimensionalen Raum. In R rufe ich svm
das e1071
Paket auf, um eine separate Hyperebene für diese Klassen zu erstellen. Ich benutze den folgenden Befehl:
svm(x, y, scale = FALSE, type = 'C-classification', kernel = 'linear', cost = 50000)
Wo x
enthält meine Datenpunkte und y
enthält ihre Beschriftungen. Der Befehl gibt ein svm-Objekt zurück, mit dem ich die Parameter (normaler Vektor) und (Achsenabschnitt) der trennenden Hyperebene berechne .
Abbildung (a) unten zeigt meine Punkte und die vom svm
Befehl zurückgegebene Hyperebene (nennen wir diese Hyperebene die optimale). Der blaue Punkt mit dem Symbol O zeigt den Raum Ursprung zeigen gepunktete Linien Rand, eingekreist sind Punkte , die nicht Null haben (slack Variablen).
Abbildung (b) zeigt eine weitere Hyperebene, bei der es sich um eine parallele Translation der optimalen um 5 handelt (b_new = b_optimal - 5). Es ist nicht schwer zu erkennen, dass für diese Hyperebene die Zielfunktion (die durch die C-Klassifikation svm minimiert wird) einen niedrigeren Wert hat als für die in Abbildung (1) gezeigte optimale Hyperebene. ein). Sieht es so aus, als gäbe es ein Problem mit dieser Funktion? Oder habe ich irgendwo einen Fehler gemacht?
svm
Unten ist der R-Code, den ich in diesem Experiment verwendet habe.
library(e1071)
get_obj_func_info <- function(w, b, c_par, x, y) {
xi <- rep(0, nrow(x))
for (i in 1:nrow(x)) {
xi[i] <- 1 - as.numeric(as.character(y[i]))*(sum(w*x[i,]) + b)
if (xi[i] < 0) xi[i] <- 0
}
return(list(obj_func_value = 0.5*sqrt(sum(w * w)) + c_par*sum(xi),
sum_xi = sum(xi), xi = xi))
}
x <- structure(c(41.8226593092589, 56.1773406907411, 63.3546813814822,
66.4912298720281, 72.1002963174962, 77.649309469458, 29.0963054665561,
38.6260575252066, 44.2351239706747, 53.7648760293253, 31.5087701279719,
24.3314294372308, 21.9189647758150, 68.9036945334439, 26.2543850639859,
43.7456149360141, 52.4912298720281, 20.6453186185178, 45.313889181287,
29.7830021158501, 33.0396571934088, 17.9008386892901, 42.5694092520593,
27.4305907479407, 49.3546813814822, 40.6090664454681, 24.2940422573947,
36.9603428065912), .Dim = c(14L, 2L))
y <- structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L,
1L), .Label = c("-1", "1"), class = "factor")
a <- svm(x, y, scale = FALSE, type = 'C-classification', kernel = 'linear', cost = 50000)
w <- t(a$coefs) %*% a$SV;
b <- -a$rho;
obj_func_str1 <- get_obj_func_info(w, b, 50000, x, y)
obj_func_str2 <- get_obj_func_info(w, b - 5, 50000, x, y)
Antworten:
In den libsvm-FAQ wird erwähnt, dass die im Algorithmus verwendeten Bezeichnungen von Ihren abweichen können. Dies kehrt manchmal das Vorzeichen der "Coefs" des Modells um.
Siehe die Frage "Warum werden das Vorzeichen vorhergesagter Bezeichnungen und Entscheidungswerte manchmal umgekehrt?" hier .
quelle
Ich habe das gleiche Problem mit LIBSVM in MATLAB ausgeführt. Um es zu testen, habe ich einen sehr einfachen, linear trennbaren 2D-Datensatz erstellt, der zufällig entlang einer Achse nach -100 verschoben wurde. Das Trainieren einer linearen SVM mit LIBSVM ergab eine Hyperebene, deren Achsenabschnitt immer noch bei Null lag (und die Fehlerrate betrug natürlich 50%). Das Standardisieren der Daten (Abziehen des Mittelwerts) hat geholfen, obwohl das resultierende SVM immer noch nicht perfekt funktioniert hat ... verwirrend. Es scheint, als würde LIBSVM die Hyperebene nur um die Achse drehen, ohne sie zu verschieben. Vielleicht sollten Sie versuchen, den Mittelwert von Ihren Daten zu subtrahieren, aber es scheint merkwürdig, dass sich LIBSVM so verhält. Vielleicht fehlt uns etwas.
Für das, was es wert ist, hat die eingebaute MATLAB-Funktion
svmtrain
einen Klassifikator mit 100% Genauigkeit ohne Standardisierung erzeugt.quelle