【问题标题】:Select only first or last value for each unique value in data table?为数据表中的每个唯一值仅选择第一个或最后一个值?
【发布时间】:2015-02-11 10:16:08
【问题描述】:

我有一个这样的数据表。

> dt
    ID value
 1   a  v1
 2   a  v2
 3   a  v3
 4   a  v4
 5   a  v5
 6   b  v6
 7   b  v7
 8   b  v8

我只想为每个 ID 选择一个 。它可以是第一个值或最后一个值。我就是这样做的。

unique_id_value_mapping <- dt[, list(new_value=head(.SD[,value],1)), by="ID"]

但对于大型数据表(约 10 万行),这需要大量时间。有谁知道更快的方法吗?

更新
针对上述问题提出的答案效果很好。 但是,如果我需要根据某些条件选择值怎么办。考虑一个数据表

> dt
    ID value days
 1   a  v1     2
 2   a  v2     4
 3   a  v3     7 *
 4   a  v4     7
 5   a  v5     1
 6   b  v6     5 *
 7   b  v7     4
 8   b  v8     2

并且我只想为每个 ID 选择一个 ,只要该 IDdays 是最大值。我就是这样做的。

unique_id_value_mapping <- dt[, list(new_value=head(.SD[days==max(days),value])), by="ID"]

如何更快?

【问题讨论】:

  • 你为什么使用.SD?这是没有意义的。为什么不只是dt[, .(new_value = head(value, 1)), ID]dt[, .(new_value = tail(value, 1)), ID]headtail 都是非常高效的函数,因此您应该获得最大的速度。速度下降的另一个原因是,如果您有大量唯一的 IDs,这将使这基本上是一个行操作(这总是很慢)。
  • @DavidArenburg 在 1e6 数据集上,头部,尾部,定时 0.014
  • @akrun 这和你的时间一样,不是吗? system.time 有一些差异,所以我猜它在阈值之内。
  • @DavidArenburg 是的,类似。
  • 也许dt[, .(new_value = value[which.max(days)]), ID]

标签: r data.table


【解决方案1】:

试试

dt[, list(new_value=value[1L]), ID]
dt[, list(new_value= value[.N]), ID]

使用更大的数据集

set.seed(24)
df1 <- data.frame(ID= sample(1:100, 1e6, replace=TRUE), 
     value=rnorm(1e6))
dt1 <- as.data.table(df1)
system.time(dt1[, list(new_value=value[1L]), ID])
#   user  system elapsed 
#  0.012   0.000   0.013 
 system.time(dt1[, list(new_value=value[.N]), ID])
#  user  system elapsed 
#  0.011   0.000   0.012 

更新

根据@David Arenburg 建议的新更新

 dt[, list(new_value = value[which.max(days)]), by = ID]
 #    ID new_value
 #1:  a        v3
 #2:  b        v6

假设你需要满足条件的行

 dt[dt[, .I[which.max(days)], by = ID]$V1]
 #   ID value days
 #1:  a    v3    7
 #2:  b    v6    5

或者

 dt[, .SD[which.max(days)], by = ID]

【讨论】:

  • 但正如您所见,ID=a 有两行,最大天数=7,我只需要选择第一个值(即 v3)。我不认为它会那样做。我应该使用dt[, list(new_value = head(value[which.max(days)],1)), by = ID] 吗?
  • @shubham 在您的帖子中,您提到每个 ID 只需要一行。如果有关系,dt[dt[, .I[day==max(days)], by=ID]$V1]关于选择第一个值。 which.max 返回第一个最大值的索引,我在帖子上的代码确实给出了你所要求的。我不确定你现在期待什么。
  • 对不起。这是我的错。没有尝试,我认为它会在 days==max(days) 的任何地方选择所有值。
猜你喜欢
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多