У меня есть набор данных с двумя перекрывающимися классами, семь точек в каждом классе, точки находятся в двухмерном пространстве. В R, и я бегу svm
из e1071
пакета, чтобы построить разделяющую гиперплоскость для этих классов. Я использую следующую команду:
svm(x, y, scale = FALSE, type = 'C-classification', kernel = 'linear', cost = 50000)
где x
содержит мои точки данных и y
содержит их метки. Команда возвращает svm-объект, который я использую для вычисления параметров (нормальный вектор) и (перехват) разделяющей гиперплоскости.б
На рисунке (а) ниже показаны мои точки и гиперплоскость, возвращаемая svm
командой (назовем эту гиперплоскость оптимальной). Синяя точка с символом O показывает начало пространства, пунктирные линии показывают поле, обведенные кружками точки, которые имеют ненулевое значение (переменные провисания).
На рисунке (б) показана другая гиперплоскость, которая представляет собой параллельную трансляцию оптимальной на 5 (b_new = b_optimal - 5). Нетрудно видеть, что для этой гиперплоскости целевая функция (которая минимизируется с помощью C-классификации svm) будет иметь меньшее значение, чем для оптимальной гиперплоскости, показанной на рисунке ( а). Так выглядит ли проблема с этой функцией? Или я где-то ошибся?
svm
Ниже приведен код R, который я использовал в этом эксперименте.
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)
Ответы:
В FAQ по libsvm упоминается, что метки, используемые «внутри» алгоритма, могут отличаться от ваших. Иногда это поменяет знак «коэф» модели.
Например, если у вас были метки , то первая метка в , которая равна «-1», будет классифицироваться как для запуска libsvm и, очевидно, ваше «+1» будет классифицироваться как внутри алгоритма.y + 1 - 1Y= [ - 1 , + 1 , + 1 , - 1 , . , , ] y +1 −1
И помните, что значения в возвращенной модели svm действительно являются и поэтому ваш вычисленный вектор будет из-за обращения знака . w yαnyn w y
Смотрите вопрос "Почему знак предсказанных меток и значений решений иногда меняют местами?" сюда .
источник
Я столкнулся с той же проблемой, используя LIBSVM в MATLAB. Чтобы проверить это, я создал очень простой двумерный линейно разделяемый набор данных, который, как оказалось, транслировался вдоль одной оси примерно на -100. Обучение линейного SVM с использованием LIBSVM создало гиперплоскость, чей перехват был все еще прямо около нуля (и, таким образом, частота ошибок составляла 50%, естественно). Стандартизация данных (вычитание среднего значения) помогла, хотя полученный svm по-прежнему не работал идеально ... озадачивает. Кажется, что LIBSVM вращает только гиперплоскость вокруг оси, не перемещая ее. Возможно, вам следует попытаться вычесть среднее значение из ваших данных, но кажется странным, что LIBSVM будет вести себя таким образом. Возможно, мы что-то упустили.
Что бы это ни стоило, встроенная функция MATLAB
svmtrain
создала классификатор со 100% точностью без стандартизации.источник