Помогите с помощью функции предиката () для SVM Kernlab в R? - PullRequest
6 голосов
/ 18 ноября 2009

Я пытаюсь использовать пакет kernlab R для поддержки машин опорных векторов (SVM). Для моего очень простого примера у меня есть две части обучающих данных. А и Б.

(A и B имеют тип matrix - это матрицы смежности для графов.)

Итак, я написал функцию, которая принимает A + B и генерирует матрицу ядра.

> km
         [,1]     [,2]
[1,] 14.33333 18.47368
[2,] 18.47368 38.96053

Теперь я использую функцию kernlab ksvm для генерации моей прогнозирующей модели. Прямо сейчас я просто пытаюсь заставить эту чертову вещь работать - меня не беспокоит ошибка обучения и т. Д.

Итак, Вопрос 1 : Правильно ли я генерирую свою модель? Разумно?

# y are my classes. In this case, A is in class "1" and B is in class "-1"
> y
[1]  1 -1

> model2 =  ksvm(km, y, type="C-svc", kernel = "matrix");
> model2
Support Vector Machine object of class "ksvm" 

SV type: C-svc  (classification) 
 parameter : cost C = 1 

[1] " Kernel matrix used as input."

Number of Support Vectors : 2 

Objective Function Value : -0.1224 
Training error : 0 

Пока все хорошо. Мы создали нашу собственную матрицу ядра, а затем мы создали модель ksvm, используя эту матрицу. У нас есть данные обучения, помеченные как «1» и «-1».

Теперь, чтобы предсказать:

> A
     [,1] [,2] [,3]
[1,]    0    1    1
[2,]    1    0    1
[3,]    0    0    0

> predict(model2, A)
Error in as.matrix(Z) : object 'Z' not found

Ой-ой. Это нормально. Вроде как и ожидалось. «Predict» хочет какой-то вектор, а не матрицу.

Итак, давайте попробуем несколько вещей:

> predict(model2, c(1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1,1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, km)
Error in as.matrix(Z) : object 'Z' not found

Некоторые из вышеперечисленных тестов бессмысленны, но в этом моя суть: независимо от того, что я делаю, я просто не могу получить, чтобы предсказание () смотрело на мои данные и делало предсказание. Скаляры не работают, векторы не работают. Матрица 2х2 не работает, а матрица 3х3 не работает.

Что я здесь не так делаю?

(Как только я выясню, чего хочет ksvm , я могу убедиться, что мои тестовые данные могут соответствовать этому формату в разумной / разумной / математически обоснованной форме.)

Ответы [ 4 ]

21 голосов
/ 18 ноября 2009

Если вы подумаете о том, как машина опорных векторов может «использовать» матрицу ядра, вы увидите, что вы не можете сделать это так, как пытаетесь (как вы видели: -)

Я на самом деле немного боролся с этим, когда впервые использовал Kernlab + матрицу ядра ... по совпадению, это было также и для графовых ядер!

В любом случае, давайте сначала поймем, что, поскольку SVM не знает, как рассчитать вашу функцию ядра, ему необходимо рассчитать эти значения уже между вашими новыми (тестирующими) примерами и примерами, которые он выбирает в качестве векторов поддержки во время шаг тренировки.

Итак, вам нужно вычислить матрицу ядра для всех ваших примеров вместе. Позже вы будете тренироваться на некоторых и тестировать на других, удаляя строки + столбцы из матрицы ядра, когда это уместно. Позвольте мне показать вам код.

Мы можем использовать пример кода в документации ksvm для загрузки нашего рабочего пространства некоторыми данными:

library(kernlab)
example(ksvm)

Вам нужно будет нажать return несколько раз (2), чтобы графики прорисовывались, и пример заканчивался, но теперь у вас должна быть матрица ядра в вашем рабочем пространстве с именем K. Нам нужно восстановить вектор y, который он должен использовать для своих меток (так как он был растоптан другим кодом в примере):

y <- matrix(c(rep(1,60),rep(-1,60)))

Теперь выберите набор примеров для тестирования

holdout <- sample(1:ncol(K), 10)

С этого момента я собираюсь:

  1. Создайте обучающую матрицу ядра с именем trainK из исходной K матрицы ядра.
  2. Создание модели SVM из моего тренировочного набора trainK
  3. Использование векторов поддержки, найденных в модели, для создания тестовой матрицы ядра testK ... это странная часть. Если вы посмотрите на код в kernlab, чтобы увидеть, как он использует индексы опорных векторов, вы поймете, почему это делается именно так. Возможно, это можно сделать иным способом, но я не видел документации / примеров по , предсказывающим с матрицей ядра, поэтому я делаю это "трудным путем" здесь.
  4. Использование SVM для прогнозирования этих функций и точности отчетов

Вот код:

trainK <- as.kernelMatrix(K[-holdout,-holdout])  # 1
m <- ksvm(trainK, y[-holdout], kernel='matrix')  # 2
testK <- as.kernelMatrix(K[holdout, -holdout][,SVindex(m), drop=F]) # 3
preds <- predict(m, testK)  # 4
sum(sign(preds) == sign(y[holdout])) / length(holdout) # == 1 (perfect!)

Это должно вот-вот сделать. Удачи!

Ответы на комментарии ниже

что означает K [-holdout, -holdout]? (что означает "-"?)

Представьте, что у вас есть вектор x, и вы хотите извлечь из него элементы 1, 3 и 5, вам нужно сделать:

x.sub <- x[c(1,3,5)]

Если вы хотите извлечь все из x , кроме элементов 1, 3 и 5, вам нужно сделать:

x.sub <- x[-c(1,3,5)]

Итак, K[-holdout,-holdout] возвращает все строки и столбцы K , кроме для строк, которые мы хотим удержать.

Каковы аргументы вашего as.kernelMatrix - особенно аргумент [, SVindex (m), drop = F] (что особенно странно, поскольку похоже, что вся скобка представляет собой матричный индекс K?)

Да, я встроил две команды в одну:

testK <- as.kernelMatrix(K[holdout, -holdout][,SVindex(m), drop=F])

Теперь, когда вы обучили модель, вы хотите дать ей новую матрицу ядра с вашими примерами тестирования. K[holdout,] даст вам только строки, которые соответствуют обучающим примерам в K, и все столбцы K.

SVindex(m) дает вам индексы ваших векторов поддержки из вашей оригинальной матрицы обучения - помните, у этих строк / столбцов удалено holdout. Поэтому, чтобы эти индексы столбцов были правильными (т. Е. Ссылаются на правильный столбец sv), я должен сначала удалить столбцы holdout.

Во всяком случае, возможно, это более ясно:

testK <- K[holdout, -holdout]
testK <- testK[,SVindex(m), drop=FALSE]

Теперь testK содержит только строки наших примеров тестирования и столбцы, которые соответствуют опорным векторам. testK[1,1] будет иметь значение функции ядра, вычисленное между вашим первым примером тестирования и первым опорным вектором. testK[1,2] будет иметь значение функции ядра между вашим первым примером тестирования и вторым вектором поддержки и т. Д.

Обновление (2014-01-30) для ответа на комментарий от @ wrahool

Прошло много времени с тех пор, как я поиграл с этим, поэтому подробности kernlab::ksvm немного ржавые, но в принципе это должно быть правильно :-) ... вот так:

в чем смысл testK <- K[holdout, -holdout] - разве вы не удаляете столбцы, которые соответствуют тестовому набору?

Да. Краткий ответ: если вы хотите predict использовать матрицу ядра, вы должны предоставить матрицу, имеющую размерность rows, на support vectors. Для каждой строки матрицы (новый пример, который вы хотите предсказать) значения в столбцах являются просто значением матрицы ядра, вычисленной между этим примером и опорным вектором.

Вызов SVindex(m) возвращает индекс векторов поддержки, заданных в измерении оригинальных обучающих данных.

Итак, сначала выполнение testK <- K[holdout, -holdout] дает мне матрицу testK со строками примеров, которые я хочу предсказать, и столбцы взяты из тех же примеров (измерений), на которых обучалась модель.

Далее я подставлю столбцы testK на SVindex(m), чтобы получить только те столбцы, которые (сейчас) соответствуют моим опорным векторам. Если бы я не сделал первый выбор [, -holdout], индексы, возвращаемые SVindex(m), могут не соответствовать правильным примерам (если только все N ваших тестовых примеров не являются последними N столбцами вашей матрицы).

Кроме того, что именно делает условие drop = FALSE?

Это немного защитное кодирование, чтобы гарантировать, что после выполнения операции индексации возвращаемый объект будет того же типа, что и индексированный объект.

В R, если вы индексируете только одно измерение 2D (или более высокого (?)) Объекта, вам возвращается объект более низкого измерения. Я не хочу передавать numeric вектор в predict, потому что он хочет иметь matrix

Например

x <- matrix(rnorm(50), nrow=10)

class(x)
[1] "matrix"

dim(x)
[1] 10  5

y <- x[, 1]

class(y)
[1] "numeric"

dim(y)
NULL

То же самое произойдет с data.frame с и т. Д.

2 голосов
/ 18 ноября 2009

Во-первых, я не использовал kernlab много. Но, просто глядя на документы, я вижу рабочие примеры для метода predict.ksvm(). Копирование, вставка и пропуск печати на экран:

 ## example using the promotergene data set
 data(promotergene)

 ## create test and training set
 ind <- sample(1:dim(promotergene)[1],20)
 genetrain <- promotergene[-ind, ]
 genetest <- promotergene[ind, ]

 ## train a support vector machine
 gene <-  ksvm(Class~.,data=genetrain,kernel="rbfdot",\
               kpar=list(sigma=0.015),C=70,cross=4,prob.model=TRUE)

 ## predict gene type probabilities on the test set
 genetype <- predict(gene,genetest,type="probabilities")

Это выглядит довольно прямолинейно: используйте случайную выборку для генерации обучающего набора genetrain и его дополнения genetest, затем подгонку через ksvm и вызов метода predict() с использованием подбора и новых данных. в соответствующем формате. Это очень стандартно.

Вам может пригодиться пакет caret Макса Куна. Он обеспечивает общую структуру оценки и тестирования для различных методов и пакетов регрессии, классификации и машинного обучения, включая kernlab , и содержит несколько виньеток плюс документ JSS .

1 голос
/ 18 мая 2014

Стив Лианоглу прав.

В kernlab это немного запутано, и при предсказании этого требует входную матрицу ядра между каждым тестовым примером и векторами поддержки. Вам нужно найти эту матрицу самостоятельно.

Например, тестовая матрица [n x m], где n - количество тестовых выборок, а m - количество опорных векторов в изученной модели (упорядочено в последовательности SVindex (модель)).

Пример кода

trmat <- as.kernelMatrix(kernels[trainidx,trainidx])
tsmat <- as.kernelMatrix(kernels[testidx,trainidx])

#training
model = ksvm(x=trmat, y=trlabels, type = "C-svc", C = 1)

#testing
thistsmat = as.kernelMatrix(tsmat[,SVindex(model)])
tsprediction = predict(model, thistsmat, type = "decision")

kernels - это входная матрица ядра. trainidx и testidx - это идентификаторы для обучения и тестирования.

0 голосов
/ 04 марта 2015

Создайте ярлыки самостоятельно из элементов решения. Используйте этот альтернативный метод предиктора, который использует модель ksvm (m) и данные в оригинальном формате обучения (d)

predict.alt <- function(m, d){
  sign(d[, m@SVindex] %*% m@coef[[1]] - m@b)
}

K - это kernelMatrix для обучения. Ради валидации, если вы запустите predict.alt для обучающих данных, вы заметите, что альтернативный метод предиктора переключает значения вместе с подобранными значениями, возвращаемыми ksvm. Собственный предиктор ведет себя неожиданным образом:

aux <- data.frame(fit=kout@fitted, native=predict(kout, K), alt=predict.alt(m=kout, d=as.matrix(K))) 
sample_n(aux, 10)
    fit  native alt
1     0       0  -1
100   1       0   1
218   1       0   1
200   1       0   1
182   1       0   1
87    0       0  -1
183   1       0   1
174   1       0   1
94    1       0   1
165   1       0   1
...