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

R中函数与参数传递执行问题求助(含递归场景)

解决R项目中RMSE计算卡顿崩溃问题与递归函数参数传递优化

咱们先揪出导致卡顿崩溃的核心问题,再一步步修正代码逻辑,实现正确的函数参数传递和递归细化:

核心问题分析

  1. sapply与do.call用法完全错误
    你当前写的RMSE <- sapply(lambdas, do.call(FUN, params))是致命问题:sapply需要的是一个能接收单个lambda的函数,但你直接执行了do.call(FUN, params),相当于把整个lambdas向量、拆分后的训练/测试集一股脑传给了子函数,这会让子函数处理完全超出预期的超大输入,直接撑爆内存导致崩溃。

  2. 参数构造逻辑错误
    params = c(lambdas, train_set, test_set)里的c()会把数据框拆成单个向量元素,完全破坏了数据集的结构,子函数拿到的根本不是完整的训练/测试集。

  3. 函数传递方式冗余
    传入FUN="regularized_rmse_3"字符串完全没必要,直接传递函数对象更高效,还能避免环境查找的潜在问题。

修正后的完整代码

父函数 find_generic_lambda

library(ggplot2)
library(dplyr)

find_generic_lambda <- function(seq_start, seq_end, seq_increment, FUN, detailed_flag = FALSE, training_set, testing_set) {
  lambdas <- seq(seq_start, seq_end, seq_increment)
  
  # 正确遍历每个lambda,调用子函数计算RMSE
  RMSE <- sapply(lambdas, function(current_lambda) {
    # 直接传递当前lambda、完整的训练集和测试集给子函数
    FUN(current_lambda, training_set, testing_set)
  })
  
  # 绘制RMSE曲线(如果不需要递归时重复绘图,可加判断只在第一次绘制)
  print(qplot(lambdas, RMSE, xlab = "Lambda", ylab = "RMSE", main = "RMSE vs Lambda"))
  
  # 找到当前区间的最优lambda
  min_lambda <- lambdas[which.min(RMSE)]
  
  # 开启细化模式时,进行一次递归缩小范围
  if (detailed_flag) {
    # 计算原区间的10%作为新的搜索范围,中心在当前最优lambda
    original_total_range <- seq_end - seq_start
    new_search_range <- original_total_range / 10
    min_lambda <- find_generic_lambda(
      seq_start = min_lambda - new_search_range,
      seq_end = min_lambda + new_search_range,
      seq_increment = seq_increment / 10,
      FUN = FUN,
      detailed_flag = FALSE,
      training_set = training_set,
      testing_set = testing_set
    )
  }
  
  return(min_lambda)
}

子函数 regularized_rmse_3

regularized_rmse_3 <- function(l, train_set, test_set) {
  mu <- mean(train_set$rating)
  just_the_sum <- train_set %>% 
    group_by(movieId) %>% 
    summarize(
      s = sum(rating - mu),
      n_i = n(),
      .groups = "drop"  # 显式取消分组,避免后续join的分组问题
    )
  
  predicted_ratings <- test_set %>% 
    left_join(just_the_sum, by = "movieId") %>% 
    mutate(
      b_i = s/(n_i + l),
      pred = mu + b_i
    ) %>% 
    pull(pred)
  
  return(RMSE(predicted_ratings, test_set$rating))
}

调用父函数

# 注意这里直接传递函数对象,不是字符串!
rmse3_lambda <- find_generic_lambda(
  seq_start = 0,
  seq_end = 10,
  seq_increment = 0.5,
  FUN = regularized_rmse_3,
  detailed_flag = TRUE,
  training_set = training_set,
  testing_set = testing_set
)

关键优化点说明

  • 修复RMSE计算逻辑:用匿名函数包裹子函数调用,确保每个lambda单独传入,同时完整传递训练/测试集,彻底解决内存过载问题。
  • 修正递归范围计算:原代码的new_lambda_range逻辑错误,现在用原区间的10%作为新搜索范围,确保递归时聚焦在最优lambda附近。
  • 显式取消分组:在summarize后添加.groups = "drop",避免分组状态传递到后续操作引发警告或错误。
  • 函数传递优化:直接传递函数对象,比字符串更高效,也避免了do.call查找函数时的环境问题。

额外性能建议

如果你的数据集非常大,可以考虑用purrr::map_dbl代替sapply,语法更清晰且性能相当;另外如果不需要递归时重复绘制图表,可以在绘图前加个判断,比如只在detailed_flag为TRUE时绘制第一次的图。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:22:43