Эффективно вычесть вектор из матрицы на основе data.frame - PullRequest
1 голос
/ 27 мая 2020

У меня есть матрица X, два фрейма данных A и B и векторы индексов vec_a и vec_b. A и B содержат индексную переменную каждый, где значения соответствуют значениям в vec_a и vec_b. Помимо этого, A и B содержат столько значений, сколько столбцов в X:

# original data
X <- matrix(rnorm(200),100,2)

# values to substract in data.frames
A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))

# indices, which values to substract (one for each row of X)
vec_a <- sample(1:4, nrow(X), replace = T)
vec_b <- sample(1:4, nrow(X), replace = T)

Я хочу добиться следующего: для каждой строки iii в X получить значения value1 и value2 из A и B на основе элементов iii в векторах vec_a и vec_b. Затем вычтите эти значения из соответствующей строки в X. Может показаться немного запутанным, но я надеюсь, что следующее решение проясняет цель:

# iterate over all rows of X 
for(iii in 1:nrow(X)){

  # get correct values
  X_clean <- A[which(A$index_a == vec_a[iii]),-1] -    # subtract correct A value
             B[which(B$index_b == vec_b[iii]),-1]      # subtract correct B value

  # this intermediate step is necessary, otherwise we substract a data.frame from a matrix
  X_clean <- as.numeric(X_clean)  

  # subtract from X
  X[iii,] = X[iii,] - X_clean

}

Обратите внимание, что мы должны преобразовать в numeric в моем решении l oop, иначе X теряет класс matrix, поскольку мы вычитаем data.frame из matrix. Мое решение работает нормально, пока вам не понадобится делать это для многих матриц, таких как A и B, и для миллионов наблюдений. Есть ли решение, которое не полагается на цикл по всем строкам?

EDIT

Спасибо, оба ответа значительно улучшают скорость кода. Я выбрал ответ StupidWolf, поскольку он более эффективен, чем использование data.table:

Unit: microseconds
        expr        min         lq       mean     median         uq        max neval cld
   datatable   5557.355   5754.931   6052.402   5881.729   5975.386  14154.040   100  b 
 stupid.wolf    818.529   1172.840   1311.784   1187.593   1221.164   4777.743   100 a  
        loop 111748.790 115141.149 116677.528 116109.571 117085.048 156497.999   100   c

Ответы [ 2 ]

2 голосов
/ 27 мая 2020

Вы можете просто сопоставить строки:

set.seed(111)
# original data
X <- matrix(rnorm(200),100,2)

A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))

vec_a <- sample(1:4, nrow(X), replace = T)
vec_b <- sample(1:4, nrow(X), replace = T)

newX <- X - as.matrix(A[match(vec_a,A$index_a),-1]-B[match(vec_b,B$index_b),-1])

Затем мы запускаем ваш l oop:

for(iii in 1:nrow(X)){

  X_clean <- A[which(A$index_a == vec_a[iii]),-1] -    # subtract correct A value
             B[which(B$index_b == vec_b[iii]),-1]      # subtract correct B value

  X_clean <- as.numeric(X_clean)  
  X[iii,] = X[iii,] - X_clean
}

И проверяем, что значения равны:

all.equal(c(newX),c(X))
[1] TRUE

Соответствие должно быть довольно быстрым, но если оно все еще слишком медленное, вы можете просто вызвать значения A, используя vec_a, например A[vec_a,] ..

1 голос
/ 27 мая 2020

В этом подходе используется data.table для простого соединения.

library(data.table)
set.seed(111)
X <- matrix(rnorm(200),100,2)
A <- data.frame(index_a = 1:4, value1 = rnorm(4), value2 = rnorm(4))
B <- data.frame(index_b = 1:4, value1 = rnorm(4), value2 = rnorm(4))
vec_a <- sample(1:4, nrow(X), replace = T)
vec_b <- sample(1:4, nrow(X), replace = T)
setDT(A);setDT(B)
dtX <- as.data.table(cbind(1:nrow(X),X,vec_a,vec_b))

as.matrix(
  dtX[A, on = .(vec_a = index_a)][B,
      on = .(vec_b = index_b)][order(V1),
       .(V2 - (value1 - i.value1), V3 - (value2 - i.value2))]
  )
            V1      V2
  [1,]  0.22746  0.7069
  [2,]  1.84340 -0.1258
  [3,] -0.70038  1.2494
...
 [98,]  2.04666  0.6767
 [99,]  0.02451  1.0473
[100,] -2.72553 -0.6595

Надеюсь, это будет довольно быстро для очень больших матриц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...