【问题标题】:Reorder rows in data.table in a specific order按特定顺序重新排序 data.table 中的行
【发布时间】:2016-10-19 02:49:30
【问题描述】:

我有一个data.tabledumdt

set.seed(123)
dumdt <- data.table(v1=sample(1:10, 5), v2=1:5)

我想按照这个特定的索引顺序重新排序哪些行(首先是第三个观察,然后是第五个,然后是第二个,等等):

to_ord <- c(3, 5, 2, 1, 4)

所以我希望dumdt 成为dumdt[to_ord] 的结果,但我也希望通过引用来实现,避免使用dumdt &lt;- dumdt[to_ord]

我知道我可以通过引用setorder(或setorderv)对行重新排序,但只能根据一个或多个变量,按升序或降序排列,而不是按自定义顺序。
但是,如果我想按自定义顺序重新排序列而不是行,我可以使用setcolorder

所以我的问题来了:是否有一个函数可以像 setcolorder 一样工作但与行(或使用 setorder 来做同样的事情)?

我想要的输出是这样的

setroworder(x=dumdt, neworder=to_ord)
dumdt
   # v1 v2
# 1:  4  3
# 2:  6  5
# 3:  8  2
# 4:  3  1
# 5:  7  4

【问题讨论】:

  • setorder(cbind(dumdt,to_ord),to_ord)(然后将 to_ord 设置为 NULL)不够快吗?
  • @EricLecoutre 谢谢你的评论,我不确定cbind 的使用是否有效,但无论如何,这会改变cbind 的未分配输出而不是初始对象,这样不会真的有帮助。 (实际上我非常确信输出不会是预期的......)
  • 是的...确实。参考文献总是有些困难...

标签: r sorting data.table


【解决方案1】:

如果我理解正确,您可以添加一个 col 然后按它排序:

setorder(dumdt[, .r := order(to_ord)], .r)[, .r := NULL]

   v1 v2
1:  4  3
2:  6  5
3:  8  2
4:  3  1
5:  7  4

【讨论】:

  • to_ord 的顺序“加倍”的好方法,我不知道如何在上面使用顺序,没有想到order(order(to_ord))==to_ord :-)
  • 好的,但是如果我们在dumdt 中添加一行或者从dumdt 中删除一行呢?然后我们需要以某种方式修改to_ord...
  • @JS1204 通过引用添加和删除行是不可能的,尽管您可以通过子集或使用 rbind 创建一个新表。如果您想删除某些内容,我想将其 to_ord 值设置为 NA 然后过滤掉 NA 可能会起作用;但我不确定在这里添加一行是什么意思。您可以尝试提出一个新问题(因为我认为我的评论还不够,因为我不完全理解您所描述的问题)
  • 谢谢。我正在考虑dumdt 与原始帖子中的情况略有不同的情况。原帖是一个特例,v2to_ord 包含完全相同数量的元素,而v2 的所有元素都是唯一的。
【解决方案2】:

此功能(尚未)导出。在查看setorderv 的源代码后,我能够提取对 C 函数的所需调用,该函数可以满足您的需求并为其提供自定义顺序。

library(data.table)
set.seed(123)
dumdt <- data.table(v1=sample(1:10, 5), v2=1:5)
print(dumdt)
#   v1 v2
#1:  3  1
#2:  8  2
#3:  4  3
#4:  7  4
#5:  6  5
setroworder <- function(x, neworder) {
    .Call(data.table:::Creorder, x, as.integer(neworder), PACKAGE = "data.table")
    invisible(x)
}
to_ord <- c(3, 5, 2, 1, 4)
setroworder(x=dumdt, neworder=to_ord)
print(dumdt)
#   v1 v2
#1:  4  3
#2:  6  5
#3:  8  2
#4:  3  1
#5:  7  4

不过,Frank 提出的解决方案看起来要好一些。

【讨论】:

  • 这对我来说就像魔术一样 ;-) 非常感谢,您刚刚创建了我希望存在的功能。现在我觉得自己像个被宠坏的女孩;-)
  • 总的来说,我认为弗兰克的回答更正确一点,因为它只依赖于从 data.table 导出的函数,不像我的 ::: 用于访问未导出的函数。
  • 您认为Creorder 可能会被修改为您的功能将不再起作用?可能这两个答案都有其优点/缺陷。我同意弗兰克的更“适合”日常使用,但你的在弗兰克提到的“酷方式”中不那么“普通”:-)(显然我并不是在暗示任何“坏”的东西弗兰克的回答,也真的很棒)
  • @Frank 好点,订购两次。顺便提一句。如果有人愿意,可以对 Frank 的解决方案进行包装:setroworder &lt;- function(x, neworder) setorderv(x[, eval(call(":=", as.name(".r"), call("order", neworder)))], ".r")[, ".r" := NULL]
猜你喜欢
  • 2022-09-29
  • 1970-01-01
  • 2018-03-28
  • 1970-01-01
  • 2022-06-28
  • 2014-08-17
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
相关资源
最近更新 更多