使用Data.Table在组内有条件地选择行

3

我希望使用data.table找到解决方案― 我有一个包含以下列的data.table:

data <- data.frame(GROUP=c(3,3,4,4,5,6),
                    YEAR=c(1979,1985,1999,2011,2012,1994),
                    NAME=c("S","A","J","L","G","A"))

data <- as.data.table(data)

Data.table:

GROUP  YEAR    NAME
3      1979    Smith 
3      1985    Anderson
4      1999    James
4      2011    Liam
5      2012    George
6      1994    Adams

对于每个组,我们要使用以下规则选择一行:

  • 如果有一个年份大于2000,则选择最小的年份高于2000的行。
  • 如果没有年份大于2000,则选择具有最大年份的行。

期望输出:

GROUP  YEAR    NAME
3      1985    Anderson
4      2011    Liam
5      2012    George
6      1994    Adams

谢谢!我已经为此苦苦挣扎了一段时间。

3个回答

8

data.table 如果你使用特殊的 .I 行计数器进行子集操作,会更加简单:

library(data.table)
setDT(data)
data[
  data[
        ,
        if(any(YEAR > 2000)) 
           .I[which.min(2000 - YEAR)] else
           .I[which.max(YEAR)],
        by=GROUP
      ]$V1
]
#   GROUP YEAR NAME
#1:     3 1985    A
#2:     4 2011    L
#3:     5 2012    G
#4:     6 1994    A

感谢@r2evans提供的背景信息-
.I是一个整数向量,相当于seq_len(nrow(x))。 参考: http://rdrr.io/cran/data.table/man/special-symbols.html 因此,在每个by=级别的每个计算中,我所做的就是为整个数据获取匹配行索引。然后使用这些行索引再次对数据进行子集化。

1
我遇到了一个错误 Error in [.data.frame(data, , if (any(YEAR > 2000)) .I[which.min(2000 - : unused argument (by = GROUP),你能否完全按照这个方式工作? - morgan121
2
@user10626943 - 这篇帖子标记了 data.table,所以我假设 OP 已经在使用 data.table 了 - 如果不是的话,你需要先进行转换。我已经编辑过了。 - thelatemail
2
对于后来者,.I是一个整数向量,相当于seq_len(nrow(x))。参考:https://rdrr.io/cran/data.table/man/special-symbols.html(我不得不查一下 :-)) - r2evans

3
你也可以执行一些滚动连接操作:
res = unique(data[, .(GROUP)])

# get row with YEAR above 2000
res[, w := data[c(.SD, YEAR = 2000), on=.(GROUP, YEAR), roll=-Inf, which=TRUE]]

# if none found, get row with nearest YEAR below   
res[is.na(w), w := data[c(.SD, YEAR = 2000), on=.(GROUP, YEAR), roll=Inf, which=TRUE]]

# subset by row numbers
data[res$w]

   GROUP YEAR NAME
1:     3 1985    A
2:     4 2011    L
3:     5 2012    G
4:     6 1994    A

2
使用dplyr包,我得到了这样的输出(虽然它可能不是最简单的答案):
 library(dplyr)
 library(magrittr)

 data <- data.frame(GROUP=c(3,3,4,4,5,6),
                    YEAR=c(1979,1985,1999,2011,2012,1994),
                    NAME=c("S","A","J","L","G","A"))

 data %>%
   subset(YEAR < 2000) %>%
   group_by(GROUP) %>%
   summarise(MAX=max(YEAR)) %>%
   join(data %>%
          subset(YEAR > 2000) %>%
          group_by(GROUP) %>%
          summarise(MIN=min(YEAR)), type="full") %>%
   mutate(YEAR=ifelse(is.na(MIN), MAX, MIN)) %>%
   select(c(GROUP, YEAR)) %>%
   join(data)

结果:

   GROUP YEAR NAME
      3  1985   A
      4  2011   L
      5  2012   G
      6  1994   A

编辑:抱歉,我的第一次回答没有考虑到最小/最大条件。希望这可以帮助。


1
感谢您提供的tidyverse解决方案!以及格式化指针。 - CFB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接