为parsnip配置kernlab自定义PUK核SVM模型时遇vec_slice错误
解决Parsnip自定义KSVM PUK核模型的拟合错误
问题描述
尝试为Parsnip搭建自定义模型,使用kernlab包中ksvm函数的自定义PUK核,模型定义阶段代码可正常运行,但执行拟合命令时出现错误,而直接调用ksvm使用该核则能正常运行。
自定义模型代码如下:
library(tidyverse) library(tidymodels) library(kernlab) set_new_model("svm_puk") set_model_mode(model = "svm_puk", mode = "regression") set_model_engine(model = "svm_puk", mode = "regression", eng = "kernlab") set_dependency("svm_puk", eng = "kernlab", pkg = "kernlab") set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "cost", original = "C", func = list(pkg = "dials", fun = "cost"), has_submodel = FALSE) set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "puk_nu", original = "nu", func = list(pkg = "dials", fun = "rbf_sigma"), has_submodel = FALSE) set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "margin", original = "epsilon", func = list(pkg = "dials", fun = "margin"), has_submodel = FALSE) svm_puk <- function(mode = "regression", cost = NULL, puk_nu = NULL, margin = NULL) { args <- list(cost = rlang::enquo(cost), puk_nu = rlang::enquo(puk_nu), margin = rlang::enquo(margin)) new_model_spec("svm_puk", args = args, eng_args = NULL, mode = mode, method = NULL, engine = NULL) } puk_kernel <- function(sigma = 1.5, omega = 1) { kfun <- function(x, y) { x <- as.matrix(x) y <- as.matrix(y) dist_matrix <- sum((x - y)^2) denom <- 2 * omega * sqrt(2^(1 / sigma) - 1) K <- (1 + dist_matrix / denom)^(-sigma) return(K) } class(kfun) <- "kernel" return(kfun) } set_fit(model = "svm_puk", eng = "kernlab", mode = "regression", value = list(interface = "formula", protect = c("formula", "data"), func = c(pkg = "kernlab", fun = "ksvm"), defaults = list(kernel = puk_kernel)) ) set_pred(model = "svm_puk", eng = "kernlab", mode = "regression", type = "numeric", value = list(pre = NULL, post = NULL, func = c(fun = "predict"), args = list(object = rlang::expr(object), newdata = rlang::expr(new_data), type = "response")) ) svm_puk_spec <- svm_puk(cost = 400, puk_nu = 0.2, margin = 0.001) %>% set_engine("kernlab") %>% set_mode("regression")
执行拟合命令svm_puk_fit <- fit(svm_puk_spec, mpg ~ ., data = mtcars)时出现以下错误:
Error in `vctrs::vec_slice()`: ! `x` must be a vector, not `NULL`. --- Backtrace: ▆ 1. ├─generics::fit(svm_puk_spec, mpg ~ ., data = mtcars) 2. ├─parsnip::fit.model_spec(svm_puk_spec, mpg ~ ., data = mtcars) 3. │ └─parsnip:::form_form(object = object, control = control, env = eval_env) 4. │ └─vctrs::vec_slice(...) 5. └─vctrs:::stop_scalar_type(`<fn>`(NULL), "x", `<env>`) 6. └─vctrs:::stop_vctrs(...) 7. └─rlang::abort(message, class = c(class, "vctrs_error"), ..., call = call)
解决方案
错误根源在于Parsnip的拟合配置中,核函数的传递方式错误,且缺少必要的ksvm参数。以下是修正步骤及完整代码:
修正要点
- 调整核参数映射:原代码中
puk_nu错误映射到ksvm的nu参数,实际应对应PUK核的sigma和omega参数 - 动态生成核对象:在拟合时需调用
puk_kernel()生成核对象,而非传递函数本身 - 补充ksvm必要参数:添加
type = "eps-svr"(回归类型)和scaled = TRUE(与直接调用ksvm保持一致)
修正后的完整代码
library(tidyverse) library(tidymodels) library(kernlab) # 1. 定义模型基础信息 set_new_model("svm_puk") set_model_mode(model = "svm_puk", mode = "regression") set_model_engine(model = "svm_puk", mode = "regression", eng = "kernlab") set_dependency("svm_puk", eng = "kernlab", pkg = "kernlab") # 2. 定义模型参数映射 # 成本参数对应ksvm的C set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "cost", original = "C", func = list(pkg = "dials", fun = "cost"), has_submodel = FALSE) # 回归epsilon参数对应ksvm的epsilon set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "margin", original = "epsilon", func = list(pkg = "dials", fun = "margin"), has_submodel = FALSE) # PUK核的sigma参数 set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "puk_sigma", original = NULL, func = list(pkg = "dials", fun = "rbf_sigma"), has_submodel = FALSE) # PUK核的omega参数 set_model_arg(model = "svm_puk", eng = "kernlab", parsnip = "puk_omega", original = NULL, func = list(pkg = "dials", fun = "numeric_range", range = c(0.1, 5)), has_submodel = FALSE) # 3. 模型构造函数 svm_puk <- function(mode = "regression", cost = NULL, margin = NULL, puk_sigma = NULL, puk_omega = NULL) { args <- list( cost = rlang::enquo(cost), margin = rlang::enquo(margin), puk_sigma = rlang::enquo(puk_sigma), puk_omega = rlang::enquo(puk_omega) ) new_model_spec( "svm_puk", args = args, eng_args = NULL, mode = mode, method = NULL, engine = NULL ) } # 4. 自定义PUK核函数 puk_kernel <- function(sigma = 1.5, omega = 1) { kfun <- function(x, y) { x <- as.matrix(x) y <- as.matrix(y) dist_matrix <- sum((x - y)^2) denom <- 2 * omega * sqrt(2^(1 / sigma) - 1) K <- (1 + dist_matrix / denom)^(-sigma) return(K) } class(kfun) <- "kernel" return(kfun) } # 5. 配置拟合逻辑:动态生成核对象,补充ksvm必要参数 set_fit(model = "svm_puk", eng = "kernlab", mode = "regression", value = list( interface = "formula", protect = c("formula", "data"), func = c(pkg = "kernlab", fun = "ksvm"), defaults = list( type = "eps-svr", scaled = TRUE ), # 处理核参数,动态生成核对象 eng_args = list( kernel = rlang::expr(puk_kernel(sigma = puk_sigma, omega = puk_omega)) ) ) ) # 6. 配置预测逻辑 set_pred(model = "svm_puk", eng = "kernlab", mode = "regression", type = "numeric", value = list( pre = NULL, post = NULL, func = c(fun = "predict"), args = list( object = rlang::expr(object), newdata = rlang::expr(new_data), type = "response" ) ) ) # 7. 定义模型规格并拟合 svm_puk_spec <- svm_puk( cost = 400, margin = 0.001, puk_sigma = 0.2, puk_omega = 1 ) %>% set_engine("kernlab") %>% set_mode("regression") # 执行拟合,此时可正常运行 svm_puk_fit <- fit(svm_puk_spec, mpg ~ ., data = mtcars)
关键修改说明
- 将原错误的
puk_nu参数替换为PUK核专属的puk_sigma和puk_omega,并正确映射到核函数的参数 - 在
set_fit中通过eng_args动态生成核对象,确保传递给ksvm的是已初始化的核函数实例 - 添加
type = "eps-svr"和scaled = TRUE参数,与直接调用ksvm的参数保持一致,避免因参数缺失导致错误
内容的提问来源于stack exchange,提问作者GreenManXY
相关产品推荐
相关产品推荐

