【问题标题】:Collapsing rows on condition and re-using their values in R根据条件折叠行并在 R 中重新使用它们的值
【发布时间】:2018-03-05 14:16:45
【问题描述】:

我有一个非常简单的问题,它似乎没有一个非常简单的解决方案。假设我有以下数据:

> test <- data.frame(Day = c(1:10), Counts = c(0, 0, 6, 0, 0, 5, 1, 0, 3, 4))
> test
   Day Counts
1    1      0
2    2      0
3    3      6
4    4      0
5    5      0
6    6      5
7    7      1
8    8      0
9    9      3
10  10      4

根据对数据来源​​的了解,我可以安全地假设非零 计数 不会在随后的几天发生。而是在最初的Day 中遗漏了一些计数。例如,第 6 天和第 7 天的 Counts 将属于 Day 6(总共有 6 个 Counts) .

我想找到一个可以产生这种期望输出的常规解决方案:

  Day Counts
1   1      0
2   2      0
3   3      6
4   4      0
5   5      0
6   6      6
7   8      0
8   9      7

注意Day第 7 天和第 10 天是如何被删除的,并且它们的 Counts 已添加到Day第 6 天和第 9 天的计数中。这确实是我后续分析数据所需的格式,它会受到“错误”计数的影响。

我已经使用zooRcppRoll 包中的函数以及使用dplyrs lag() 的所谓tidy 解决方案尝试了多种“移动/滚动窗口”方法和lead() 函数,但没有Heureka!迄今。由于我的数据集包含数十万行(以及更多列),因此非常不希望手动更正。

感谢任何帮助!即使它只是指向一个现有的问题......

p.s.:显示 tidyverse 解决方案的奖励积分,因为我打算在管道工作流程中使用它。

编辑:感谢您的解决方案,它们都可以完美运行!让我开心:)

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    leadlag 当然是一种方法。

    test %>%
      mutate(lead1 = lead(Counts, 1), lag1 = lag(Counts)) %>% 
      mutate(Counts2 = if_else(Counts > 0, Counts + lead1, Counts)) %>% 
      filter(!(lag1 > 0 & Counts > 0))
    

    代码可以缩短为

    test %>%
      mutate(Counts = if_else(Counts > 0, Counts + lead(Counts, 1), Counts)) %>% 
      filter(!(lag(Counts) > 0 & Counts > 0))
    
      Day Counts
    1   1      0
    2   2      0
    3   3      6
    4   4      0
    5   5      0
    6   6      6
    7   8      0
    8   9      7
    

    【讨论】:

      【解决方案2】:

      另一种基于laglead 的简单dplyr 方法:

      test %>%
        mutate(Counts = ifelse(Counts != 0 & lead(Counts) != 0,
                               Counts + lead(Counts), Counts)) %>%
        mutate(Counts = ifelse(Counts != 0 & lag(Counts) != 0, NA, Counts)) %>%
        na.omit()
        Day Counts
      1   1      0
      2   2      0
      3   3      6
      4   4      0
      5   5      0
      6   6      6
      8   8      0
      9   9      7
      

      【讨论】:

        【解决方案3】:

        1) 这使用了 data.table 包。首先将 test 转换为 data.table dt,然后使用 rleid 创建一个分组变量,该变量为每次运行的零或非零创建一个组。对于每个这样的组,返回计数的总和,后跟零:

        library(data.table)
        dt <- as.data.table(test)
        
        dt[, Fix := c(sum(Counts), 0 * Counts[-1]), by = rleid(Counts > 0)]
        

        给予:

        > dt
            Day Counts Fix
         1:   1      0   0
         2:   2      0   0
         3:   3      6   6
         4:   4      0   0
         5:   5      0   0
         6:   6      5   6
         7:   7      1   0
         8:   8      0   0
         9:   9      3   7
        10:  10      4   0
        

        2) 这使用 dplyr 和来自 data.table 的 rleid

        library(dplyr)
        library(data.table)
        
        test %>%
             group_by(rleid(Counts > 0)) %>%
             mutate(Fix = c(sum(Counts), 0 * Counts[-1])) %>%
             ungroup
        

        【讨论】:

          猜你喜欢
          • 2020-07-08
          • 2019-06-28
          • 1970-01-01
          • 1970-01-01
          • 2016-02-03
          • 1970-01-01
          • 2020-02-17
          • 2022-01-23
          • 1970-01-01
          相关资源
          最近更新 更多