【问题标题】:Cumulative Sum Starting at Center of Data Frame - R从数据框中心开始的累积和 - R
【发布时间】:2014-07-03 22:20:24
【问题描述】:

我有这个data.framedum

   dummy <- data.frame(label = "a", x = c(1,1,1,1,0,1,1,1,1,1,1,1,1))
   dummy1 <- data.frame(label = "b", x = c(1,1,1,1,1,1,1,1,0,1,1,1,1))

   dum <- rbind(dummy,dummy1)

我要做的是在dumx 列中从 0 开始计算累积和。求和将按label 列分组,可以在dplyrplyr 中实现。我苦苦挣扎的部分是如何从x 中的0 位置开始累积和向外。

生成的data.frame 应如下所示:

 >dum
   label x output
1      a 1      4
2      a 1      3
3      a 1      2
4      a 1      1
5      a 0      0
6      a 1      1
7      a 1      2
8      a 1      3
9      a 1      4
10     a 1      5
11     a 1      6
12     a 1      7
13     a 1      8
14     b 1      8
15     b 1      7
16     b 1      6
17     b 1      5
18     b 1      4
19     b 1      3
20     b 1      2
21     b 1      1
22     b 0      0
23     b 1      1
24     b 1      2
25     b 1      3
26     b 1      4

这需要对数百万行数据进行数千次迭代。

像往常一样,感谢您的任何帮助

【问题讨论】:

    标签: r dataframe cumulative-sum


    【解决方案1】:

    您似乎只想找到到零的距离,而不是任何类型的累积总和。如果是这样的话,那么

    #find zeros for each group
    zeros <- tapply(seq.int(nrow(dum)) * as.numeric(dum$x==0), dum$label, max)
    
    #calculate distance from zero for each point
    dist <- abs(zeros[dum$label]-seq.int(nrow(dum)))
    

    这就给了

    cbind(dum, dist)
    
    #    label x dist
    # 1      a 1    4
    # 2      a 1    3
    # 3      a 1    2
    # 4      a 1    1
    # 5      a 0    0
    # 6      a 1    1
    # 7      a 1    2
    # 8      a 1    3
    # 9      a 1    4
    # 10     a 1    5
    # 11     a 1    6
    # 12     a 1    7
    # 13     a 1    8
    # 14     b 1    8
    # 15     b 1    7
    # 16     b 1    6
    # 17     b 1    5
    # 18     b 1    4
    # 19     b 1    3
    # 20     b 1    2
    # 21     b 1    1
    # 22     b 0    0
    # 23     b 1    1
    # 24     b 1    2
    # 25     b 1    3
    # 26     b 1    4
    

    甚至ave 会让你一步完成

    dist <- with(dum, ave(x,label,FUN=function(x) abs(seq_along(x)-which.min(x))))
    cbind(dum, dist)
    

    【讨论】:

    • 效果很好。在 2300 万行的 14000 块(本例中为 dum$label)的数据帧上只用了大约 5 分钟
    • 为了不浪费我现在删除的答案,这个函数对于一个组中的多个 0 的概括是:do.call(pmin,lapply(which(dum$x==0), function(n) abs(n-seq_along(dum$x)) ))
    【解决方案2】:

    您可以使用by 执行此操作,也可以使用plyrdata.table 等执行此操作。每个子集上使用的函数是

    f <- function(d) {
      x <- d$x
      i <- match(0, x)
      v1 <- rev(cumsum(rev(x[1:i])))
      v2 <- cumsum(x[(i+1):length(x)])
      transform(d, output = c(v1, v2))
    }
    

    在每个子集上调用它,例如与by

    res <- by(dum, list(dum$label), f)
    do.call(rbind, res)
    

    如果你想使用ddply

    library(plyr)
    ddply(dum, .(label), f)
    

    data.table 可能会更快

    library(data.table)
    dumdt <- as.data.table(dum)
    setkey(dumdt, label)
    dumdt[, f(.SD), by = key(dumdt)]
    

    【讨论】:

    • dum[,abs(which.min(x) - seq_along(x)),by=label] 将是一个更简单的 data.table 方法。
    • 很公平,如果x 始终为0 或1,@MrFlick 的方式要好得多。这在OP 中没有明确说明,所以我选择了cumsum
    【解决方案3】:

    使用dplyr

    library(dplyr)
    dum%>% 
    group_by(label)%>% 
    mutate(dist=abs(row_number()-which.min(x)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-30
      • 2016-02-19
      相关资源
      最近更新 更多