You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键修改说明

  1. 将原错误的puk_nu参数替换为PUK核专属的puk_sigma和puk_omega,并正确映射到核函数的参数
  2. 在set_fit中通过eng_args动态生成核对象,确保传递给ksvm的是已初始化的核函数实例
  3. 添加type = "eps-svr"和scaled = TRUE参数,与直接调用ksvm的参数保持一致,避免因参数缺失导致错误

内容的提问来源于stack exchange,提问作者GreenManXY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:55:57