【发布时间】:2012-07-19 10:43:55
【问题描述】:
我有一个数据框full,我想从中获取最后一列和一列v。然后我想以最快的方式对v 上的两列进行排序。 full 是从 csv 读取的,但这可用于测试(包括一些真实性的 NA):
n <- 200000
full <- data.frame(A = runif(n, 1, 10000), B = floor(runif(n, 0, 1.9)))
full[sample(n, 10000), 'A'] <- NA
v <- 1
我这里有v,但实际上它可能会改变,full 有很多列。
我尝试使用order 和sort.list 对数据框、数据表和矩阵进行排序(一些想法来自this thread)。所有这些的代码:
# DATA FRAME
ord_df <- function() {
a <- full[c(v, length(full))]
a[with(a, order(a[1])), ]
}
sl_df <- function() {
a <- full[c(v, length(full))]
a[sort.list(a[[1]]), ]
}
# DATA TABLE
require(data.table)
ord_dt <- function() {
a <- as.data.table(full[c(v, length(full))])
colnames(a)[1] <- 'values'
a[order(values)]
}
sl_dt <- function() {
a <- as.data.table(full[c(v, length(full))])
colnames(a)[1] <- 'values'
a[sort.list(values)]
}
# MATRIX
ord_mat <- function() {
a <- as.matrix(full[c(v, length(full))])
a[order(a[, 1]), ]
}
sl_mat <- function() {
a <- as.matrix(full[c(v, length(full))])
a[sort.list(a[, 1]), ]
}
时间结果:
ord_df sl_df ord_dt sl_dt ord_mat sl_mat
Min. 0.230 0.1500 0.1300 0.120 0.140 0.1400
Median 0.250 0.1600 0.1400 0.140 0.140 0.1400
Mean 0.244 0.1610 0.1430 0.136 0.142 0.1450
Max. 0.250 0.1700 0.1600 0.140 0.160 0.1600
或使用microbenchmark(结果以毫秒为单位):
min lq median uq max
1 ord_df() 243.0647 248.2768 254.0544 265.2589 352.3984
2 ord_dt() 133.8159 140.0111 143.8202 148.4957 181.2647
3 ord_mat() 140.5198 146.8131 149.9876 154.6649 191.6897
4 sl_df() 152.6985 161.5591 166.5147 171.2891 194.7155
5 sl_dt() 132.1414 139.7655 144.1281 149.6844 188.8592
6 sl_mat() 139.2420 146.8578 151.6760 156.6174 186.5416
似乎订购数据表获胜。 order 和 sort.list 之间没有太大区别,除非使用 sort.list 更快的数据帧。
在数据表版本中,我还尝试将v 设置为键(因为它是根据文档进行排序的),但由于v 的内容不是整数,我无法让它工作。
理想情况下,我希望尽可能加快速度,因为对于不同的v 值,我必须多次执行此操作。有谁知道我如何能够进一步加快这个过程?是否值得尝试Rcpp 实现?谢谢。
这是我用来计时的代码,如果它对任何人有用的话:
sortMethods <- list(ord_df, sl_df, ord_dt, sl_dt, ord_mat, sl_mat)
require(plyr)
timings <- raply(10, sapply(sortMethods, function(x) system.time(x())[[3]]))
colnames(timings) <- c('ord_df', 'sl_df', 'ord_dt', 'sl_dt', 'ord_mat', 'sl_mat')
apply(timings, 2, summary)
require(microbenchmark)
mb <- microbenchmark(ord_df(), sl_df(), ord_dt(), sl_dt(), ord_mat(), sl_mat())
plot(mb)
【问题讨论】:
-
我不知道您的确切规格,但如果他们允许,请考虑在您的排序功能之外运行一次像
full <- as.matrix(full)或full <- as.data.table(full)这样的东西。这些转换可能会对您的计算时间产生重大影响,而它们并没有真正进行排序。 -
好吧,
full最初是一个数据框,在进行任何排序之前(我无法更改),因此将其转换为矩阵或数据表是排序方法的一部分,因此需要包括在我认为的时间安排中。 -
请升级到 data.table v1.8.2,现在在 CRAN 上。一条评论是您无法在非整数列上设置键 - 现在在 1.8.2 中可以,请参阅 NEWS。在 v 上设置一个键应该更快,是的。此外,您似乎在排序时间中包括了转换为 data.table 的时间。这公平吗?但是,您可能会发现在 1.8.2 中转换的时间比在 1.8.0 中要快得多。 +1顺便说一句。好问题。
-
您可能还需要超过 200,000 行。每当我看到报告的无关紧要的时间有显着差异时,我通常都会翻白眼。您是说 data.table 以 0.13 秒和 0.23 秒为基础获胜?我会说这是微不足道的。请参阅 vignette("datatable-timings") 了解我认为是好的基准。 8.8 秒减少到 0.013(快 678 倍),22.6 秒减少到 1.1 秒(胖 19 倍)。这些是重要时期的重大差异。您(几乎)有足够时间在等待时泡杯茶的任务。
-
对于
ord_df,不需要with。您的速度差异是由于订购数据帧order(a[1])而不是矢量order(a[[1]]);order(a[[1]])就像sort.list(a[[1]])。如果要排序的列实际上是整数值,那么sort.list(..., method="radix")非常快(比 data.table 快?)。
标签: r data.table