如何使用目标向量对data.table进行排序

11

所以,我有以下数据表格

DT = data.table(x=rep(c("b","a","c"),each=3), y=c(1,2,3))

> DT
   x y
1: b 1
2: b 2
3: b 3
4: a 1
5: a 2
6: a 3
7: c 1
8: c 2
9: c 3

我有以下向量:

k <- c("2","3","1")

我想使用k作为目标向量,利用yDT进行排序,得到类似以下的结果。

> DT
   x y
1: b 2
2: a 2
3: c 2
4: b 3
5: a 3
6: c 3
7: b 1
8: a 1
9: c 1

有什么想法吗?如果我使用DT [order(k)],我会得到原始数据的一个子集,这不是我所要寻找的。

3个回答

19

在其中加入一次对 match() 的调用。

DT[order(match(y, as.numeric(k)))]
#    x y
# 1: b 2
# 2: a 2
# 3: c 2
# 4: b 3
# 5: a 3
# 6: c 3
# 7: b 1
# 8: a 1
# 9: c 1

实际上 DT[order(match(y, k))] 也可以工作,但为了安全起见,最好确保match()的参数属于相同类别。

注意: 在某些情况下,已知match()效率不佳。如果您有大量行数据,您可能希望切换到fastmatch::fmatch以获得更快的匹配速度。


如何使用这个逻辑来使用目标向量k对多列进行排序? - undefined

3
你可以这样做:
DT = data.table(x=rep(c("b","a","c"),each=3), y=c(1,2,3))
k <- c("2","3","1")
setkey(DT,y)
DT[data.table(as.numeric(k))]

或者(来自Richard的评论)
DT = data.table(x=rep(c("b","a","c"),each=3), y=c(1,2,3))
k <- c("2","3","1")
DT[data.table(y = as.numeric(k)), on = "y"] 

1
现在你可以只需执行 DT[data.table(y = as.numeric(k)), on = "y"] 来按 y 合并,而不必设置键。 - Rich Scriven

0
我想知道是否可以将这个答案中提出的方法(使用ordermatch)扩展到使用目标向量对多列进行排序。我想到了以下的方法,希望能够发布出来,也许对其他人也有用。
这个方法有点复杂,也许有更聪明、更简洁的方法吗?
library(data.table)
set.seed(42L)
DT <- data.table(
  x = rep(letters[1:3], each = 3), 
  y = sample(letters[1:3], 9, TRUE),
  z = c(1, 2, 3)
)

k <- c("b", "a", "c")

x <- DT[, lapply(.SD, match, table = k), .SDcols = c("x", "y")]

# https://dev59.com/y4nca4cB1Zd3GeqP-27i#29483058
ii <- do.call(order, x)

DT[ii]
#>    x y z
#> 1: b b 2
#> 2: b b 3
#> 3: b a 1
#> 4: a a 1
#> 5: a a 2
#> 6: a a 3
#> 7: c b 1
#> 8: c a 2
#> 9: c c 3

第二种方法是将列转换为factor,并将levels设置为k。然后按照这两列进行排序。可以使用set*函数来实现。大致如下;
# method2
DT2 <- copy(DT)

for(col in c("x", "y")) {
  set(DT2, j = col, value = factor(DT[[col]], levels = k))  
}

setorderv(DT2, col = c("x", "y"))
DT2
#>    x y z
#> 1: b b 2
#> 2: b b 3
#> 3: b a 1
#> 4: a a 1
#> 5: a a 2
#> 6: a a 3
#> 7: c b 1
#> 8: c a 2
#> 9: c c 3

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