Помогите использовать predic () для SVM kernlab в R?

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

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

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

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

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

Итак, вопрос 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(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

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

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

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


person poundifdef    schedule 18.11.2009    source источник


Ответы (4)


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

Я действительно немного боролся с этим, когда впервые использовал 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] будет иметь значение функции ядра между вашим 1-м тестовым примером и вторым вектором поддержки и т. Д.

Обновление (30 января 2014 г.), чтобы ответить на комментарий от @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.frames и т. Д.

person Steve Lianoglou    schedule 18.11.2009
comment
Хорошо, я запустил ваш код в том виде, в каком он был написан, и он работает! Но мне немного сложно понять, что он делает. Не могли бы вы помочь мне понять: что означает K [-noldout, -holdout]? (что означает -?) Каковы аргументы вашего as.kernelMatrix - особенно аргумент [, SVindex (m), drop = F] (что особенно странно, потому что похоже, что вся скобка представляет собой матричный индекс K ?) - person poundifdef; 19.11.2009
comment
Поскольку это было долго, я ответил на ваш комментарий в своем исходном посте - прочтите нижнюю половину. Если у вас есть дополнительные вопросы, вы всегда можете обратиться к списку r-help, чтобы задать дополнительные вопросы. Наконец, если мой ответ действительно отвечает на ваш вопрос, не забудьте отметить его как таковой ;-) - person Steve Lianoglou; 19.11.2009
comment
Чувак. Ты так много качаешься. Спасибо! - person poundifdef; 20.11.2009
comment
@Steve Lianoglou, спасибо за это решение, оно спасло мне день! У меня очень мало знаний о SVM, а kernlab имеет очень специфические методы ... однако мне не ясно, следует ли включать переменную ответа y для вычисления матрицы ядра? есть ли способ обновить матрицу ядра, не вычисляя ее снова, когда есть новые данные? еще раз большое спасибо - person nopeva; 30.09.2013
comment
@ AP13: Не поймите меня неправильно, но если у вас ограниченные знания о SVM, вам следует сделать домашнее задание, чтобы лучше понять, как они работают, прежде чем просто слепо их использовать. При этом было сказано: (1) Функция ядра является функцией функций ваших примеров и не зависит от их меток, поэтому вам не нужно y при вычислении матрицы ядра; и (2) это возможно, но вам, вероятно, придется самостоятельно кодировать решение. Матрица ядра дает вам значения ядра для каждой пары примеров (строка, столбец). Вам нужно будет создать обновленную матрицу ядра, которая учитывает это. - person Steve Lianoglou; 30.09.2013
comment
@Steve Lianoglou, спасибо за ответы, я обязательно изучу теорию, прежде чем использовать их. - person nopeva; 30.09.2013
comment
@Steve Lianoglou, это отличный ответ! Однако мне нужно одно небольшое уточнение: в чем смысл testK <- K[holdout, -holdout] - разве вы не удаляете столбцы, соответствующие набору тестов? Кроме того, что именно делает условие drop = FALSE? - person wrahool; 30.01.2014
comment
@wrahool Я обновляю свой ответ, чтобы ответить на ваш комментарий - он слишком длинный, чтобы поместиться в это поле для комментариев. - person Steve Lianoglou; 30.01.2014
comment
Отличный ответ, и я признаю, что немного поздно, но должен ли этот метод работать и для rvm? - person catastrophic-failure; 19.06.2016

Во-первых, я мало использовал 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.

person Dirk Eddelbuettel    schedule 18.11.2009
comment
Верно - я читал? Предсказывать тоже. В этом примере вы передаете функцию ядра (rbfdot) и обучающие данные (genetrain) в ksvm (). В моем случае входными данными является матрица ядра, поэтому ksvm () никогда не имеет параметра данных, поэтому нет четкого сопоставления между структурой моих обучающих данных и структурой моих тестовых данных. - person poundifdef; 18.11.2009
comment
Если вам интересно, я пытаюсь реализовать ядра графов в R, поэтому вместо классификации векторных данных я смотрю на данные графа. Таким образом, моя функция ядра смотрит на количество случайных блужданий, которые эквивалентны между двумя графиками, чтобы определить их расстояние. - person poundifdef; 18.11.2009

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

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

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

Пример кода

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

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

person user1165814    schedule 18.05.2014

Изготовьте этикетки самостоятельно из элементов раствора. Используйте этот альтернативный метод прогнозирования, который принимает модель 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
person user3349904    schedule 04.03.2015