到目前为止,已经发布了三种不同的方法:
- using match() https://stackoverflow.com/a/43521841/3817004
- using dplyr https://stackoverflow.com/a/43521923/3817004
- using merge() https://stackoverflow.com/a/43522640/3817004
还有第四种方法称为更新加入弗兰克在聊天中建议:
library(data.table)
setDT(sample)[, yr := year(Date)][setDT(a), on = .(yr = a), `:=`(y = i.y, Z = i.Z)]
事实证明这是四个中最快、最简洁的。
基准测试结果:
为了确定哪种方法在速度方面最有效,我使用以下方法设置了基准microbenchmark
package.
Unit: microseconds
expr min lq mean median uq max neval
create_data 248.827 291.116 316.240 302.0655 323.588 665.298 100
match 4488.685 4545.701 4752.226 4649.5355 4810.763 6881.418 100
dplyr 6086.609 6275.588 6513.997 6385.2760 6625.229 8535.979 100
merge 2871.883 2942.490 3183.712 3004.6025 3168.096 5616.898 100
update_join 1484.272 1545.063 1710.651 1659.8480 1733.476 3434.102 100
As sample
被修改后,必须在每次基准测试运行之前重新创建。这是由基准测试中包含的函数完成的(创建数据)。时间为创建数据需要从其他时间中减去。
因此,即使对于大约 1800 行的小数据集,更新加入是最快的,几乎是第二个的两倍merge, 其次是match, and dplyr是最后一个,慢了 4 倍以上更新加入(与时间创建数据减去)。
基准代码
datess <- seq(as.Date('2005-01-01'), as.Date('2009-12-31'), 'days')
a <- data.frame(Z = c(1, 3, 4, 5, 2),
a = 2005:2009,
y = c('abc', 'def', 'ijk', 'xyz', 'thanks'),
stringsAsFactors = FALSE)
setDT(a)
make_sample <- function() data.frame(Date = datess, y = NA_character_, Z = NA_real_)
library(data.table)
library(magrittr)
microbenchmark::microbenchmark(
create_data = make_sample(),
match = {
sample <- make_sample()
matched<-match(format(sample$Date,"%Y"),a$a)
sample$y<-a$y[matched]
sample$Z<-a$Z[matched]
},
dplyr = {
sample <- make_sample()
sample <- sample %>%
dplyr::mutate(a = format(Date, "%Y") %>% as.numeric) %>%
dplyr::inner_join(a %>% dplyr::select(a), by = "a")
},
merge = {
sample <- make_sample()
sample2 <- data.frame(Date = datess)
sample2$a <- lubridate::year(sample2$Date)
sample <- base::merge(sample2, a, by="a")
},
update_join = {
sample <- make_sample()
setDT(sample)[, yr := year(Date)][a, on = .(yr = a), `:=`(y = i.y, Z = i.Z)]
}
)