【问题标题】:R: How to sum values from rows only if the key value is the same and also if the key duplicated in consecutive rows?R:只有当键值相同并且键在连续行中重复时,如何对行中的值求和?
【发布时间】:2015-08-31 10:01:01
【问题描述】:

我有下面这个结构的数据表:

+-------------------+
| id  | key | value |
+-----+-----+-------+
| 1   | A   | 1000  |
| 1   | A   | 2000  |
| 1   | B   | 2001  |
| 1   | A   | 2002  |
| 1   | A   | 2004  |
| 2   | B   | 2002  |
| 2   | C   | 2002  |
+-------------------+

我的目标是按 id 和 key 对值进行求和,但不是仅按 id 和 key 分组,我只想对连续行的 id 和 key 对相同的值求和。

结果应该是:

+-------------------+
| id  | key | value |
+-----+-----+-------+
| 1   | A   | 3000  |
| 1   | B   | 2001  |
| 1   | A   | 4006  |
| 2   | B   | 2002  |
| 2   | C   | 2002  |
+-------------------+

有没有办法达到这个效果?

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我们可以使用data.table中的rleid

    我们将“data.frame”转换为“data.table”。从“key”列创建另一个分组列“ind”。按'id'和'ind'分组,我们得到'value'的sum,得到'key'的第一个元素。我们可以将 'ind' 分配给 NULL,因为它在预期的输出中不需要。

    library(data.table)
    setDT(df1)[,list(value = sum(value), key=key[1L]),
                        by = .(ind=rleid(key), id)][, ind:=NULL][]
    #   id value key
    #1:  1  3000   A
    #2:  1  2001   B
    #3:  1  4006   A
    #4:  2  2002   B
    #5:  2  2002   C
    

    或者按照@Frank的建议,我们可以在rleid中使用多个列,将其用作分组变量,获取其他变量的第一个元素和'value'的sum,将不需要的列分配给NULL避免复制。

    setDT(df1)[, list(id=id[1L], key=key[1L], value=sum(value)) ,
            by = .(r=rleid(id, key))][, r:= NULL][]
    #   id key value
    #1:  1   A  3000
    #2:  1   B  2001
    #3:  1   A  4006
    #4:  2   B  2002
    #5:  2   C  2002
    

    或者我们可以使用dplyr。我们通过比较'key'的相邻元素来创建分组变量'ind',并得到'value'的sum和'key'的first元素与summarise

    library(dplyr)
    df1 %>%
         group_by(ind= cumsum(key!=lag(key, default=TRUE)), id) %>%
         summarise(value=sum(value), key=first(key)) %>% 
         ungroup() %>%
         select(-ind)
    #  id value key
    #1  1  3000   A
    #2  1  2001   B
    #3  1  4006   A
    #4  2  2002   B
    #5  2  2002   C
    

    注意:在dplyrdata.table 中,我们还可以将“key”列作为分组变量并删除key=key[1L]key=first(key))


    或者我们通过创建“ind”列来transform 数据集并使用base R 中的aggregate 来获得预期的输出

    df1 <- transform(df1, ind = cumsum(c(TRUE,head(key,-1)!=tail(key,-1))))
    aggregate(value~., df1, FUN=sum)[-3]
    #  id key value
    #1  1   A  3000
    #2  1   B  2001
    #3  1   A  4006
    #4  2   B  2002
    #5  2   C  2002
    

    数据

    df1 <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L), key = c("A", 
    "A", "B", "A", "A", "B", "C"), value = c(1000L, 2000L, 2001L, 
    2002L, 2004L, 2002L, 2002L)), .Names = c("id", "key", "value"
    ), class = "data.frame", row.names = c(NA, -7L))
    

    【讨论】:

    • 你似乎依赖于id..的排序?对于它的价值,rleid 可以接受两个参数,解决这个问题:DT[, .(id=id[1],key=key[1],value=sum(value)), by=.(r=rleid(id,key))][,!"r",with=FALSE]
    • @Frank 谢谢。我没有对其进行基准测试,希望您的方法有效。
    • (不是很重要:)我没有考虑效率,只是逻辑连贯性——将“如果连续行的 id 和 key 对相同”转换为代码。我不确定它是否应该更有效。
    猜你喜欢
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2014-02-26
    相关资源
    最近更新 更多