【问题标题】:R data.table binary value for last row in group by conditionR data.table 按条件分组的最后一行的二进制值
【发布时间】:2019-05-10 22:03:01
【问题描述】:

我有这样的数据:

library(data.table)
id <- c("1232","1232","1232","4211","4211","4211")
conversion <- c(0,0,0,1,1,1)
DT <- data.table(id, conversion)

id   date         conversion
1232 2018-01-01   0
1232 2018-01-03   0
1232 2018-01-04   0
4211 2018-04-01   1
4211 2018-04-04   1
4211 2018-04-06   1

我想根据 id 行仅为每个组的最后一行创建一个二进制值。只有当组的转换为 1 时,二进制才会为 1。

id   date         conversion  lastconv
1232 2018-01-01   0           0
1232 2018-01-03   0           0 
1232 2018-01-04   0           0
4211 2018-04-01   1           0
4211 2018-04-04   1           0
4211 2018-04-06   1           1

我尝试在 data.table 中使用一些带有“mult”参数的示例,但只返回错误。

DT[unique(id), lastconv := 1, mult = "last"]

【问题讨论】:

  • 如果你有setkey 在你的行之前你的例子会起作用。请注意,mult = "last" 也会导致 1 被放置在 id 1232 上。

标签: r data.table


【解决方案1】:

修改 OP 的代码以加入每个组的最后一行:

DT[, v := 0]
DT[.(DT[conversion == 1, unique(id)]), on=.(id), mult="last", v := 1]

     id conversion v
1: 1232          0 0
2: 1232          0 0
3: 1232          0 0
4: 4211          1 0
5: 4211          1 0
6: 4211          1 1

这只是不同之处在于它根据所需条件选择要编辑的ids。

【讨论】:

    【解决方案2】:

    对于每个id,检查行号是否是组中的最后一个行号,'conversion'是否为1。将逻辑结果转换为整数。

    DT[ , lastconv := as.integer(.I == .I[.N] & conversion == 1), by = id]
    

    【讨论】:

      【解决方案3】:

      参考时间:

      library(data.table)
      #data.table 1.12.3 IN DEVELOPMENT built 2019-05-12 17:04:48 UTC; root using 4 threads (see ?getDTthreads).  Latest news: r-datatable.com
      set.seed(0L)
      nid <- 3e6L
      DT <- data.table(id=rep(1L:nid, each=3L))[,
          conversion := sample(c(0L,1L), 1L, replace=TRUE), by=.(id)]
      DT0 <- copy(DT)
      DT1 <- copy(DT)
      DT2 <- copy(DT)
      DT3 <- copy(DT)
      
      mtd0 <- function() {
          DT0[DT0[, .I[.N], by=id]$V1, lastconv := conversion]
          DT0[is.na(lastconv), lastconv := 0L]
      }
      
      mtd1 <- function() {
          DT1[DT1[, .I[.N], by=id]$V1, lastconv := conversion]
          setnafill(DT1, cols = "lastconv", fill = 0L)
      }
      
      mtd2 <- function() {
          DT2[, v := 0]
          DT2[.(DT2[conversion == 1, unique(id)]), on=.(id), mult="last", v := 1]
      
          #or also
          #DT2[, v := 0L][
          #    DT2[,.(cv=last(conversion)), id], on=.(id), mult="last", v := cv]
      }
      
      mtd3 <- function() {
          DT3[ , lastconv := as.integer(.I == .I[.N] & conversion == 1), by = id]
      }
      
      library(microbenchmark)
      microbenchmark(mtd0(), mtd1(), mtd2(), mtd3(), times=1L)
      

      时间安排:

      Unit: milliseconds
         expr       min        lq      mean    median        uq       max neval cld
       mtd0() 1363.1783 1416.1867 1468.9256 1469.1952 1521.7992 1574.4033     3  b 
       mtd1() 1349.5333 1365.4653 1378.9350 1381.3974 1393.6358 1405.8743     3  b 
       mtd2()  511.5615  515.4728  552.9133  519.3841  573.5892  627.7944     3 a  
       mtd3() 3966.8867 4009.1128 4048.9607 4051.3389 4089.9977 4128.6564     3   c
      

      【讨论】:

        【解决方案4】:

        过滤每个组的最后一行并将lastconv 设置为等于conversion

        DT[DT[, .I[.N], by=id]$V1, lastconv := conversion]
        

        然后将NAs 替换为0

        DT[is.na(lastconv), lastconv := 0L]
        

        结果

        DT
        #     id conversion lastconv
        #1: 1232          0        0
        #2: 1232          0        0
        #3: 1232          0        0
        #4: 4211          1        0
        #5: 4211          1        0
        #6: 4211          1        1
        

        如果安装了data.table v1.12.3,我们还可以在第二步中使用新功能setnafill替换NAs

        DT[DT[, .I[.N], by=id]$V1, lastconv := conversion]
        setnafill(DT, cols = "lastconv", fill = 0L)
        

        【讨论】:

        • 很高兴看到用户发布最近的功能!谢谢,在NEWS 文件或manual 中提供有关此新功能的更多信息
        【解决方案5】:

        您是否尝试过类似以下的方法?

        library(tidyverse)
        
        final_conversion_dat <- DT %>% 
          group_by(id) %>% 
          mutate(date = as.Date(date),
                 final_conversion = ifelse(date == max(date, na.rm = T) & conversion == 1, 1, 0))
        

        【讨论】:

          猜你喜欢
          • 2013-08-09
          • 2017-10-19
          • 2021-11-25
          • 1970-01-01
          • 2015-05-12
          • 1970-01-01
          • 2021-09-25
          • 1970-01-01
          • 2022-11-15
          相关资源
          最近更新 更多