按另一个顺序对向量重新排序

Mar*_*rcW 4 sorting r rcpp

我有两个向量:

vec1 <- c(0, 1, 2, 3, 4, 5, 6, 7, 9)
vec2 <- c(1, 2, 7, 5, 3, 6, 80, 4, 8)
Run Code Online (Sandbox Code Playgroud)

我想设置相同的顺序vec1,因为它是在vec2。例如,vec2最高数字(位置 9)在位置 7,所以我想将vec1(位置 9,数字 9)中的最高数字放到位置 7。

预期输出:

vec1 <- c(0, 1, 6, 4, 2, 5, 9, 3, 7)
Run Code Online (Sandbox Code Playgroud)

我在任何向量中都没有任何重复值。

我主要对高效的 Rcpp 解决方案感兴趣,但也欢迎 R 中的任何内容。

mar*_*kus 9

另一种baseR选择是match

vec1[match(vec2, sort(vec2))]
# [1] 0 1 6 4 2 5 9 3 7
Run Code Online (Sandbox Code Playgroud)

编辑

包括具有更大样本量的基准

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]
Run Code Online (Sandbox Code Playgroud)

结果

# 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
Run Code Online (Sandbox Code Playgroud)


duc*_*ayr 6

我们可以调整来自这个答案Rcpp版本(考虑到您不想检查重复项并按排序顺序添加函数)以制定以下解决方案:order()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];
}
Run Code Online (Sandbox Code Playgroud)

然后我们得到了预期的结果:

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
Run Code Online (Sandbox Code Playgroud)

具有不错的性能(与其他答案提供的 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
Run Code Online (Sandbox Code Playgroud)

请注意,此解决方案仅在没有重复项时才有效。(如果您可能遇到重复项,请在链接到的答案中演示添加检查)。另请注意,这些基准只是针对这些数据进行的;我不确定它们是如何大规模变化的。


akr*_*run 5

我们可以用 rank

vec1[rank(vec2)]
#[1] 0 1 6 4 2 5 9 3 7
Run Code Online (Sandbox Code Playgroud)

或与 order

vec1[order(order(vec2))]
#[1] 0 1 6 4 2 5 9 3 7
Run Code Online (Sandbox Code Playgroud)

或者@markus 建议了一个选项frankfromdata.table

library(data.table)
vec1[frank(vec2)]
Run Code Online (Sandbox Code Playgroud)

  • 只是用“data.table::frank()”对你的第一个选项进行了基准测试,到目前为止它似乎优于所有其他选项。也许也包括该选项? (3认同)