我们正在寻找一个快速解决以下问题的解决方案,在R中(允许使用Rcpp)。
我有一个角色矢量:
set.seed(42)
x <- sample(LETTERS[1:4], 1e6, replace = TRUE)
我想将其更改为非连续数字向量,其中:
A = 5
B = 4
C = 3
D = 1
例如:
c("A", "B", "C", "D")
将是:
c(5,4,3,1)
实习生和我已经拥有了我们认为的快速解决方案,但我们认为互联网可以打败我们。在得到一些回复之后,我们将添加我们最快的解决方案作为答案。
让我们看看!
到目前为止的时间:
library(microbenchmark)
set.seed(42)
x <- sample(LETTERS[1:4], 1e6, replace = TRUE)
richscriven <- function(x) {
as.vector(c(A=5, B=4, C=3, D=2, E=1)[x])
}
richscriven_unname <- function(x) {
unname(c(A=5, B=4, C=3, D=2, E=1)[x])
}
richscriven_op <- function(x) {
(5:1)[c(factor(x))]
}
op_and_interns_fun <- function(x) {
c(5,4,3,1)[as.numeric(as.factor(x))]
}
ronakshah <- function(x) {
vec = c("A" = 5, "B" = 4, "C" = 3, "D" = 1)
unname(vec[match(x, names(vec))])
}
microbenchmark(
richscriven_unname(x),
richscriven(x),
richscriven_op(x),
op_and_interns_fun(x),
ronakshah(x),
times = 15
)
Unit: milliseconds
expr min lq mean median uq max neval
richscriven_unname(x) 36.06018 38.01026 62.80854 38.87179 41.86411 337.65773 15
richscriven(x) 37.90615 41.61194 43.50555 44.14130 45.17277 47.47804 15
richscriven_op(x) 31.70345 37.43262 44.10522 41.34828 45.22127 88.79605 15
op_and_interns_fun(x) 40.18935 44.20475 49.48811 45.77867 48.15706 99.85034 15
ronakshah(x) 29.36408 32.52615 42.40753 35.09052 38.55763 95.78571 15
答案 0 :(得分:3)
我们可以将矢量放在一个命名的数字向量
中vec <- c("A" = 5, "B" = 4, "C" = 3, "D" = 1)
然后我们可以写一个函数,
get_recoded_data <- function(num_vec, recode_data) {
unname(recode_data[match(num_vec, names(recode_data))])
}
并使用
调用该函数get_recoded_data(x, vec)
在我的系统上,
system.time(get_recoded_data(x, vec))
#user system elapsed
#0.028 0.004 0.032
我正在使用MacOS Sierra 10.12.6,16GB RAM i7 RStudio 1.1.383
来自@ zacdav的评论使用fmatch
包中的fastmatch
函数提供了良好的效果提升
get_recoded_data <- function(num_vec, recode_data) {
unname(recode_data[fmatch(num_vec, names(recode_data))])
}
检查相同的数据,我得到了
system.time(get_recoded_data(x, vec))
#user system elapsed
#0.017 0.004 0.021
答案 1 :(得分:1)
我们的答案依赖于一种不太常见的按位置分组的方法:
op_and_interns_fun <- function(x) {
c(5,4,3,1)[as.numeric(as.factor(x))]
}