【问题标题】:Conditional grouping and summarizing data frame in [R][R]中的条件分组和汇总数据框
【发布时间】:2015-05-27 16:06:03
【问题描述】:

我有一个这样的数据框:

df <- data.frame(ID = c("A", "A", "B", "B", "C", "C"), 
                 time = c(3.1,3.2,6.5,12.3, 3.2, 3.4), 
                 intensity = c(10, 20, 30, 40, 50, 60))
|身份证号|时间|强度| |:--|----:|---------:| |一个 | 3.1| 10| |一个 | 3.2| 20| |B | 6.5| 30| |B | 12.3| 40| |C | 3.2| 50| |C | 3.4| 60|

我只想在时差小于 0.3 时按 ID 聚合值(总强度)。首先我计算了这个时间差:

df.2 <- df %>% 
        group_by(ID) %>% 
        mutate(time.diff = max(time) - min(time)) 

...导致:

|身份证号|时间|强度|时间.diff| |:--|----:|---------:|---------:| |一个 | 3.1| 10| 0.1| |一个 | 3.2| 20| 0.1| |B | 6.5| 30| 5.8| |B | 12.3| 40| 5.8| |C | 3.2| 50| 0.2| |C | 3.4| 60| 0.2|

为了清楚起见,我希望得到的输出是:

|身份证号|时间|强度|时间.diff| |:--|----:|---------:|---------:| |一个 | 3.15| 30| 0.1| |B | 6.5| 30| 5.8| |B | 12.3| 40| 5.8| |C | 3.3| 110| 0.2|

现在时间是综合观察的平均值,强度是它们的总和。 ID“B”保留两个观测值,因为它的时间差大于 0.3。我已经尝试过使用 dplyr,但 summarise 总是会删除“B”的观察结果之一,我想保留它们,但我不知道如何进行 条件 em> _group_by_。

感谢您的任何想法!

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    data.table 的可能选项

    library(data.table)
    unique(setDT(df)[, time.diff := max(time)-min(time), ID][
       time.diff <= 0.3, c('time', 'intensity') := list(mean(time),
            sum(intensity)), ID]) 
    #    ID  time intensity time.diff
    #1:  A  3.15        30       0.1
    #2:  B  6.50        30       5.8
    #3:  B 12.30        40       5.8
    #4:  C  3.30       110       0.2
    

    或使用dplyr

    library(dplyr)
    df %>% 
       group_by(ID) %>%
       mutate(time.diff=max(time)-min(time), indx=all(time.diff<=0.3),
             intensity=ifelse(indx, sum(intensity), intensity),
             time=ifelse(indx, mean(time), time)) %>% 
       filter(!indx|row_number()==1) %>%
       select(-indx)
     #  ID  time intensity time.diff
     #1  A  3.15        30       0.1
     #2  B  6.50        30       5.8
     #3  B 12.30        40       5.8
     #4  C  3.30       110       0.2
    

    【讨论】:

    • @VeerendraGadekar 更正了输出。再次感谢 cmets。
    • @Arun 是的,它更适合作为单独的答案
    • @Arun 和 acrun,你们的两个解决方案都很棒!我想我会使用 dplyr 解决方案,因为我更习惯它——通常我觉得它更具可读性,但在这种情况下我必须说 data.table解决方案看起来比 dplyr 更简单。感谢您的大力帮助!
    【解决方案2】:

    data.table 解决方案的另一种变体:

    setDT(df)[, time.diff := max(time) - min(time), by = ID
            ][, if (time.diff <= 0.3) 
                    .(time = mean(time), intensity = sum(intensity))
                else .SD, by = .(ID, time.diff)]
    #    ID time.diff  time intensity
    # 1:  A       0.1  3.15        30
    # 2:  B       5.8  6.50        30
    # 3:  B       5.8 12.30        40
    # 4:  C       0.2  3.30       110
    

    【讨论】:

    • could not find function "." 我需要升级我的data.table吗?
    • 糟糕.. 将其替换为list() 而不是.()。它在v1.9.5+ 中实现.. 或者从here 安装data.table 的开发版本。跨度>
    【解决方案3】:
    # get time.diff
    df$time.diff <- ave(x = df$time,df$ID,FUN = function(x){max(x)-min(x)})
    
    # new split variable to use with ID
    df$cut <- cumsum(df$time.diff > .3)
    
    # aggregate everything you need and ignore the cut variable
    require(plyr)
    ddply(df,c('cut','ID'),summarize,
          time = mean(time),
          intensity = sum(intensity),
          time.diff = mean(time.diff))[2:5]
    

    【讨论】:

      【解决方案4】:

      使用sqldf

      library(sqldf)
      sqldf('SELECT ID, AVG(time) time, SUM(intensity) intensity, (MAX(time)-MIN(time)) dif FROM df 
               GROUP BY ID 
               HAVING (MAX(time)-MIN(time))<0.3
               UNION
               SELECT ID, df.time, df.intensity, df2.dif
               FROM (SELECT ID, AVG(time) time, SUM(intensity) intensity, (MAX(time)-MIN(time)) dif
               FROM df 
               GROUP BY ID 
               HAVING (MAX(time)-MIN(time))>0.3) as df2
               LEFT JOIN df USING (ID)')
      

      输出:

        ID  time intensity dif
      1  A  3.15        30 0.1
      2  B  6.50        30 5.8
      3  B 12.30        40 5.8
      4  C  3.30       110 0.2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多