Эффективный способ получить матрицу с попарным максимумом между двумя значениями - PullRequest
0 голосов
/ 31 мая 2019

Я хочу создать матрицу, которая для записи i,j возвращает максимум от D[i,1] до D[j,1].

У меня есть вектор чисел, который в MWE может быть уменьшен до этого:

set.seed(10)
n <- 2000 
D <- matrix(runif(n,0,100), ncol=1)

С двойным циклом for в Base R это крайне неэффективно:

X <- Matrix::Matrix(0, nrow = n, ncol = n, sparse = T)

for (i in 1:n) {
  for (j in 1:n) {
    X[i,j] <- max(D[i,1], D[j,1])
  }
}

Я также пытался с dplyr :

library(dplyr)

X <- tibble(i = 1:n, D = D)

X <- expand.grid(i = 1:n, j = 1:n)

X <- X %>%
  as_tibble() %>%
  left_join(X, by = "i") %>%
  left_join(X, by = c("j" = "i")) %>%
  rowwise() %>%
  mutate(D = max(D.x, D.y)) %>%
  ungroup()

возвращает Error: std::bad_alloc, прежде чем я смогу сделать X <- Matrix::Matrix(X$D, nrow = n, ncol = n, sparse = T)

Моя последняя попытка состояла в том, чтобы использовать RcppArmadillo таким образом, что он также работает с Windows:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

using namespace Rcpp;

// [[Rcpp::export]]
arma::mat pairwise_max(arma::mat x, arma::mat y) {
  // Constants
  int n = (int) x.n_rows;

  // Output
  arma::mat z(n,n);

  // Filling with ones
  z.ones();

  for (int i=0; i<n; i++)
    for (int j=0; j<=i; j++) {
      // Fill the lower part
      z.at(i,j) = std::max(y(i,0), y(j,0));
      // Fill the upper part
      z.at(j,i) = z.at(i,j);
    }

    return z;
}

это работает почти безупречно, но я вполне уверен, что есть эффективный способ с базой R, который я не вижу.

1 Ответ

2 голосов
/ 31 мая 2019

В базе R я бы сделал

D2 <- drop(D)
X2 <- outer(D2, D2, pmax)

, что примерно в 20 раз быстрее, чем удвоенный цикл for.

...