【问题标题】:How to sapply a vector on a user defined function in R如何在 R 中的用户定义函数上应用向量
【发布时间】:2020-08-30 00:31:12
【问题描述】:

我有一个名为make_data 的用户定义函数用于创建数据集。 我需要使用make _datamu_1 <- seq(1:3) 生成3 个不同的数据集。我不知道怎么用sapply,因为make_data函数有多个参数,

library(dplyr) # for `%>%` and `slice`
library(caret) # for createDataPartion
make_data <- function(n = 1000, p = 0.5, 
                  mu_0 = 0, mu_1 = 2, 
                  sigma_0 = 1,  sigma_1 = 1){



 y <- rbinom(n, 1, p)
  f_0 <- rnorm(n, mu_0, sigma_0)
  f_1 <- rnorm(n, mu_1, sigma_1)
  x <- ifelse(y == 1, f_1, f_0)

  test_index <- createDataPartition(y, times = 1, p = 0.5, list = FALSE)

  list(train = data.frame(x = x, y = as.factor(y)) %>% slice(-test_index),
       test = data.frame(x = x, y = as.factor(y)) %>% slice(test_index))
}

使用 sapply 函数

mu_1 <- seq(0, 3)
dat_3<- sapply(mu_1,make_data)

我收到如下所示的错误报告。

createDataPartition(y, times = 1, p = 0.5, list = FALSE) 中的错误: y 必须至少有 2 个数据点。

【问题讨论】:

  • 第一次调用make_data 是用n=0,所以你有效地执行rbinom(0, 1, p),它返回一个长度为0 的向量。你希望如何在零数据上创建一个分区? (同样,1 是不够的,因为错误表明它需要 “至少 2 个数据点”。我会以 mu_1 &lt;- seq(2, 4) 或类似的开头。
  • 对于 mu1 为 0 或 1,您的函数将执行 ... createDataPartition(0, times = 1, p = 0.5, list = FALSE) ...,这似乎会引发错误。
  • @r2evans 那么我应该在 'sapply' 函数中再次定义所有参数吗?

标签: r function sapply


【解决方案1】:

出现您的错误是因为您的参数 mu_1mu_1 的位置匹配,而不是与 make_data 函数中的 mu_1 匹配,而是与 n 参数匹配。要将参数传递给函数中的“非第一个”参数,其中所有其他参数在定义中都有可接受的默认值,您需要将该“乱序”参数封装在匿名函数中,然后将其作为命名参数接受:

 library(dplyr) # for `%>%` and `slice`
 library(caret) # for createDataPartion
 # your code here
 dat_3<- sapply(mu_1, function(param) make_data(mu_1=param))  #succeeds

n 参数现在是您明确预期的 1000。

str(dat_3)
List of 8
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] 2.963 0.313 0.853 -1.154 -1.895 ...
  ..$ y: Factor w/ 2 levels "0","1": 1 1 2 2 1 2 2 1 2 2 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] -1.288 1.245 -0.109 -0.794 0.11 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 1 2 1 1 1 1 1 2 1 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] -0.686 1.823 -0.052 1.189 -0.318 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 2 1 1 1 1 1 2 1 1 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] -0.623 0.311 1.298 0.848 1.17 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 1 2 1 1 2 1 2 2 1 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] 0.956 0.825 1.592 2.729 -0.299 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 1 1 2 1 1 1 1 1 1 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] 1.92059 3.29866 0.00569 0.38111 0.41855 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 2 2 1 1 2 2 2 1 1 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] 4.572 3.19 -0.598 3.744 0.463 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 2 1 2 1 2 1 1 2 2 ...
 $ :'data.frame':   500 obs. of  2 variables:
  ..$ x: num [1:500] 2.7439 -0.0985 -0.4698 -1.2808 0.6663 ...
  ..$ y: Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
 - attr(*, "dim")= int [1:2] 2 4
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:2] "train" "test"
  ..$ : NULL

这消除了错误,但数据集没有得到您想要的名称。那是因为sapply 删除了它们,因为它的“简化”过程(即sapply 中的s)。您应该改用lapply。然后,这将为您提供命名数据帧,它们将嵌入您可以正确迭代的列表结构中,而不是来自 sapply 的“简化”结果:

  dat_3<- lapply(mu_1, function(x) make_data(mu_1=x))

我开始想我会通过部署traceback() 来回答这个问题,并展示如何调试并基本上扩展 cmets,但这让我无处可去。我意识到sapply/lapply 对命名对象的操作是问题的根源。这是一个让 R 的许多新老用户感到沮丧的绊脚石。只有值而不是名称被传递给函数。正确接受除第一个以外的任何参数的责任完全留给用户。甚至注定第一个参数的值的名称也无法通过。当你“说”lapply(obj_name, FUN) 时……原来FUN 没有得到obj_name,而只是得到eval(objname) 的结果。

【讨论】:

  • 成功了,感谢您的帮助。你救了我的道德:)
猜你喜欢
  • 2018-11-18
  • 2015-11-21
  • 2013-12-19
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 2020-12-02
相关资源
最近更新 更多