【问题标题】:Conditionally remove rows that match in column A, based on column B in R using data.table使用 data.table 根据 R 中的 B 列有条件地删除 A 列中匹配的行
【发布时间】:2014-11-26 21:11:47
【问题描述】:

尝试使用 R 中的 data.table 修复重复数据删除问题。

A 列是名称列表,其中一些名称出现多次。 B 列是日期列表。我还想复制许多其他列(Name on Date 发生的事情。)

但是,我只想查看新数据表中每个人的最多活动,其中每个名称对应于最近的日期有 1 个条目。

示例数据

    name.last       date
 1:     Adams 2014-10-20
 2:     Adams 2014-07-07
 3:   Barnett 2014-11-06
 4:   Barnett 2014-09-22
 5:      Bell 2014-10-22
 6:      Bell 2014-07-29
 7:     Burns 2014-09-08
 8:     Burns 2014-09-03
 9:   Camacho 2014-08-12
10:   Camacho 2014-07-08
11:  Casillas 2014-10-07
12:  Casillas 2014-07-17
13:    Chavez 2014-09-23
14:    Chavez 2014-09-17
15:   Chavira 2014-07-15
16:   Chavira 2014-07-07
17:    Claren 2014-10-30
18:    Claren 2014-10-23
19:  Colleary 2014-11-11
20:  Colleary 2014-11-07

答案将只返回每个名称的第一个(因为这里的行是按照每个第一个的最近日期排序的。)但是,如果我设置 dt 键 setkey(dt,name.last) 以便使用 unique() 删除重复项,它按键顺序(名称上的字母顺序)重新排序表。然后使用unique(dt) 返回每​​个名称的第一次出现,这不一定是最近的日期。

如果我在 setkeyv(dt,c(name.last,date)) 两列上设置键,我将无法使用 unique() 删除重复项,因为所有键都是唯一的。

问题类似于这里的一篇帖子:Collapsing data frame by selecting one row per group。但是,我不能假设要选择的数据是第一个或最后一个,除非您可以建议一种方法来操作我的数据以在设置密钥后使其如此。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    有很多方法可以在不对数据表进行排序的情况下执行此操作(尽管排序是首选,因为duplicated 非常有效,而且您还避免使用by - 会做到这一点)。

    首先,您必须确保 date 属于 Date 类,以使事情变得更容易

    dt[, date := as.Date(date)]
    

    第一个简单的方法(虽然不是最有效的)

    dt[, max(date), name.last]
    #     name.last         V1
    #  1:     Adams 2014-10-20
    #  2:   Barnett 2014-11-06
    #  3:      Bell 2014-10-22
    #  4:     Burns 2014-09-08
    #  5:   Camacho 2014-08-12
    #  6:  Casillas 2014-10-07
    #  7:    Chavez 2014-09-23
    #  8:   Chavira 2014-07-15
    #  9:    Claren 2014-10-30
    # 10:  Colleary 2014-11-11
    

    第二种(提供的)方法与您的相似,但使用的是 data.tables setorder(对于 data.table 版本 >= 1.9.4),应该是最有效的

    setorder(dt, name.last, -date)[!duplicated(name.last)]
    #     name.last       date
    #  1:     Adams 2014-10-20
    #  2:   Barnett 2014-11-06
    #  3:      Bell 2014-10-22
    #  4:     Burns 2014-09-08
    #  5:   Camacho 2014-08-12
    #  6:  Casillas 2014-10-07
    #  7:    Chavez 2014-09-23
    #  8:   Chavira 2014-07-15
    #  9:    Claren 2014-10-30
    # 10:  Colleary 2014-11-11
    

    您可以使用setkey(就像您已经做过的那样)和在duplicated 中指定from.last = TRUE 并删除! 来实现相同的目的

    setkey(dt, name.last, date)[duplicated(name.last, from.last = TRUE)]
    
    #     name.last       date
    #  1:     Adams 2014-10-20
    #  2:   Barnett 2014-11-06
    #  3:      Bell 2014-10-22
    #  4:     Burns 2014-09-08
    #  5:   Camacho 2014-08-12
    #  6:  Casillas 2014-10-07
    #  7:    Chavez 2014-09-23
    #  8:   Chavira 2014-07-15
    #  9:    Claren 2014-10-30
    # 10:  Colleary 2014-11-11
    

    第三种方法是使用data.tables unique函数(应该也很高效)

    unique(setorder(dt, name.last, -date), by = "name.last")
    #     name.last       date
    #  1:     Adams 2014-10-20
    #  2:   Barnett 2014-11-06
    #  3:      Bell 2014-10-22
    #  4:     Burns 2014-09-08
    #  5:   Camacho 2014-08-12
    #  6:  Casillas 2014-10-07
    #  7:    Chavez 2014-09-23
    #  8:   Chavira 2014-07-15
    #  9:    Claren 2014-10-30
    # 10:  Colleary 2014-11-11
    

    最后一种方法是使用.SD。这是效率最低的,但在某些情况下,当您想要获得所有列作为回报并且您不能使用诸如 sduplicated 之类的函数时,它很有用

    setorder(dt, name.last, -date)[, .SD[1], name.last]
    #     name.last       date
    #  1:     Adams 2014-10-20
    #  2:   Barnett 2014-11-06
    #  3:      Bell 2014-10-22
    #  4:     Burns 2014-09-08
    #  5:   Camacho 2014-08-12
    #  6:  Casillas 2014-10-07
    #  7:    Chavez 2014-09-23
    #  8:   Chavira 2014-07-15
    #  9:    Claren 2014-10-30
    # 10:  Colleary 2014-11-11
    

    【讨论】:

      【解决方案2】:

      如果我理解你的问题,我认为你可以使用 sqldf 包更清楚地做到这一点,但缺点是你必须了解 sql.

      install.packages("sqldf")
      library("sqldf")
      dt <-data.frame(read.table(header = TRUE, text = " name.last       date
      1:     Adams 2014-10-20
      2:     Adams 2014-07-07
      3:   Barnett 2014-11-06
      4:   Barnett 2014-09-22
      5:      Bell 2014-10-22
      6:      Bell 2014-07-29
      7:     Burns 2014-09-08
      8:     Burns 2014-09-03
      9:   Camacho 2014-08-12
      10:   Camacho 2014-07-08
      11:  Casillas 2014-10-07
      12:  Casillas 2014-07-17
      13:    Chavez 2014-09-23
      14:    Chavez 2014-09-17
      15:   Chavira 2014-07-15
      16:   Chavira 2014-07-07
      17:    Claren 2014-10-30
      18:    Claren 2014-10-23
      19:  Colleary 2014-11-11
      20:  Colleary 2014-11-07")
      )
      head(dt)
      colnames(dt) <- c('names', 'date')
      sqldf("select names, min(date), max(date) from dt group by names")
      

      希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        在写这篇文章时,我想通了。为了后代......

        按名称和日期对表格进行排序,以便您可以根据希望成为组中第一个或最后一个的日期。例如:dt[order(names,-date)]

        那么与其设置密钥并使用unique(),不如简单:

        dt[!duplicated(names)]

        names 是重复的列。

        应该输出所需的表。如果有更优雅/可靠的方法可以做到这一点,我会很想听听。

        【讨论】:

          猜你喜欢
          • 2021-03-06
          • 2021-06-01
          • 2014-05-04
          • 1970-01-01
          • 1970-01-01
          • 2017-09-28
          • 1970-01-01
          • 2020-06-10
          • 1970-01-01
          相关资源
          最近更新 更多