如何在保持组内特定排序顺序的同时标记组中的最后一个观察值?

时间:2019-06-11 13:00:51

标签: r data.table

这与this question有关。我有这样的数据:

   x t
1: 1 1
2: 1 2
3: 1 3
4: 2 1
5: 2 2
6: 2 3

我想标记每个组中的最后一个观测值(并保留其他观测值),由x定义,其中“最后”观测值由t定义。我尝试过:

dt[order(x, t), flag_last := 1, by = "x", mult = "last"]

但返回

   x t flag_last
1: 1 1         1
2: 1 2         1
3: 1 3         1
4: 2 1         1
5: 2 2         1
6: 2 3         1

所需的输出是

   x t flag_last
1: 1 1         0
2: 1 2         0
3: 1 3         1
4: 2 1         0
5: 2 2         0
6: 2 3         1

我会以错误的方式处理吗?


一些警告:

  • 实际数据集大约为61 GB,并且每个x组只有几个观察值,因此,如果可能的话,我想避免使用唯一值创建另一个副本或使用来创建另一个副本dplyr。如果不可避免,我会做。

  • 显然,这是简单的数据。 每个组中的观察次数不一定相同,并且t的值也不同,因此简单地选择t == 3就行不通了。

    < / li>

4 个答案:

答案 0 :(得分:3)

像这样使用内置的.I

DT[, is.end := .I == last(.I), by = "x"]

答案 1 :(得分:2)

dt[, flag_last := replace(vector(mode = "integer", length = .N), which.max(t), 1L), x]


#    x t flag_last
# 1: 1 1         0
# 2: 1 2         0
# 3: 1 3         1
# 4: 2 1         0
# 5: 2 2         0
# 6: 2 3         1

答案 2 :(得分:2)

一种选择是使用.Nwhich.max检查行索引与t最大化的行索引之间是否相等

df[, flag := as.integer(1:.N == which.max(t)), x]

但是基准测试显示,replace在我的计算机上对此数据集更快,并且如果您不介意使用NA而不是0,则David Arenburg建议使用.I的方法是最快的。

df <- data.table(x = rep(1:1e4, each = 1e4), t = sample(1e4*1e4))

library(microbenchmark)

microbenchmark(
replace = df[, flag_last := replace(vector(mode = "integer", length = .N), which.max(t), 1L), x],
use.N = df[, flag := as.integer(1:.N == which.max(t)), x],
use.max = df[, flag := as.integer(t==max(t)), x],
use.I = {
  df[, flag := 0L]
  df[df[, .I[which.max(t)], by = x]$V1, flag := 1L]
},
use.I.no0 = df[df[, .I[which.max(t)], by = x]$V1, flag := 1L],
times = 20)


# Unit: seconds
#       expr      min       lq     mean   median       uq      max neval cld
#    replace 1.228490 1.292348 1.442919 1.443021 1.578300 1.659990    20  b 
#      use.N 1.439939 1.522782 1.617104 1.574932 1.696046 1.923207    20   c
#    use.max 1.405741 1.436817 1.596363 1.502337 1.663895 2.743942    20   c
#      use.I 1.497599 1.547276 1.574657 1.564789 1.589066 1.686353    20  bc
#  use.I.no0 1.080715 1.115329 1.162752 1.145145 1.182280 1.383989    20 a  

答案 3 :(得分:1)

如果您创建一个id变量,然后可以将其用于将两个数据集合并在一起,那么就可以解决问题:

library(dplyr)
x <- c(1,1,1,2,2,2)
t <- c(1,2,3,1,2,3)
id <- as.character(c(1,2,3,4,5,6))

data <- data.frame(x,t, id)

使用每个组的最大值创建切片的数据集,然后将其合并回初始数据框。

sliced <- data %>%
  group_by(x) %>%
  slice(which.max(t)) %>%
  ungroup() %>%
  select(id) %>%
  mutate(max = "max_group")

tot <- left_join(data, sliced, c("id"))

切片的df只有两个变量,因此使用它可能还不错。这是我想到的更简单的方法。