Использование функции над всеми парами строк двух матриц - PullRequest
0 голосов
/ 19 сентября 2018

Если я хочу вычислить n-мерное расстояние двух векторов, я могу использовать функцию, такую ​​как:

a = c(1:10)
b = seq(20, 23, length.out = length(a))

test_fun = 
  function(x,y) {
    return(
      sqrt(
        sum(
          (x - y) ^ 2
        )
      )
    )
  }

n_distance = test_fun(a,b)

Теперь я хочу расширить это до параметра матрицы: я хочу вычислитьn-мерное расстояние для каждой пары строк двух матриц.

set.seed(123)
a_mtx = matrix(1:30, ncol = 5)
b_mtx = matrix(sample(1:15,15), ncol = 5)

n_distance_mtx = 
matrix(
  NA,
  nrow = nrow(b_mtx), 
  ncol = nrow(a_mtx)
  )
for(i in 1:nrow(b_mtx)) {
 for(j in 1:nrow(a_mtx)) {
  n_distance_mtx[i,j] = 
    test_fun(a_mtx[j,], b_mtx[i,])
 }
}

Где каждый столбец n_distance_mtx содержит метрики расстояния между каждой строкой a_mtx и b_mtx (т. е. n_distance_mtx[,1]это расстояние между a_mtx[1,] и b_mtx[1:3,].

Если я вычислю значения столбца на n_distance_mtx, я могу получить среднее расстояние между каждой строкой в ​​a_mtx и всеми строками b_mtx.

colMeans(n_distance_mtx)
#[1] 23.79094 24.90281 26.15618 27.53303 29.01668 30.59220

Итак 23.79094 - это среднее расстояние между a_mtx[1,] и b_mtx[1:3,], а 24.90281 - среднее расстояние между a_mtx[2,] и b_mtx[1:3,], ии так далее.

Вопрос: Как я могу прийти к тому же решению без использования циклов for?

Я хочу применить этот метод к матрицам с гораздо большей размерностью (порядка сотен тысяч строк). Глядя на это и это , кажется, должен быть способ сделать это с помощью функции Vectorize d outer, но я не смог сгенерировать такую ​​функцию.

test_fun_vec = 
 Vectorize(
   function(x,y) {
     outer(
       x,
       y,
       test_fun
       )
   }
 )
test_fun_vec(a_mtx,b_mtx)
#[1]  4  0  2  7  4  6  3  5  1  5  7  5 10  0  9 11 15 17  8 11  9 12 10 16
#[25] 10 22 20 25 15 24

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Мы можем использовать Vectorize с outer

f1 <- Vectorize(function(i, j) test_fun(a_mtx[j, ], b_mtx[i, ]))
out <- outer(seq_len(nrow(b_mtx)), seq_len(nrow(a_mtx)), FUN = f1)
out
#         [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
#[1,] 20.88061 21.84033 22.97825 24.26932 25.69047 27.22132
#[2,] 24.87971 25.57342 26.43861 27.45906 28.61818 29.89983
#[3,] 25.61250 27.29469 29.05168 30.87070 32.74141 34.65545

colMeans(out)
#[1] 23.79094 24.90281 26.15618 27.53303 29.01668 30.59220

identical(n_distance_mtx, out)
#[1] TRUE
0 голосов
/ 19 сентября 2018

Если я правильно понял ваш вопрос, вам нужно евклидово расстояние между каждым вектором (строкой) в a_mtx и другими векторами в b_mtx.

Если это так, вы можете использовать apply дважды так:

result = apply(a_mtx, 1, function(x){ apply(b_mtx, 1, function(y){ test_fun(x,y) })})

Это дает матрицу расстояний:

         [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
[1,] 20.88061 21.84033 22.97825 24.26932 25.69047 27.22132
[2,] 24.87971 25.57342 26.43861 27.45906 28.61818 29.89983
[3,] 25.61250 27.29469 29.05168 30.87070 32.74141 34.65545

, где индекс строки - соответствующий вектор (строка) из b_mtx, а индекс столбца - соответствующий вектор из a_mtx

Наконец, получите среднее расстояние, используя:

colMeans(result)
[1] 23.79094 24.90281 26.15618 27.53303 29.01668 30.59220
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...