在R中为data.table查找组的最大值索引

时间:2014-08-15 03:48:07

标签: r data.table

我有一个data.table或data.frame,如下所示:

Name     Person     Date
A        1          1/1/2004
A        2          1/1/2004
A        2          1/3/2004
A        3          1/1/2004
A        3          1/3/2004
A        3          1/9/2004
B        4          1/7/2004
B        5          1/7/2004
B        5          1/10/2004
B        6          1/7/2004
B        6          1/10/2004
B        6          1/17/2004

在这里,我正在尝试创建一个具有" NA"对于日期,如果他们不是最大的人。基本上,我试图让数据表看起来像:

    Name     Person     Date
A        1          1/1/2004
A        2          "NA"
A        2          1/3/2004
A        3          "NA"
A        3          "NA"
A        3          1/9/2004
B        4          1/7/2004
B        5          "NA"
B        5          1/10/2004
B        6          "NA"
B        6          "NA"
B        6          1/17/2004

基本上,我想到的算法是按人看每个分组。如果按人分组只有一个元素,则该值为最大值,因此我们将其保留在那里。但是,例如,在按人2分组时,最大值是1/3/2004,所以我们让1/1/2004为" NA"。

我能想到这样做的唯一方法是找到与组(Person)的最大值对应的数据表的索引,然后创建所有NA的新向量,然后替换为最大值的索引。

代码如下:

which.max(data$Date, by=data$Person)

这对我来说不起作用,但无论哪种方式,这段代码看起来都可能是时间密集的,特别是如果我的数据集是1亿行。是否可以快速实现大型数据集,尤其是在data.table包中工作?谢谢!

3 个答案:

答案 0 :(得分:4)

使用data.table

#dat <- as.data.table(dat)
#dat$Date <- as.Date(dat$Date,format="%m/%d/%Y")
dat[dat[, Date != max(Date) , by=Person][,V1], Date := NA]
dat

 #   Name Person       Date
 #1:    A      1 2004-01-01
 #2:    A      2       <NA>
 #3:    A      2 2004-01-03
 #4:    A      3       <NA>
 #5:    A      3       <NA>
 #6:    A      3 2004-01-09
 #7:    B      4 2004-01-07
 #8:    B      5       <NA>
 #9:    B      5 2004-01-10
#10:    B      6       <NA>
#11:    B      6       <NA>
#12:    B      6 2004-01-17

答案 1 :(得分:3)

这是ave()的一个很好的用例,它允许您将函数应用于每个人的值。如果这是您的样本数据

dd<-structure(list(Name = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 
    2L, 2L, 2L, 2L, 2L), .Label = c("A", "B"), class = "factor"), 
    Person = c(1L, 2L, 2L, 3L, 3L, 3L, 4L, 5L, 5L, 6L, 6L, 6L
    ), Date = structure(c(12418, 12418, 12420, 12418, 12420, 
    12426, 12424, 12424, 12427, 12424, 12427, 12434), class = "Date")), 
    .Names = c("Name", "Person", "Date"), 
    row.names = c(NA, -12L), class = "data.frame")

然后使用

with(dd, ave(Date, Person,FUN=function(x) {x[x!=max(x)]<-NA; x}))
#  [1] "2004-01-01" NA           "2004-01-03" NA           NA          
#  [6] "2004-01-09" "2004-01-07" NA           "2004-01-10" NA          
# [11] NA           "2004-01-17"

答案 2 :(得分:3)

使用data.table的另一种方式(假设每组没有多个最大值)

 dat[dat[, order(Date)!=.N, by=Person]$V1, Date:= NA]
 dat
 #   Name Person       Date
 #1:    A      1 2004-01-01
 #2:    A      2       <NA>
 #3:    A      2 2004-01-03
 #4:    A      3       <NA>
 #5:    A      3       <NA>
 #6:    A      3 2004-01-09
 #7:    B      4 2004-01-07
 #8:    B      5       <NA>
 #9:    B      5 2004-01-10
#10:    B      6       <NA>
#11:    B      6       <NA>
#12:    B      6 2004-01-17

如果您有多个最大值:

dat[dat[, rank(Date,ties.method="max")!=.N, by=Person]$V1, Date:=NA]

格式化date

dat[dat[, order(Date)!=.N, by=Person]$V1, Date:= NA][,Date:=format(Date, "%m/%d/%Y")]