使用data.table实现同时排序、行过滤和列选择

10

我将尝试在R中一行代码中完成多个步骤,以便通过多个条件从数据表(dt)中选择一个值。

例如:

set.seed(123)
dt <- data.table(id = rep(letters[1:2],2),
             time = rnorm(4),
             value = rnorm(4)*100)

#    id        time      value
# 1:  a -0.56047565   12.92877
# 2:  b -0.23017749  171.50650
# 3:  a  1.55870831   46.09162
# 4:  b  0.07050839 -126.50612

# Now I want to select the last (maximum time) value from id == "a"
# My pseudo data.table code looks like this

dt[order(time) & id == "a" & .N, value]
# [1] 12.92877 46.09162  

我想获取两个值中的最后一个值(具有更高的时间值),而不是获取两个值。

如果逐步执行,它可以正常工作:

dt <- dt[order(time) & id == "a"]
dt[.N, value]
# [1] 46.09162

附加信息:

如何在不复制数据表的情况下对数据表进行排序,例如:

dt <- dt[order(time)]

没有使用 <-。类似于 := 操作符,例如 dt[, new_val := value*2],它可以在不复制整个 data.table 的情况下创建新变量。

谢谢,任何想法都会受到高度赞赏!


1
你说 dt[order(time) & id == "a"] 可以工作,但是 order 返回的是一个整数而不是逻辑值,因此它会被强制转换为 TRUE,所以这等同于 dt[TRUE & id=="a"] 或者 dt[id=="a"]。你的例子很小,看起来好像可以在这里工作。 - Frank
2个回答

10

对于你的第一个问题,请尝试

dt[id == "a", value[which.max(time)]]
## [1] 46.09162

对于一个额外的问题,尝试使用setorder函数,它可以就地对您的数据进行排序(您还可以通过在time前面添加-来按降序排序)

setorder(dt, time)
dt
#    id        time      value
# 1:  a -0.56047565   12.92877
# 2:  b -0.23017749  171.50650
# 3:  b  0.07050839 -126.50612
# 4:  a  1.55870831   46.09162

此外,如果您已经按时间排序了您的数据,您可以在一行中通过引用进行排序并根据条件选择value

setorder(dt, time)[id == "a", value[.N]]

6
我知道这是一个比较老的问题,但我想补充一些内容。由于遇到了类似的问题,我偶然发现了这个问题。虽然David Arenburg的答案确实提供了解决这个问题的方法,但当我尝试替换/覆盖来自过滤和排序数据表的值时,我遇到了困难。因此,这里提供另一种替代方法,它还可以让您直接对过滤和排序的数据表应用<-调用。
关键在于data.table允许您将多个[]连接在一起。
例如:
dt[id=="a", ][order(time), ][length(value), "value"] <- 0

这也适用于多个条目,只需提供一个合适的向量作为替换值即可。
请注意,列表对象.N需要替换为列的长度等整数,因为data.table在i的这个位置期望一个整数,在j中选择要选择的列需要用""括起来。
我发现这是更直观的方式,它不仅可以过滤数据表,还可以操作其值,而无需担心临时表。

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