在r中的数据表中按组累计识别新值

在r中的数据表中按组累计识别新值,r,dataframe,dplyr,data.table,tidyverse,R,Dataframe,Dplyr,Data.table,Tidyverse,如何创建一个新列,该列通过年+月的一组独特梳子来累计标识字母列中的新值外观 数据样本 require(data.table) dt <- data.table(Letter = c(LETTERS[c(5, 1:2, 1:2, 1:4, 3:6)]), Year = 2018, Month = c(rep(5,5), rep(6,4), rep(7,4))) 我试图得到的结果是: Letter Year Mont

如何创建一个新列,该列通过
+
的一组独特梳子来累计标识
字母
列中的新值外观

数据样本

require(data.table)
dt <- data.table(Letter = c(LETTERS[c(5, 1:2, 1:2, 1:4, 3:6)]),
                 Year = 2018,
                 Month = c(rep(5,5), rep(6,4), rep(7,4)))
我试图得到的结果是:

    Letter Year Month   New
 1:      E 2018     5  TRUE
 2:      A 2018     5  TRUE
 3:      B 2018     5  TRUE
 4:      A 2018     5  TRUE
 5:      B 2018     5  TRUE
 6:      A 2018     6 FALSE
 7:      B 2018     6 FALSE
 8:      C 2018     6  TRUE
 9:      D 2018     6  TRUE
10:      C 2018     7 FALSE
11:      D 2018     7 FALSE
12:      E 2018     7 FALSE
13:      F 2018     7  TRUE
详细问题:

  • 第1组(“E”、“A”、“B”、“A”、“B”)在默认情况下均为TRUE,无需进行比较
  • 第2组中的哪个字母(“A”、“B”、“C”、“D”)在第1组中不重复
  • 那么,第3组(“C”、“D”、“E”、“F”)中的哪个字母在第1组和第2组(“E”、“A”、“B”、“A”、“B”、“B”、“C”、“D”)中不重复
  • 简单地说:

     # dt[,new := ifelse(Letter %in% dt$Letter[dt$Month<Month],F,T), by="Month"][]
    
     #   Letter Year Month   new
     #1:      E 2018     5  TRUE
     #2:      A 2018     5  TRUE
     #3:      B 2018     5  TRUE
     #4:      A 2018     5  TRUE
     #5:      B 2018     5  TRUE
     #6:      A 2018     6 FALSE
     #7:      B 2018     6 FALSE
     #8:      C 2018     6  TRUE
     #9:      D 2018     6  TRUE
    #10:      C 2018     7 FALSE
    #11:      D 2018     7 FALSE
    #12:      E 2018     7 FALSE
    #13:      F 2018     7  TRUE
    

    #dt[,new:=ifelse(字母%in%dt$字母[dt$月另一种可能的方法:

    dupes <- c()
    dt[, New := {
        x <- !Letter %chin% dupes
        dupes <- c(dupes, unique(Letter[x]))
        x
    }, by=.(Year, Month)]
    
    如果字母是字符:

    microbenchmark(mtd0=dt0[, New := !(Letter %chin% dt0$Letter[dt0$Month<Month]), by=Month],
        mtd1={
            dt1[, v := FALSE]
            dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
        },
        mtd2={
            dupes <- c()
            dt2[, New := {
                x <- !Letter %chin% dupes
                dupes <- c(dupes, unique(Letter[x]))
                x
            }, by=.(Year, Month)]        
        },
        times=3L)
    
    检查:

    > identical(dt2$New, dt1$v)
    [1] TRUE
    > identical(dt0$New, dt1$v)
    [1] FALSE
    
    数据:

    set.seed(0L)
    
    nr初始化为FALSE;然后用每个字母连接到第一年的月份,并更新为TRUE:

    dt[, v := FALSE]
    dt[unique(dt, by="Letter"), on=.(Letter, Year, Month), v := TRUE][]
    
        Letter Year Month     v
     1:      E 2018     5  TRUE
     2:      A 2018     5  TRUE
     3:      B 2018     5  TRUE
     4:      A 2018     5  TRUE
     5:      B 2018     5  TRUE
     6:      A 2018     6 FALSE
     7:      B 2018     6 FALSE
     8:      C 2018     6  TRUE
     9:      D 2018     6  TRUE
    10:      C 2018     7 FALSE
    11:      D 2018     7 FALSE
    12:      E 2018     7 FALSE
    13:      F 2018     7  TRUE
    

    @Andre这是一个简单而伟大的答案!谢谢你!@David谢谢你的添加。如果有多个年份,仅按月份分组和测试不平等性是不够的,对吗?你可以创建一个新的YearMonth:=粘贴(年,月)变量并使用它。我不知道不同年份的逻辑是什么。我宁愿按年份分割。使用我的代码和rbind。@Andre顺便说一句,用数据替换%
    中的
    %in%
    。表的本机
    %chin%
    使它更加有效。仅供参考,您的DUPS对象在DT之外[…]没有被修改。这不是一个问题,但是一些可能感兴趣的替代方案:让它只存在于DT[…]中,比如
    DT[,New:={if(.GRP==1L)谢谢你,弗兰克。是的,如果需要
    unique
    set,那么可以使用
    @chinsoon12谢谢!非常好的方法!特别是在字符串的效率方面。
    
    Unit: milliseconds
     expr       min       lq      mean    median        uq      max neval
     mtd0 1293.3100 1318.775 1331.7129 1344.2398 1350.9143 1357.589     3
     mtd1  377.1534  391.178  402.4423  405.2026  415.0868  424.971     3
     mtd2 2015.2115 2020.926 2023.7209 2026.6400 2027.9756 2029.311     3
    
    microbenchmark(mtd0=dt0[, New := !(Letter %chin% dt0$Letter[dt0$Month<Month]), by=Month],
        mtd1={
            dt1[, v := FALSE]
            dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
        },
        mtd2={
            dupes <- c()
            dt2[, New := {
                x <- !Letter %chin% dupes
                dupes <- c(dupes, unique(Letter[x]))
                x
            }, by=.(Year, Month)]        
        },
        times=3L)
    
    Unit: milliseconds
     expr       min        lq      mean    median        uq       max neval
     mtd0 1658.5806 1689.8941 1765.9329 1721.2076 1819.6090 1918.0105     3
     mtd1  849.2361  851.1807  852.8632  853.1253  854.6768  856.2283     3
     mtd2  420.1013  426.0941  433.9202  432.0869  440.8296  449.5723     3
    
    > identical(dt2$New, dt1$v)
    [1] TRUE
    > identical(dt0$New, dt1$v)
    [1] FALSE
    
    set.seed(0L)
    nr <- 1e7
    dt <- unique(data.table(Letter=sample(nr/1e2, nr, replace=TRUE),
        Year=sample(2014:2018, nr, replace=TRUE),
        Month=sample(1:12, nr, replace=TRUE)))
    setorder(dt, Year, Month)#[, Letter := as.character(Letter)]
    dt0 <- copy(dt)
    dt1 <- copy(dt)
    dt2 <- copy(dt)
    
    #for seed=0L, dt has about 4.8mio rows
    
    dt[, v := FALSE]
    dt[unique(dt, by="Letter"), on=.(Letter, Year, Month), v := TRUE][]
    
        Letter Year Month     v
     1:      E 2018     5  TRUE
     2:      A 2018     5  TRUE
     3:      B 2018     5  TRUE
     4:      A 2018     5  TRUE
     5:      B 2018     5  TRUE
     6:      A 2018     6 FALSE
     7:      B 2018     6 FALSE
     8:      C 2018     6  TRUE
     9:      D 2018     6  TRUE
    10:      C 2018     7 FALSE
    11:      D 2018     7 FALSE
    12:      E 2018     7 FALSE
    13:      F 2018     7  TRUE