Помогите использовать предикат () для SVM Kernlab в R?
Я пытаюсь использовать kernlab
Пакет R для поддержки опорных векторов (SVM). Для моего очень простого примера у меня есть две части обучающих данных. А и Б.
(А и В имеют тип matrix
- это матрицы смежности для графов.)
Поэтому я написал функцию, которая принимает A+B и генерирует матрицу ядра.
> km
[,1] [,2]
[1,] 14.33333 18.47368
[2,] 18.47368 38.96053
Сейчас пользуюсь kernlab
"s 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 ответа
Если вы подумаете о том, как машина опорных векторов может "использовать" матрицу ядра, вы увидите, что вы не можете сделать это так, как пытаетесь (как вы видели:-)
Я на самом деле немного боролся с этим, когда впервые использовал 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)
С этого момента я собираюсь:
- Создать обучающую матрицу ядра с именем
trainK
из оригиналаK
матрица ядра. - Создать модель SVM из моего тренировочного набора
trainK
- Используйте векторы поддержки, найденные в модели, для создания тестовой матрицы ядра
testK
... это странная часть. Если вы посмотрите на код вkernlab
чтобы увидеть, как он использует индексы опорных векторов, вы поймете, почему это делается именно так. Возможно, это можно сделать по-другому, но я не видел документации / примеров по прогнозированию с помощью матрицы ядра, поэтому я делаю это "трудным путем" здесь. - Используйте 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
с и т. д.
Во-первых, я не использовал 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()
метод с использованием подгонки и новые данные в соответствующем формате. Это очень стандартно.
Вам может пригодиться пакет карет Макса Куна. Он предоставляет общую структуру оценки и тестирования для различных методов и пакетов регрессии, классификации и машинного обучения, включая kernlab, и содержит несколько виньеток плюс документ JSS.
Стив Лианоглу прав.
В 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 - это идентификаторы для обучения и тестирования.
Создайте ярлыки самостоятельно из элементов решения. Используйте этот альтернативный метод предиктора, который использует модель ksvm (m) и данные в оригинальном формате обучения (d)
predict.alt <- function(m, d){
sign(d[, m@SVindex] %*% m@coef[[1]] - m@b)
}
К является 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