Более эффективный способ получить матрицу данных, основанную на некоторой матрице значений и индексов в R? - PullRequest
3 голосов
/ 08 октября 2019

Предположим, у меня есть вектор значений вроде:

M=3;val<-rnorm(M)

и соответствующая индексная матрица, например:

N=20;J=10;ind<-matrix(sample(1:M,N*J,replace=T),nrow=J)

Я могу легко присвоить значения с их индексами, чтобы получить данныематрица как:

x<-matrix(val[ind],J,N)

Теперь у меня есть матрица значений, таких как:

val<-matrix(rnorm(M*J),nrow=J)

, и мне нужно присваивать значения и индексы построчно (т. е. одна строка в val с однойстрока в ind), чтобы получить матрицу данных.

Я могу сделать это с помощью цикла for следующим образом:

x<-ind;
for(j in 1:J){x[j,]<-val[j,ind[j,]]}

Но мне интересно, есть ли более эффективный способ сделать это, особенно во избежаниеиспользуя цикл for?

Мне нужно сделать повторную выборку и повторить процесс назначения сотни тысяч раз. Поэтому я переживаю, что цикл for займет много времени.

Ответы [ 2 ]

4 голосов
/ 08 октября 2019

В общем случае матрица может быть поднабором или назначаться поднабором с использованием двухколоночной матрицы в качестве индексов строк и столбцов. Итак

i_idx = rep(1:J, each = ncol(ind))
x_idx = cbind(i_idx, 1:ncol(ind))
val_idx = cbind(i_idx, as.vector(t(ind[1:J,])))

x[x_idx] = val[val_idx]
1 голос
/ 08 октября 2019

Еще три метода, один с использованием sapply, одно матричное поднабор и одно векторное подмножество . Матрица и векторное подмножество выглядят более быстрыми, то есть с sapply медленнее, чем цикл for.

В настоящее время

matrix(val[1:J + (ind-1)*J],J,N)

выглядит как самый быстрый способ.

M <- 3; N <- 20; J <- 10
ind <- matrix(sample(1:M,N*J,replace=T),nrow=J)
val <- matrix(rnorm(M*J),nrow=J)

x<-ind;
for(j in 1:J){x[j,]<-val[j,ind[j,]]}

identical(x, t(sapply(1:J, function(j) val[j,ind[j,]])))
#[1] TRUE

identical(x, matrix(val[matrix(c(rep(1:J, N), ind), ncol=2)],J,N))
#[1] TRUE
#Other ways for rep(1:J, N)
identical(x, matrix(val[matrix(c(row(ind), ind), ncol=2)],J,N))
#[1] TRUE
identical(x, matrix(val[matrix(c(slice.index(ind, 1), ind), ncol=2)],J,N))
#[1] TRUE

#Vector subsetting as suggested by Aaron
identical(x, matrix(val[row(ind) + (ind-1)*J],J,N))
#[1] TRUE
#Other ways
identical(x, matrix(val[1:J + (ind-1)*J],J,N))
#[1] TRUE
identical(x, matrix(val[sweep((ind-1)*J, 1, 1:J, "+")],J,N))
#[1] TRUE

Сравнение скорости:

library(microbenchmark)

f1 <- function() {
  x<-ind;
  for(j in 1:J){x[j,]<-val[j,ind[j,]]}
}
f2 <- function() {t(sapply(1:J, function(j) val[j,ind[j,]]))}
f3 <- function() {matrix(val[matrix(c(row(ind), ind), ncol=2)],J,N)}
f4 <- function() {matrix(val[row(ind) + (ind-1)*J],J,N)} #Comment from Aaron
f5 <- function() {matrix(val[1:J + (ind-1)*J],J,N)}

microbenchmark(f1(), f2(), f3(), f4(), f5(), setup=gc)
#Unit: microseconds
# expr    min      lq     mean  median      uq     max neval
# f1() 16.540 18.3595 20.11216 19.8820 20.7915  36.201   100
# f2() 43.514 46.3650 49.77573 48.0320 49.5120 113.631   100
# f3()  8.325  9.3265 10.38931  9.9425 10.4825  46.561   100
# f4()  6.934  7.8270  9.00286  8.4405  9.1355  25.840   100
# f5()  5.839  6.8730  7.71322  7.3520  8.3145  16.349   100
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...