【问题标题】:How do I access a second sub-element within a list and pass it to *apply?如何访问列表中的第二个子元素并将其传递给 *apply?
【发布时间】:2014-11-26 21:08:14
【问题描述】:

给定一个包含 72 个元素(dataset_1dataset_2 等)的列表(list.data.partitions),每个元素包含两个子元素(2 个数据帧):$training$testing;例如:

> str(list.data.partitions$dataset_1)
List of 2
 $ training:'data.frame':   81 obs. of  20 variables:
  ..$ b0   : num [1:81] 11.61 9.47 10.61 7.34 12.65 ...
  ..$ b1   : num [1:81] 11.6 9.94 10.7 10.11 12.2 ...
  ..$ b2   : num [1:81] 34.2 31 32.7 27.9 36.1 ...
  ...
  ..$ index: num [1:81] 0.165 0.276 0.276 0.181 0.201 ...

 $ testing :'data.frame':   19 obs. of  20 variables:
  ..$ b0   : num [1:19] 6.05 12.4 13.99 16.82 8.8 ...
  ..$ b1   : num [1:19] 12.4 10.8 11.8 13.7 16.3 ...
  ..$ b2   : num [1:19] 25.4 29.8 31.2 34.1 27.3 ...
  ...
  ..$ index: num [1:19] 0.143 1.114 0.201 0.529 1.327 ...

如何使用 lapply(或类似功能)和插入符号的 predict 函数正确访问 $testing 数据框:

    fun.predict.rf <- function(x, y) {
      predict(x, newdata = y$testing)
    }

    list.predictions <- lapply(list.models, fun.predict.rf, y=list.data.partitions)

上述函数“有效”,但它返回基于$training 数据帧(~80 obs)的预测,而不是指定的$testing 数据帧(~20 ob​​s)。最终,我希望一个列表包含我列表中每个元素的预测,基于 $testing 数据框。

list.models 是基于 $training 数据框的 72 个模型的列表,使用 R 中的 caret 包(未显示或包含)。在考虑单个子元素($training$testing)时,list.models 中的模型数 (72) 等于 list.data.partitions 中的元素数 (72)。 list.data.partitions 中 72 个元素的名称各不相同:dataset_1dataset_2 等,但结构相同(参见上面的 str 输出)。

list.data.partitions可以下载here。在这个版本中,这 72 个元素没有名称,但在我的版本中,这 72 个元素被命名(例如,dataset_1dataset_2 等)。每个子元素仍然命名为$training$testing

【问题讨论】:

  • 你的电话不需要y=list.data.partitions$dataset_1而不是y=list.data.partitions吗?这就是为什么它不起作用。我无法从该文件中提取数据,顺便说一句
  • 我知道你在做什么,但是如果我将y=list.data.partitions$dataset_1 硬编码到调用中,那么model.list 中的 72 个模型中的每一个都会调用该特定数据集,而我想要每个要在每个元素的 $testing 数据帧上运行的模型。 list.data.partitions$[each of the 72 elements]$testing 之类的东西是我想要的,但我找不到正确的语法。我使用save(list.data.partitions, file = "/file/path") 来保存对象,所以它可能必须加载到 R 中。
  • 我改变了我的答案。我想现在会更好
  • 我可能错了,但这里似乎最简单的解决方案是使用mapply。如果您将函数调用更改为:list.predictions &lt;- mapply(fun.predict.rf, list.models, list.data.partitions),我认为您应该会得到想要的结果。
  • @Cotton.Rockwood - 呃……该死的。这很有效,而且很简单。你能写出这个答案以及为什么它比使用 lapply 有效吗?

标签: r lapply r-caret


【解决方案1】:

你可以在apply中声明函数。

在我仔细阅读问题后,这可能会起作用。 假设您有以下数据结构

list.data.partitions
  ..$dataset_1
    ..$training
    ..$testing
    ..$model # model created using the caret package

  ..$dataset_2
    ..$training
    ..$testing
    ..$model # model created using the caret package

让我们将 $model 添加到数据集,因为它是一对一的关系。把它们放在一起是有意义的。我假设你从 $training 构建模型,然后在 $test 上进行测试。

for(i in 1:len(list.data.partitions){
  list.data.partitions[[i]]$model <- list.models[[i]]
}

假设数据集 1 和 2 不相关,并且每个数据集有 3 个元素(训练、测试、训练中的模型,稍后会详细介绍)

​​>
fun.predict.rf <- function(x, y) {
      predict(x, newdata = y)
}
lapply(list.data.partitions, function(x){

  #something like
  #if no model exist yet, then you can create it here with x$training
  result<- fun.predict.rf(x$model, x$testing)
  #other things you want to do

})

【讨论】:

  • fun.predict.rf(x) 未在您的答案中定义。另外,我不完全清楚为什么output 将由trainingtesting 组成。我只想使用后者。你能提供更多细节吗?
  • 没有$model 子元素,只有$training$testing。模型存储在一个名为model.list 的列表中,该列表由lapply 调用。
【解决方案2】:

我相信简单的解决方案是使用mapply 而不是lapply。或者,您可以将模型对象与 trainingtesting 数据集存储在同一列表中,并按照 Steven 的建议使用 lapply。使用带有列表名称的 Richard Scriven 示例数据集的修改版本:

set.seed(1)
dataset <- list(training = data.frame(replicate(4, rnorm(10))),
                testing = data.frame(replicate(4, rexp(5))))
dataset1 <- list(training = data.frame(replicate(4, rnorm(10))),
                 testing = data.frame(replicate(4, rexp(5))))
dataset2 <- list(training = data.frame(replicate(4, rnorm(10))),
                testing = data.frame(replicate(4, rexp(5))))
list.data.partitions <- c(replicate(2, dataset, simplify = FALSE),list(dataset1), list(dataset2))
names(list.data.partitions) <- paste0("dataset", seq(list.data.partitions))  

这给出了一个列表,其中包含两个相同的数据集,后跟两个唯一的数据集,用于说明目的。 然后,创建具有基本线性拟合的模型对象列表:

list.models <- lapply(list.data.partitions, function(x) lm(X1 ~ X2+X3+X4, data = x$training))

对于这两个对象,使用mapply

fun.predict.rf <- function(x, y) {
     predict(x, newdata = y$testing)
 }

list.predictions <- mapply(fun.predict.rf, list.models, list.data.partitions)
list.predictions

      dataset1     dataset2    dataset3   dataset4
1 -0.098696452 -0.098696452  0.09015207 -0.5004038
2  0.103316974  0.103316974  0.11770013 -0.7323202
3 -0.908623491 -0.908623491 -0.06951799 -0.8765770
4 -1.332241452 -1.332241452 -0.20407761 -0.5816534
5 -0.002156741 -0.002156741 -0.24583670 -0.7057936

请注意,前两个数据集的预测与我们预期的相同,每个数据集有五个预测元素,与测试元素的数量一致。

我认为存在一些混淆,因为在您的问题中不清楚您的模型对象是否存储在单独的列表中 (list.models)。由于您传递了lapplylist.models,但指定了y=list.data.partitions,因此您的函数fun.predict.rf 将按顺序传递每个模型元素,但每次调用都会传递整个list.data.partitions。没有元素list.data.partitions$testing,因此您实际上指定了newdata = NULL,因此预测函数忽略了newdata 参数并使用来自模型对象的数据。请注意,如果您使用 lapply 代码并与各个训练元素的预测进行比较,它们匹配:

list.predictions <- lapply(list.models, fun.predict.rf, y=list.data.partitions)
list.predictions

predict(model.list[[1]], newdata=list.data.partitions[[1]]$training)
predict(model.list[[2]], newdata=list.data.partitions[[2]]$training)
predict(model.list[[3]], newdata=list.data.partitions[[3]]$training)
predict(model.list[[4]], newdata=list.data.partitions[[4]]$training)

如果您更改list.data.partitions 中的数据,lapply 调用仍会给出相同的结果,而指定list.data.partitions$training 数据会给出不同的结果:

list.data.partitions[[1]] <- list.data.partitions[[3]]
lapply(list.models, fun.predict.rf, y=list.data.partitions)

predict(list.models[[1]], newdata=list.data.partitions[[1]]$training)

【讨论】:

    猜你喜欢
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多