按另一个向量的顺序重新排序向量
Reorder a vector by order of another
我有两个向量:
vec1 <- c(0, 1, 2, 3, 4, 5, 6, 7, 9)
vec2 <- c(1, 2, 7, 5, 3, 6, 80, 4, 8)
我想在 vec1
中设置与 vec2
中相同的顺序。比如vec2
中最高的数字(9号位)在7号位,所以我想把vec1
中的最高号(9号位,9号)放到7号位。
预期输出:
vec1 <- c(0, 1, 6, 4, 2, 5, 9, 3, 7)
我在任何向量中都没有任何重复值。
我主要对高效的 Rcpp 解决方案感兴趣,但也欢迎使用 R 中的任何内容。
如果我没理解错的话,你希望 vec1 遵循与 vec1 相同的顺序。也就是说,如果 vec2 在增加,那么 vec1 的值也应该增加;如果 vec2 正在减少,vec1 也应该减少,依此类推。
sort(vec1)[order(vec2)]
另一个baseR
选项是match
vec1[match(vec2, sort(vec2))]
# [1] 0 1 6 4 2 5 9 3 7
编辑
包括样本量较大的基准
set.seed(42)
n <- 1e6
vec1 <- seq_len(n)
vec2 <- sample(1:1e7, size = n)
benchmarks <- bench::mark(match = vec1[match(vec2, sort(vec2))],
rank = vec1[rank(vec2)],
frank = vec1[data.table::frank(vec2)],
order_order = vec1[order(order(vec2))],
rcpp_order_order = foo(vec1, vec2),
iterations = 25)
benchmarks[ , 1:3]
结果
# A tibble: 5 x 3
# expression min median
# <bch:expr> <bch:tm> <bch:tm>
#1 match 259.8ms 322ms
#2 rank 825.9ms 876ms
#3 frank 88.6ms 134ms
#4 order_order 110.6ms 139ms
#5 rcpp_order_order 793.5ms 893ms
我们可以使用 rank
vec1[rank(vec2)]
#[1] 0 1 6 4 2 5 9 3 7
或 order
vec1[order(order(vec2))]
#[1] 0 1 6 4 2 5 9 3 7
或者正如@markus 建议的 frank
来自 data.table
的选项
library(data.table)
vec1[frank(vec2)]
我们可以从 this answer 改编 order()
的 Rcpp
版本(考虑到您不想检查重复项并添加一个函数以按排序顺序)做出以下 Rcpp
解决方案:
#include <Rcpp.h>
Rcpp::IntegerVector order(const Rcpp::NumericVector& x) {
return Rcpp::match(Rcpp::clone(x).sort(), x);
}
Rcpp::IntegerVector order(const Rcpp::IntegerVector& x) {
return Rcpp::match(Rcpp::clone(x).sort(), x);
}
// [[Rcpp::export]]
Rcpp::NumericVector foo(const Rcpp::NumericVector x,
const Rcpp::NumericVector y) {
return x[order(order(y))-1];
}
然后我们得到了预期的结果:
library(Rcpp)
sourceCpp("foo.cpp")
vec1 <- c(0, 1, 2, 3, 4, 5, 6, 7, 9)
vec2 <- c(1, 2, 7, 5, 3, 6, 80, 4, 8)
foo(vec1, vec2)
# [1] 0 1 6 4 2 5 9 3 7
具有不错的性能(与其他答案提供的 R 解决方案进行比较):
benchmarks <- bench::mark(match = vec1[match(vec2, sort(vec2))],
rank = vec1[rank(vec2)],
order_order = vec1[order(order(vec2))],
rcpp_order_order = foo(vec1, vec2),
iterations = 10000)
benchmarks[ , 1:3]
# # A tibble: 4 x 3
# expression min median
# <bch:expr> <bch:tm> <bch:tm>
# 1 match 28.4µs 31.72µs
# 2 rank 7.99µs 9.84µs
# 3 order_order 26.27µs 30.61µs
# 4 rcpp_order_order 2.51µs 3.23µs
请注意,此解决方案仅在没有重复的情况下才有效。 (如果您可能 运行 重复,添加支票将在链接答案中演示)。另请注意,这些基准测试只是针对此数据完成的;我不确定它们是如何大规模变化的。
我有两个向量:
vec1 <- c(0, 1, 2, 3, 4, 5, 6, 7, 9)
vec2 <- c(1, 2, 7, 5, 3, 6, 80, 4, 8)
我想在 vec1
中设置与 vec2
中相同的顺序。比如vec2
中最高的数字(9号位)在7号位,所以我想把vec1
中的最高号(9号位,9号)放到7号位。
预期输出:
vec1 <- c(0, 1, 6, 4, 2, 5, 9, 3, 7)
我在任何向量中都没有任何重复值。
我主要对高效的 Rcpp 解决方案感兴趣,但也欢迎使用 R 中的任何内容。
如果我没理解错的话,你希望 vec1 遵循与 vec1 相同的顺序。也就是说,如果 vec2 在增加,那么 vec1 的值也应该增加;如果 vec2 正在减少,vec1 也应该减少,依此类推。
sort(vec1)[order(vec2)]
另一个baseR
选项是match
vec1[match(vec2, sort(vec2))]
# [1] 0 1 6 4 2 5 9 3 7
编辑
包括样本量较大的基准
set.seed(42)
n <- 1e6
vec1 <- seq_len(n)
vec2 <- sample(1:1e7, size = n)
benchmarks <- bench::mark(match = vec1[match(vec2, sort(vec2))],
rank = vec1[rank(vec2)],
frank = vec1[data.table::frank(vec2)],
order_order = vec1[order(order(vec2))],
rcpp_order_order = foo(vec1, vec2),
iterations = 25)
benchmarks[ , 1:3]
结果
# A tibble: 5 x 3
# expression min median
# <bch:expr> <bch:tm> <bch:tm>
#1 match 259.8ms 322ms
#2 rank 825.9ms 876ms
#3 frank 88.6ms 134ms
#4 order_order 110.6ms 139ms
#5 rcpp_order_order 793.5ms 893ms
我们可以使用 rank
vec1[rank(vec2)]
#[1] 0 1 6 4 2 5 9 3 7
或 order
vec1[order(order(vec2))]
#[1] 0 1 6 4 2 5 9 3 7
或者正如@markus 建议的 frank
来自 data.table
library(data.table)
vec1[frank(vec2)]
我们可以从 this answer 改编 order()
的 Rcpp
版本(考虑到您不想检查重复项并添加一个函数以按排序顺序)做出以下 Rcpp
解决方案:
#include <Rcpp.h>
Rcpp::IntegerVector order(const Rcpp::NumericVector& x) {
return Rcpp::match(Rcpp::clone(x).sort(), x);
}
Rcpp::IntegerVector order(const Rcpp::IntegerVector& x) {
return Rcpp::match(Rcpp::clone(x).sort(), x);
}
// [[Rcpp::export]]
Rcpp::NumericVector foo(const Rcpp::NumericVector x,
const Rcpp::NumericVector y) {
return x[order(order(y))-1];
}
然后我们得到了预期的结果:
library(Rcpp)
sourceCpp("foo.cpp")
vec1 <- c(0, 1, 2, 3, 4, 5, 6, 7, 9)
vec2 <- c(1, 2, 7, 5, 3, 6, 80, 4, 8)
foo(vec1, vec2)
# [1] 0 1 6 4 2 5 9 3 7
具有不错的性能(与其他答案提供的 R 解决方案进行比较):
benchmarks <- bench::mark(match = vec1[match(vec2, sort(vec2))],
rank = vec1[rank(vec2)],
order_order = vec1[order(order(vec2))],
rcpp_order_order = foo(vec1, vec2),
iterations = 10000)
benchmarks[ , 1:3]
# # A tibble: 4 x 3
# expression min median
# <bch:expr> <bch:tm> <bch:tm>
# 1 match 28.4µs 31.72µs
# 2 rank 7.99µs 9.84µs
# 3 order_order 26.27µs 30.61µs
# 4 rcpp_order_order 2.51µs 3.23µs
请注意,此解决方案仅在没有重复的情况下才有效。 (如果您可能 运行 重复,添加支票将在链接答案中演示)。另请注意,这些基准测试只是针对此数据完成的;我不确定它们是如何大规模变化的。