什么可以替代R中的嵌套循环

时间:2018-01-16 21:08:48

标签: r nested-loops lapply

我想通过运行给定两个变量outputinput的多个方案,从R中的数据框x创建数据框y。列outputvaluexcol < x & ycol < y中所有值的总和。

input =
xcol ycol value
1   5   4
2   6   9
3   7   8
4   9   7
5   14  8

output= 
x   y   results
2   5   0
2   10  4
2   15  35
...
6   5   0
6   10  27
6   15  35

我的代码目前是这样的:

for (x in 2:6) {
  if (x%% 2){
    next
  }
  for (y in 5:15) {
    if (y %% 5){
      next
    }
    print(x)
    print(y)
    print(sum(input$value[!is.na(input$xcol) & !is.na(input$ycol) & !is.na(input$value) & 
              input$xcol < x &  input$ycol < y]))
  }
}

应该有一种更好的方法来使用lapply&amp;更换这个嵌套循环。我想,应该创造一个数据帧。我很感激任何帮助。

由于

2 个答案:

答案 0 :(得分:1)

在某种意义上,这似乎更像是一个实验设计,您可以迭代xy的不同可能值。

xs <- 2:6
ys <- 5:15
eg <- expand.grid(x = xs, y = ys)
head(eg)
#   x y
# 1 2 5
# 2 3 5
# 3 4 5
# 4 5 5
# 5 6 5
# 6 2 6

我认为您的%%过滤应该在此之前/之前完成,所以:

xs <- xs[!xs %% 2]
ys <- ys[!ys %% 5]
eg <- expand.grid(x = xs, y = ys)
head(eg)
#   x  y
# 1 2  5
# 2 4  5
# 3 6  5
# 4 2 10
# 5 4 10
# 6 6 10

从这里开始,您可以遍历行:

eg$out <- sapply(seq_len(nrow(eg)), function(r) {
  sum(input$value[ complete.cases(input) & input$xcol < eg$x[r] & input$ycol < eg$y[r] ])
})
eg
#   x  y out
# 1 2  5   0
# 2 4  5   0
# 3 6  5   0
# 4 2 10   4
# 5 4 10  21
# 6 6 10  28
# 7 2 15   4
# 8 4 15  21
# 9 6 15  36

我认为你的output变量有点偏差,因为&#34; 2,15&#34;应该只包含input$value[1]x < 2是限制因素)。 (存在其他差异。)

无论您的实际索引逻辑是什么,我建议使用此方法,而不是for或双 - lapply实现。

NB:

  1. 这些命令在功能上等同于此input

    complete.cases(input)                                         # 1
    complete.cases(input[c("xcol","ycol","value")])               # 2
    !is.na(input$xcol) & !is.na(input$xcol) & !is.na(input$value) # 3
    

    我使用了第一个&#34;代码高尔夫&#34;,但如果您的实际input data.frame包含其他列,您可能更喜欢第二个更有选择性地选择哪些列非{ {1}}值。

  2. NA非常适合此类扩展。但是,如果您正在查看明显更大的数据集(包括您的过滤是否比expand.grid提供的更复杂),那么它可能有点贵,因为它必须在内存中创建整个%%。 Python在这里使用惰性迭代器会很有用,在这种情况下,您可能更喜欢使用https://stackoverflow.com/a/36144255/3358272(github gist中的扩展函数和一些文档:https://gist.github.com/r2evans/e5531cbab8cf421d14ed)。

    < / LI>

答案 1 :(得分:0)

这不是最优雅的解决方案,但你可以用lapply替换for循环:

lapply (2:6, function(x) {
  if (x%% 2){
    next
  }
  lapply (5:15, function(y) {
    if (y %% 5){
      next
    }
    print(x)
    print(y)
    print(sum(input$value[!is.na(input$xcol) & !is.na(input$ycol) & !is.na(input$value) & 
              input$xcol < x &  input$ycol < y]))
  })
})