【问题标题】:For loop in R that calculates for the group and then the componentsR中的for循环计算组,然后计算组件
【发布时间】:2016-10-05 12:20:42
【问题描述】:

我有一组数据和一个循环,其中包含数据集的大量计算,其中该组的各个组件被分成一个子集并一个一个地循环。但是,我首先需要能够对整个原始数据集执行相同的计算。

对于一个名为 masterdata 的虚构数据集,它包含 3 个组件(D1 列)和许多变量 (X2-X10):

# masterdata
#   D1 X2 X3 X4 X5 X6 X7 X8 X9 X10
#   A  NA NA NA NA NA NA NA NA  NA
#   B  NA NA NA NA NA NA NA NA  NA
#   C  NA NA NA NA NA NA NA NA  NA
#   B  NA NA NA NA NA NA NA NA  NA
#   B  NA NA NA NA NA NA NA NA  NA
#   C  NA NA NA NA NA NA NA NA  NA
#   C  NA NA NA NA NA NA NA NA  NA
#   A  NA NA NA NA NA NA NA NA  NA
#   B  NA NA NA NA NA NA NA NA  NA
#   A  NA NA NA NA NA NA NA NA  NA

有一个循环来拆分组件 A 的子集,执行计算,输出结果,然后对 B 和 C 重复此操作:

Component.List = c("A", "B", "C")

for(k in 1:length(Component.List)) {        
      subdata = subset(masterdata, D1 == Component.List[k])
      # Numerous calculations performed on "subdata" within the loop
}
# End of loop

我要做的是最初对整个masterdata 执行相同的大量计算,然后开始循环遍历各个组件。

计算的部分输出是创建的两个向量被放置在执行循环之前创建的数据帧的第一列中:

# Prior to the start of the loop two frames below created
Components = 3 # In this example 3 components in column D1 - "A", "B", "C"

Result.Frame.V1 = as.data.frame(matrix(0, nrow = 200, ncol = Components))
Result.Frame.V2 = as.data.frame(matrix(0, nrow = 200, ncol = Components))

# Loop runs and contains all of the calculations and within the calculations the last two  
# lines below place two vectors generated into the the kth columns of the frames.

Result.Frame.V1[,k] = V1.Result
Result.Frame.V2[,k] = V2.Result

# First run of the loop for "A" will place the outputs in the 1st columns 
# Second run of the loop for "B" will place the outputs in the 2nd columns, etc.
# With the expansion to also calculate against the whole group, the above data frames
# would be expanded to an extra column that would hold the result vector for the whole 
# masterdata run through the calculations 

我最初的理论解决方案是为masterdata编写一次循环中的每个计算,然后进行上述循环,但是计算是数百行代码!

是否可以在 For 循环中加入一种计算原始数据的方法,然后继续循环遍历组件?

【问题讨论】:

  • 为什么不把所有的计算都封装到一个单独的函数中,依次传递data.frames给它,masterdata,ComponentA,ComponentB等等
  • 不需要for 循环。按组件split(masterdata, masterdata$D1) 将数据框拆分为列表,然后使用lapply/sapply 对每个列表条目执行计算。使用do.call(rbind, ...) 绑定任何生成的数据帧(如有必要)。
  • 您希望从函数或数据帧中获取向量吗? e.i 1 行 vs 多行?
  • @JonnoBourne 在计算中,有从中输出的向量和数据帧。

标签: r loops for-loop subset


【解决方案1】:

似乎dplyr 可以优雅地解决这个问题,以及其他选项

对于整个数据:

library(dplyr)  
masterdata %>%
  summarise(result = your_function(arg1 = X1, arg2 = X2, ...))

对于每个组件,只需添加group_by

masterdata %>%
  group_by(D1) %>%
  summarise(result = your_function(arg1 = X1, arg2 = X2, ...))

【讨论】:

  • 如果your_function 需要创建新列怎么办? (purrr::map 或许?)
  • @jakub 绝对!对原始问题的很好补充。
  • 如果your_function() 创建一个单独的列,您只需要mutate,不需要purrr::map_*(例如group_by(mtcars, cyl) %>% mutate(newmu=mean(vs)));如果它创建了多个列,您也许可以使用bind_cols
  • @r2evans 真的只有bind_cols?你能举个例子吗?
  • 按原样做作:group_by(mtcars, cyl) %>% do(bind_cols(., data.frame(x=rep(mean(.$vs), nrow(.)))));行数必须相同,但可以是任意列数。
【解决方案2】:

如果您要输出数据帧,那么创建一个函数,在传递数据帧时执行您的计算,并输出数据帧将是关键。在下面的示例中,该函数称为your_function()

为简单起见,使用了三阶段过程,首先在整个数据集上创建输出数据框,然后 lapply 对子数据集执行相同的计算。然后将子数据集绑定到一个数据帧中,最后与完整数据集的输出相结合。

注意:我创建了一个名为“子集”的新变量,以便所有输出都可以识别为属于每个不同的集合。

library(dplyr)
FullSet <- your_function(masterdata) %>% mutate(Subset = "Full")

SubSets <- lapply(unique(D1), function(n){
    masterdata %>% filter(D1 == n) %>%
      your_function(.) %>% mutate(Subset = n)
  }) %>% bind_rows()

FinalSet <- bind_rows(FullSet, SubSets)

如果您想并行运行该过程以提高速度,请使用

mclapply(unique(D1), function..., mc.cores=detectCores())

【讨论】:

  • 在上面的示例中,MasterFunc 应该是第一个数据框的名称吗?我只是有点困惑为什么它被分配&lt;- your_function(MasterFunc);我的假设是 masterdata 被输入到函数输入中。感谢您提供的任何详细说明,谢谢!
  • 对不起,这绝对是令人困惑的希望这个答案更清楚。我认为值得考虑需要哪些计算,就像您可以使用 summarise 一样,然后@JohnSG 的答案将提供一个非常好的解决方案。
【解决方案3】:

正如@Ossan 建议的那样:

  1. 将代码包装在一个函数中

  2. 调用超级简单的for 循环(或lapply,由@Maurits Evers 建议)

如何:

humongous_function = function(data) {
  //All the code you have written to do on 'data'
  result
}

Result.List = list()

for(k in c("A", "B", "C")) {        
  subdata = subset(masterdata, D1 == k)
  Result.List[[k]] = humongous_function(subdata)
}

【讨论】:

  • @Ossan 感谢您的回答,我可以看到您建议的代码将如何为每个组件运行计算,但我有点困惑这将如何完成整个原始数据?能详细点吗,谢谢?
猜你喜欢
  • 2020-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 2019-06-17
  • 2017-05-21
  • 1970-01-01
相关资源
最近更新 更多