【问题标题】:Shift one row by ID in R在R中按ID移动一行
【发布时间】:2016-07-30 17:00:37
【问题描述】:

我有数据框,我想创建一个新变量“Begin1”,条件是:如果变量“Begin”的第二行小于第一行的变量“End”,则设置“End”的值替换“Begin” " 由于 ID 重叠

ID <- c(rep(1,3), rep(3, 5), rep(4,4))
Begin <- c(0,2.5,5, 7,8,7,25,25,10,15,17,20)
End <- c(1.5,3.5,6, 7.5,8,11,29,35, 12,19,21,28)
df <- data.frame(ID, Begin, End)
df
    ID Begin  End
1   1   0.0  1.5
2   1   2.5  3.5
3   1   5.0  6.0
4   3   7.0  7.5
5   3   8.0  8.0
6   3   7.0 11.0**
7   3  25.0 29.0
8   3  25.0 35.0**
9   4  10.0 12.0
10  4  15.0 19.0
11  4  17.0 21.0**
12  4  20.0 28.0**

如果你能看到,行加粗,行 (6,8,11,12)。从 ID 3 的第 6 行开始,您会看到“Begin” = 7.0,它比上一行的“End”小,现在我们设置“Begin1” = 8.0。对于 ID 为 3 的第 8 行,“Begin”=25,它小于之前的“End”=29,现在我们设置“Begin1”=29,依此类推。这是输出

   ID Begin Begin1  End
1   1   0.0    0.0  1.5
2   1   2.5    2.5  3.5
3   1   5.0    5.0  6.0
4   3   7.0    7.0  7.5
5   3   8.0    8.0  8.0
6   3   7.0    8.0 11.0**
7   3  25.0   25.0 29.0
8   3  25.0   29.0 35.0**
9   4  10.0   10.0 12.0
10  4  15.0   15.0 19.0
11  4  17.0   19.0 21.0**
12  4  20.0   21.0 28.0**

感谢您的建议

这里是更新

ID <- c(rep(1,3), rep(3, 5), rep(4,4))
Group <-c(1,1,2,1,1,1,2,2,1,1,1,2)
Begin <- c(0,2.5,5, 7,8,7,25,25,10,15,17,20)
End <- c(1.5,3.5,6, 7.5,8,11,29,35, 12,19,21,28)
df <- data.frame(ID,Group, Begin, End)

这次我想按 ID 和 Group 分组,我从 data.table 得到错误。

这是输出

   ID Group Begin  End Begin1
1   1   1   0.0  1.5    0.0
2   1   1   2.5  3.5    2.5
3   1   2   5.0  6.0    5.0
4   3   1   7.0  7.5    7.0
5   3   1   8.0  8.0    8.0
6   3   1   7.0 11.0    8.0
7   3   2  25.0 29.0   25.0
8   3   2  25.0 35.0   29.0
9   4   1  10.0 12.0   35.0
10  4   1  15.0 19.0   15.0
11  4   1  17.0 21.0   19.0
12  4   2  20.0 28.0   20.0**** Right here is not change bc it's group 2

这是 dplyr 包的结果,它可以工作,但 data.table 不工作

library(dplyr)
df %>%
  group_by(ID, Group) %>% 
  mutate(Begin1 = pmax(Begin, lag(End), na.rm =TRUE))

Source: local data frame [12 x 5]
Groups: ID, Group [6]

      ID Group Begin   End Begin1
    (dbl) (dbl) (dbl) (dbl)  (dbl)
1      1     1   0.0   1.5    0.0
2      1     1   2.5   3.5    2.5
3      1     2   5.0   6.0    5.0
4      3     1   7.0   7.5    7.0
5      3     1   8.0   8.0    8.0
6      3     1   7.0  11.0    8.0
7      3     2  25.0  29.0   25.0
8      3     2  25.0  35.0   29.0
9      4     1  10.0  12.0   10.0
10     4     1  15.0  19.0   15.0
11     4     1  17.0  21.0   19.0
12     4     2  20.0  28.0   20.0**** It works

【问题讨论】:

    标签: r dataframe shift


    【解决方案1】:

    使用data.table 的另一种方式。键如下。

    • by 通过 ID 进行计算的语句
    • shift 函数,它滞后于 End 变量与 Begin 进行比较
    • pmax 函数,对元素进行 max 计算

    代码如下:

    library(data.table)
    dt <- as.data.table(df)
    dt[, Begin1 := pmax(Begin, shift(End, type = 'lag'), na.rm = TRUE), by = ID]
    

    【讨论】:

      【解决方案2】:

      这是一种使用基于End 列的lagifelse 创建列的方法。

      df$Begin1 <- ifelse(df$Begin <= lag(df$End), lag(df$End), df$Begin)
      df$Begin1[which(is.na(df$Begin1))] <- df$Begin[which(is.na(df$Begin1))]
      
      > df
         ID Begin  End Begin1
      1   1   0.0  1.5    0.0
      2   1   2.5  3.5    2.5
      3   1   5.0  6.0    5.0
      4   3   7.0  7.5    7.0
      5   3   8.0  8.0    8.0
      6   3   7.0 11.0    8.0
      7   3  25.0 29.0   25.0
      8   3  25.0 35.0   29.0
      9   4  10.0 12.0   35.0
      10  4  15.0 19.0   15.0
      11  4  17.0 21.0   19.0
      12  4  20.0 28.0   21.0
      

      【讨论】:

        【解决方案3】:

        我们可以使用data.table 来做到这一点

        library(data.table)
        setDT(df)[, Begin1 := Begin]
        i1 <- df[, .I[Begin < shift(End, fill = Begin[1L])], by = ID]$V1
        df$Begin1[i1] <- df$End[i1-1]
        df
        #     ID Begin  End Begin1
        # 1:  1   0.0  1.5    0.0
        # 2:  1   2.5  3.5    2.5
        # 3:  1   5.0  6.0    5.0
        # 4:  3   7.0  7.5    7.0
        # 5:  3   8.0  8.0    8.0
        # 6:  3   7.0 11.0    8.0
        # 7:  3  25.0 29.0   25.0
        # 8:  3  25.0 35.0   29.0
        # 9:  4  10.0 12.0   10.0
        #10:  4  15.0 19.0   15.0
        #11:  4  17.0 21.0   19.0
        #12:  4  20.0 28.0   21.0
        

        或者另一种选择是

        setDT(df)[, Begin1 := shift(End), by = ID][!which(Begin < Begin1), Begin1:= Begin]
        df
        #    ID Begin  End Begin1
        # 1:  1   0.0  1.5    0.0
        # 2:  1   2.5  3.5    2.5
        # 3:  1   5.0  6.0    5.0
        # 4:  3   7.0  7.5    7.0
        # 5:  3   8.0  8.0    8.0
        # 6:  3   7.0 11.0    8.0
        # 7:  3  25.0 29.0   25.0
        # 8:  3  25.0 35.0   29.0
        # 9:  4  10.0 12.0   10.0
        #10:  4  15.0 19.0   15.0
        #11:  4  17.0 21.0   19.0
        #12:  4  20.0 28.0   21.0
        

        或者使用dplyr

        library(dplyr)
        df %>%
            group_by(ID) %>% 
            mutate(Begin1 = pmax(Begin, lag(End), na.rm =TRUE))
        #      ID Begin   End Begin1
        #   <dbl> <dbl> <dbl>  <dbl>
        #1      1   0.0   1.5    0.0
        #2      1   2.5   3.5    2.5
        #3      1   5.0   6.0    5.0
        #4      3   7.0   7.5    7.0
        #5      3   8.0   8.0    8.0
        #6      3   7.0  11.0    8.0
        #7      3  25.0  29.0   25.0
        #8      3  25.0  35.0   29.0
        #9      4  10.0  12.0   10.0
        #10     4  15.0  19.0   15.0
        #11     4  17.0  21.0   19.0
        #12     4  20.0  28.0   21.0
        

        更新

        根据OP的新数据

        setDT(df)[, Begin1 := shift(End), by = .(ID, Group)][
                           !which(Begin < Begin1), Begin1 := Begin]
        df
        #     ID Group Begin  End Begin1
        #1:  1     1   0.0  1.5    0.0
        #2:  1     1   2.5  3.5    2.5
        #3:  1     2   5.0  6.0    5.0
        #4:  3     1   7.0  7.5    7.0
        #5:  3     1   8.0  8.0    8.0
        #6:  3     1   7.0 11.0    8.0
        #7:  3     2  25.0 29.0   25.0
        #8:  3     2  25.0 35.0   29.0
        #9:  4     1  10.0 12.0   10.0
        #10: 4     1  15.0 19.0   15.0
        #11: 4     1  17.0 21.0   19.0
        #12: 4     2  20.0 28.0   20.0
        

        【讨论】:

        • 你能解释一下为什么我们使用 fill = Begin[1L],谢谢
        • 我在 data.table 中添加了另一个 ID2,我使用 setDT(df)[, Begin1 := shift(End), by = .(ID, ID2)][!which(Begin
        • @Stat 你能更新你的帖子以便我理解吗?
        • @ give me error Error in .get_variables(formula, data, id, debug.info) : 'formula' must be a formula or a list
        • @Stat 你有什么数据,表格版本?
        猜你喜欢
        • 2016-06-15
        • 1970-01-01
        • 2021-12-26
        • 2020-07-13
        • 1970-01-01
        • 1970-01-01
        • 2014-07-31
        • 2021-08-19
        • 2017-09-27
        相关资源
        最近更新 更多