我正在致力于在癌症数据集上使用 R 构建预测分类器。 我使用随机森林、支持向量机和朴素贝叶斯分类器。我无法计算 SVM 和 NB 模型的变量重要性
我最终收到以下错误。
UseMethod("varImp") 中的错误: 'varImp' 没有适用的方法应用于类“c('svm.formula', 'svm')”的对象
如果有人能帮助我,我将不胜感激。
给定
library(e1071)
model <- svm(Species ~ ., data = iris)
class(model)
# [1] "svm.formula" "svm"
library(caret)
varImp(model)
# Error in UseMethod("varImp") :
# no applicable method for 'varImp' applied to an object of class "c('svm.formula', 'svm')"
methods(varImp)
# [1] varImp.bagEarth varImp.bagFDA varImp.C5.0* varImp.classbagg*
# [5] varImp.cubist* varImp.dsa* varImp.earth* varImp.fda*
# [9] varImp.gafs* varImp.gam* varImp.gbm* varImp.glm*
# [13] varImp.glmnet* varImp.JRip* varImp.lm* varImp.multinom*
# [17] varImp.mvr* varImp.nnet* varImp.pamrtrained* varImp.PART*
# [21] varImp.plsda varImp.randomForest* varImp.RandomForest* varImp.regbagg*
# [25] varImp.rfe* varImp.rpart* varImp.RRF* varImp.safs*
# [29] varImp.sbf* varImp.train*
varImp.svm
中没有函数methods(varImp)
,因此出现错误。您可能还想看看交叉验证上的这篇文章。
如果使用R,可以使用rminer包中的Importance方法计算变量重要性。这是我的示例代码:
library(rminer)
M <- fit(y~., data=train, model="svm", kpar=list(sigma=0.10), C=2)
svm.imp <- Importance(M, data=train)
详细请参考以下链接https://cran.r-project.org/web/packages/rminer/rminer.pdf
我创建了一个循环,一次迭代地删除一个预测变量,并在数据帧中捕获从混淆矩阵导出的各种性能度量。这不应该是一刀切的解决方案,我没有时间,但应用修改应该不难。
确保预测变量位于数据框中的最后一个。
我主要需要模型中的特异性值,通过一次删除一个预测变量,我可以评估每个预测变量的重要性,即通过删除一个预测变量,模型的最小特异性(较少的预测变量编号 i)意味着预测器最为重要。您需要知道您将根据什么指标赋予重要性。
您还可以在内部添加另一个 for 循环以在内核之间进行更改,即线性、多项式、径向,但您可能必须考虑其他参数,例如伽玛。将“label_fake”更改为目标变量,将 df_final 更改为数据框。
SVM版本:
set.seed(1)
varimp_df <- NULL # df with results
ptm1 <- proc.time() # Start the clock!
for(i in 1:(ncol(df_final)-1)) { # the last var is the dep var, hence the -1
smp_size <- floor(0.70 * nrow(df_final)) # 70/30 split
train_ind <- sample(seq_len(nrow(df_final)), size = smp_size)
training <- df_final[train_ind, -c(i)] # receives all the df less 1 var
testing <- df_final[-train_ind, -c(i)]
tune.out.linear <- tune(svm, label_fake ~ .,
data = training,
kernel = "linear",
ranges = list(cost =10^seq(1, 3, by = 0.5))) # you can choose any range you see fit
svm.linear <- svm(label_fake ~ .,
kernel = "linear",
data = training,
cost = tune.out.linear[["best.parameters"]][["cost"]])
train.pred.linear <- predict(svm.linear, testing)
testing_y <- as.factor(testing$label_fake)
conf.matrix.svm.linear <- caret::confusionMatrix(train.pred.linear, testing_y)
varimp_df <- rbind(varimp_df,data.frame(
var_no=i,
variable=colnames(df_final[,i]),
cost_param=tune.out.linear[["best.parameters"]][["cost"]],
accuracy=conf.matrix.svm.linear[["overall"]][["Accuracy"]],
kappa=conf.matrix.svm.linear[["overall"]][["Kappa"]],
sensitivity=conf.matrix.svm.linear[["byClass"]][["Sensitivity"]],
specificity=conf.matrix.svm.linear[["byClass"]][["Specificity"]]))
runtime1 <- as.data.frame(t(data.matrix(proc.time() - ptm1)))$elapsed # time for running this loop
runtime1 # divide by 60 and you get minutes, /3600 you get hours
}
朴素贝叶斯版本:
varimp_nb_df <- NULL
ptm1 <- proc.time() # Start the clock!
for(i in 1:(ncol(df_final)-1)) {
smp_size <- floor(0.70 * nrow(df_final))
train_ind <- sample(seq_len(nrow(df_final)), size = smp_size)
training <- df_final[train_ind, -c(i)]
testing <- df_final[-train_ind, -c(i)]
x = training[, names(training) != "label_fake"]
y = training$label_fake
model_nb_var = train(x,y,'nb', trControl=ctrl)
predict_nb_var <- predict(model_nb_var, newdata = testing )
confusion_matrix_nb_1 <- caret::confusionMatrix(predict_nb_var, testing$label_fake)
varimp_nb_df <- rbind(varimp_nb_df, data.frame(
var_no=i,
variable=colnames(df_final[,i]),
accuracy=confusion_matrix_nb_1[["overall"]][["Accuracy"]],
kappa=confusion_matrix_nb_1[["overall"]][["Kappa"]],
sensitivity=confusion_matrix_nb_1[["byClass"]][["Sensitivity"]],
specificity=confusion_matrix_nb_1[["byClass"]][["Specificity"]]))
runtime1 <- as.data.frame(t(data.matrix(proc.time() - ptm1)))$elapsed # time for running this loop
runtime1 # divide by 60 and you get minutes, /3600 you get hours
}
玩得开心!
如文档中所示,对于没有相应
varImp()
方法的模型,varImp.train()
使用 filterVarImp()
,它计算与模型无关的指标(参见例如 https://topepo.github.io/caret/variable- important.html#model-independent-metrics)。
而且这个函数似乎只支持数值预测器:
> library(caret)
> caret.svm <- train(Species ~ ., data = iris, method = "svmRadial",
+ preProcess = c("center", "scale"),
+ prob.model = TRUE)
> varImp(caret.svm)
ROC curve variable importance
variables are sorted by maximum importance across the classes
setosa versicolor virginica
Petal.Width 100.00 100.00 100.0
Petal.Length 100.00 100.00 100.0
Sepal.Length 90.70 59.30 90.7
Sepal.Width 54.59 54.59 0.0
> filterVarImp(iris[1:4], iris$Species)
setosa versicolor virginica
Sepal.Length 0.9846 0.9326 0.9846
Sepal.Width 0.9248 0.9248 0.8344
Petal.Length 1.0000 1.0000 1.0000
Petal.Width 1.0000 1.0000 1.0000
> iris2 <- iris
> iris2$Petal.Length <- as.factor(iris2$Petal.Length > 4)
> caret.svm <- train(Species ~ ., data = iris2, method = "svmRadial",
+ preProcess = c("center", "scale"))
> varImp(caret.svm)
Error: Not compatible with requested type: [type=character; target=double].
> filterVarImp(iris2[1:4], iris2$Species)
Error: Not compatible with requested type: [type=character; target=double].
最简单的替代方案似乎是将模型与另一个包相匹配(例如rminer;请注意,默认情况下,它还计算与模型无关的指标)。我也没有找到任何支持 kernlab 拟合的可变重要性包(例如 vip)(由
train()
组件中的 caret.svm$finalModel
返回)。