Построить сетку на основе двух входных векторов - PullRequest
0 голосов
/ 17 ноября 2018

Я пытаюсь (используя R) построить "сетку" в матрице, основанной на двух входных векторах. Итак, идея состоит в том, чтобы избежать вложенного цикла, например:

inputVector1=1:4
inputVector2=1:4
grid=NULL
for(i in inputVector1){
  line=NULL
  for(j in inputVector2){
    cellValue=i+j # Instead of i+j it can be anything like taking a value in a dataframe
    line=cbind(line,cellValue)
  }
  grid=rbind(grid,line)
}

Есть ли в R специальная функция, позволяющая выполнять эту работу быстрее и проще? Я знаю, что есть функции семейства применений, но я не нашел подходящего способа сделать это (без объединения нескольких функций семейства применений). Спасибо за помощь.

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018
  1. Петли являются простыми и не обязательно медленными.Однако это зависит от того, как использовать эти циклы.Например, в вашем коде (я называю ваш подход L.GUEGAN(), для дальнейшей справки) вы не используете тот факт, что знаете размер вашей конечной сетки и продолжаете расширять векторы, матрицы.Это замедляет ход событий.Очень простой альтернативой будет

niceFor <- function() {
  grid <- matrix(0, nrow = length(inputVector1), ncol = length(inputVector2))
  for(i in seq_along(inputVector1))
    for(j in seq_along(inputVector2))
      grid[i, j] <- i + j
  grid
}

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

Да, вы можете сказать, что есть специальная функция для чего:

outer(inputVector1, inputVector2, `+`)

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

1:2 + 3:4
# [1] 4 6
`+`(1:2, 3:4)
# [1] 4 6

Однако некоторые другие функции не векторизованы.Например,

seq(3:4, 6:7)
# Error in seq.default(3:4, 6:7) : 'from' must be of length 1

В этом случае, если вы используете outer, взгляните на ?Vectorize.

Некоторые операции имеют даже «более прямые» выделенные функции.Например, если бы у нас было

grid[i, j] <- i * j

Тогда вы должны использовать

inputVector1 %*% t(inputVector2)

, так как это будет быстрее и чище, чем обе петли и outer.

Сравнение трех подходов, упомянутых ранее

microbenchmark(L.GUEGAN(), niceFor(), funOuter(), times = 2000)
# Unit: microseconds
#        expr    min      lq      mean  median     uq     max neval cld
#  L.GUEGAN() 24.354 33.8645 38.933968 35.6315 40.878 295.661  2000   c
#   niceFor()  4.011  4.7820  6.576742  5.4050  7.697  29.547  2000 a  
#  funOuter()  4.928  6.1935  8.701545  7.3085 10.619  74.449  2000  b 

Таким образом, хороший цикл for кажется даже превосходящим, если скорость имеет значение.Обратите внимание, что вы можете улучшить его, используя симметрию вашей сетки: вы можете вычислить только половину матрицы вручную, а затем использовать результаты, чтобы заполнить другой треугольник.

0 голосов
/ 17 ноября 2018

Спасибо @hrbrmstr, вот что я искал:

outer( 1:4, 1:4, function(a,b){mapply(FUN = function(x,y){return(x+y)},a,b)} )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...