Матричные вычисления в R-функции

#r #matrix

#r #матрица

Вопрос:

Я пытаюсь закодировать функцию, которая определит, какая строка матрицы nxm M ближе всего к вектору y длины m.

Пожалуйста, что я делаю не так в своем коде? Я стремлюсь к тому, чтобы функция создавала вектор-столбец длиной n, который дает расстояние между координатами каждой строки матрицы и вектором y. Затем я хочу вывести номер строки матрицы, для которой это ближайшая точка к вектору.

 closest.point <- function(M, y) {
  p <- length(y)
  k <- nrow(M)
  T <- matrix(nrow=k)
  T <- for(i in 1:n) 
    for(j in 1:m) {
      (X[i,j] - x[j])^2   (X[i,j] - x[j])^2
    }
  W <- rowSums(T)
  max(W)
  df[which.max(W),]
}
 

Ответ №1:

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

В вашей функции были некоторые ошибки. Существуют некоторые неопределенные переменные, такие как n, m или X.

Также старайтесь избегать именования переменных как T, поскольку R интерпретирует T как TRUE . Это работает, но может привести к некоторым ошибкам, если использовать T как TRUE в следующих строках кода.

При циклическом выполнении вам нужно указать индекс вашей переменной, которую вы обновляете, например T.matrix[i, j], а не только T.matrix, поскольку это перезапишет T.matrix на каждой итерации.

 closest.point <- function(M, y) {
  k <- nrow(M)
  m <- ncol(M)
  T.matrix <- matrix(nrow = k, ncol = m)

  for (i in 1:k) {
    for (j in 1:m) {
      T.matrix[i, j] <- (M[i,j] - y[j])^2   (M[i,j] - y[j])^2
    }
  }
  W <- rowSums(T.matrix)
  return(which.min(W))
}

# example 1
closest.point(M = rbind(c(1, 1, 1), 
                        c(1, 2, 5)), 
              y = cbind(c(1, 2, 5)))
# [1] 2

# example 2
closest.point(M = rbind(c(1, 1, 1, 1), 
                        c(1, 2, 5, 7)), 
              y = cbind(c(2, 2, 6, 2)))
# [1] 2
 

Комментарии:

1. спасибо, я согласен, что другое решение более точное, но это действительно помогает мне понять, почему мое решение не работало с неопределенными переменными и т. Д.

Ответ №2:

Вы должны стараться избегать использования for цикла для выполнения операций с векторами и матрицами. dist Базовая функция вычисляет расстояния. Затем which.min вы получите индекс минимального расстояния.

 set.seed(0)
M <- matrix(rnorm(100), ncol = 5)
y <- rnorm(5)

closest_point <- function(M, y) {
    dist_mat <- as.matrix(dist(rbind(M, y)))
    all_distances <- dist_mat[1:nrow(M),ncol(dist_mat)]
    which.min(all_distances)
}

closest_point(M, y)
#>    
#> 14
 

Создано 2021-12-10 пакетом reprex (v2.0.1)

Надеюсь, это имеет смысл, дайте мне знать, если у вас есть вопросы.

Комментарии:

1. это намного аккуратнее — большое спасибо.

Ответ №3:

Здесь есть ряд проблем

  1. p определено, но никогда не используется.
  2. Хотя это и не так, T на самом деле не обязательно должно быть матрицей. Было бы достаточно, чтобы это был вектор.
  3. Хотя это и не неправильно, использование T в качестве переменной опасно, потому что T также означает TRUE .
  4. Код определяет T, и они немедленно отбрасывают его в следующем операторе, перезаписывая его. Предыдущий оператор, определяющий T, никогда не используется.
  5. for всегда имеет значение NULL, поэтому присваивать его T бессмысленно.
  6. цикл double for ничего не делает. В нем нет назначений, поэтому циклы не имеют никакого эффекта.
  7. циклы относятся к m, n, X и x, но они нигде не определены.
  8. (X[i,j] — x[j]) ^ 2 повторяется. Это необходимо только один раз.
  9. Запись max(W) в строке сама по себе не имеет никакого эффекта. Это приводит к выполнению печати только в том случае, если она выполняется непосредственно в консоли. Если выполняется в функции, это не имеет никакого эффекта. Если вы хотели ее распечатать, тогда напишите print(max(W)) .
  10. Нам нужна ближайшая точка, а не самая дальняя точка, поэтому max должно быть минимальным.
  11. df используется в последней строке, но нигде не определен.
  12. Вопрос является неполным без тестового запуска.

Я попытался внести минимальные изменения, чтобы это сработало:

 closest.point <- function(M, y) {
  nr <- nrow(M)
  nc <- ncol(M)
  W <- numeric(nr)  # vector having nr zeros
  for(i in 1:nr) {
    for(j in 1:nc) {
      W[i] <- W[i]   (M[i,j] - y[j])^2
    }
   }
  print(W)
  print(min(W))
  M[which.min(W),]
}

set.seed(123)
M <- matrix(rnorm(12), 4); M
##             [,1]       [,2]       [,3]
## [1,] -0.56047565  0.1292877 -0.6868529
## [2,] -0.23017749  1.7150650 -0.4456620
## [3,]  1.55870831  0.4609162  1.2240818
## [4,]  0.07050839 -1.2650612  0.3598138

y <- rnorm(3); y
## [1]  0.4007715  0.1106827 -0.5558411

closest.point(M, y)
## [1] 0.9415062 2.9842785 4.6316069 2.8401691  <--- W
## [1] 0.9415062    <--- min(W)
## [1] -0.5604756  0.1292877 -0.6868529  <-- closest row
 

При этом вычисление ближайшей строки может быть выполнено в этой функции с однострочным телом. Мы транспонируем M, а затем вычитаем из него y, что приведет к вычитанию y из каждого столбца, но столбцы транспонирования являются строками M, поэтому это вычитает y из каждой строки. Затем возьмите суммы столбцов квадратов разностей и найдите, какой из них наименьший. Нижний индекс M использует это.

 closest.point2 <- function(M, y) { 
  M[which.min(colSums((t(M) - y)^2)), ]
}

closest.point2(M, y)
## [1] -0.5604756  0.1292877 -0.6868529  <-- closest row
 

Комментарии:

1. спасибо — список проблем действительно полезен.