Расчет расстояния между координатами в разных фреймах - PullRequest
0 голосов
/ 31 января 2020

Предположим, у меня есть следующие два кадра данных

dfA <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfB <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfAB <- map2_df(dfA, dfB, str_c, sep=",") %>%
  rename_all(~ str_c('C', seq_along(.)))

dfC <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfD <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfCD <- map2_df(dfC, dfD, str_c, sep=",") %>%
  rename_all(~ str_c('C', seq_along(.)))

Мне нужно найти расстояние между координатами в первом и втором кадрах, поэтому я получаю третий кадр данных с расстоянием между первым ячейка dfAB и первая ячейка dfCD, а также расстояние между 2-й ячейкой dfAB и 2-й ячейкой dfCD и т. д .; т.е. вызовите столбцы C и строки R, я хотел бы получить расстояние между

dfAB        and     dfCD
C1 C2 C...          C1 C2 C...  
R1 R1               R1 R1   
R2 R2               R2 R2
... ...             ... ...
etc

. Мне нужно найти расстояние между dfABC1R1 и dfCDC1R1, dfABC1R2 и dfCDC1R2, dfABC2R1 и dfCDC2R1 и dfCDC2R1, et c .

Когда я пытаюсь использовать

dist(dfAB,dfCD)

Я получаю ошибку: Ошибка в dist (dfAB, dfCD): неверный метод расстояния

Любая помощь очень ценится

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

Согласитесь с @utubun, использование dist является проблемой в вашем примере.

dist полезно для вычисления расстояния между элементами в матрице. Например:

R> m1 <- matrix(1:8, nrow=4)
R> m1
     [,1] [,2]
[1,]    1    5
[2,]    2    6
[3,]    3    7
[4,]    4    8

R> dist(m1)
         1        2        3
2 1.414214                  
3 2.828427 1.414214         
4 4.242641 2.828427 1.414214

Обратите внимание, что евклидово расстояние между строкой [1,] и строкой [2,] равно 1,4, что аналогично расстоянию между координатами (1,5) и (2, 6) или sqrt(2).

В вашем случае вам не нужны матричные сравнения между всеми вашими точками - вас больше всего интересуют расстояния между парами координат в двух матрицах.

Как уже упоминалось @utubun, вам нужно иметь числовые значения c для ваших координат. Например, вы можете сделать:

mat1 <- matrix(apply(dfAB, 1:2, function(x) as.numeric(unlist(strsplit(x, ',')))), ncol = 2, byrow = T)
mat2 <- matrix(apply(dfCD, 1:2, function(x) as.numeric(unlist(strsplit(x, ',')))), ncol = 2, byrow = T)

И это даст вам две числительные c матрицы с 2 столбцами в каждой, которые можно рассматривать как ваши координаты:

R> mat1[1:5,]
     [,1] [,2]
[1,]    1    1
[2,]    3    2
[3,]    4    4
[4,]    1    5
[5,]    0    4

R> mat2[1:5,]
     [,1] [,2]
[1,]    4    2
[2,]    3    2
[3,]    2    3
[4,]    4    0
[5,]    3    2

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

euclidean_distance <- function(p, q){
  sqrt(sum((p - q)^2))
}

, а затем вызвать функцию построчно через две матрицы пар координат:

matrix(sapply(1:nrow(mat1), function(x) euclidean_distance(mat1[x,], mat2[x,])), ncol = 5, byrow = FALSE)

Что даст вам вашу окончательную матрицу расстояний:

          [,1]     [,2]     [,3]     [,4]     [,5]
 [1,] 3.162278 1.000000 4.472136 1.414214 1.414214
 [2,] 0.000000 0.000000 2.236068 1.000000 2.000000
 [3,] 2.236068 4.472136 5.385165 1.000000 1.000000
 [4,] 5.830952 2.236068 4.242641 3.605551 3.605551
 [5,] 3.605551 3.162278 1.000000 1.414214 2.000000
 [6,] 2.828427 2.000000 2.000000 2.000000 2.236068
 [7,] 1.414214 2.236068 2.236068 2.828427 1.414214
 [8,] 1.000000 4.000000 2.828427 2.000000 2.000000
 [9,] 3.000000 1.000000 1.000000 2.000000 1.000000
[10,] 2.236068 2.828427 4.123106 1.414214 1.000000

Данные

set.seed(5)

dfA <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfB <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfAB <- map2_df(dfA, dfB, str_c, sep=",") %>%
  rename_all(~ str_c('C', seq_along(.)))

dfC <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfD <- data.frame(x = rpois(10,2), y = rpois(10,2), z = rpois(10,2), q = rpois(10,2), t = rpois(10,2))
dfCD <- map2_df(dfC, dfD, str_c, sep=",") %>%
  rename_all(~ str_c('C', seq_along(.)))
1 голос
/ 01 февраля 2020

Примечание о сообщении об ошибке

  • Ваша ошибка 1004 * корыта, поскольку второй аргумент dist() - это строка символов, описывающая метод расчета расстояния (например, "евклидово");
  • Координатные кортежи в ваших фреймах данных dfAB и dfCD являются символьными строками. Таким образом, даже если dist() позволит вам рассчитать расстояние между каждым элементом двух фреймов данных, это приведет к ошибке.

Мой подход не слишком элегантен, но, вероятно, это тот момент, с которого вы можете начать думать о том, как подойти к вашим данным.

Данные

set.seed(60007561)

dat <- split(rpois(60, 2), paste0('df_', rep(letters[1:4], each = 15)))

for(i in names(dat)) {
  assign(
    i, 
    data.frame(split(dat[[i]], rep(letters[1:5], each = 3)))
    )
}

# inspect the data

head(
  do.call(
    cbind,
    lapply(
      list(df_a, df_b, df_c, df_d), 
      cbind, 
      data.frame(' ' = rep(' ', 3), check.names = F)
      )
  )
)

#   a b c d e   a b c d e   a b c d e   a b c d e  
# 1 1 2 1 2 3   0 2 1 2 1   5 0 2 2 0   2 5 2 3 3  
# 2 5 0 2 0 3   2 5 1 2 3   0 0 4 2 2   3 1 1 1 2  
# 3 3 2 1 3 0   4 2 0 2 2   0 3 1 2 0   2 2 5 1 4 

Sulution

Сделайте два столбца со столбцами a...e, где каждый столбец содержит кадры данных со столбцами x, y, соответствующими данным из кадров данных df_a, df_b; и df_c, df_d соответственно. Первая результирующая таблица соответствует от точек , а вторая таблица соответствует точкам :

df_ab <- as_tibble(lapply(map2(df_a, df_b, ~ list(x = .x, y = .y)), as.data.frame))
df_cd <- as_tibble(lapply(map2(df_c, df_d, ~ list(x = .x, y = .y)), as.data.frame))
#df_ab
# # A tibble: 3 x 5
#     a$x    $y   b$x    $y   c$x    $y   d$x    $y   e$x    $y
#   <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
# 1     1     0     2     2     1     1     2     2     3     1
# 2     5     2     0     5     2     1     0     2     3     3
# 3     3     4     2     2     1     0     3     2     0     2
#
#df_cd
# # A tibble: 3 x 5
#     a$x    $y   b$x    $y   c$x    $y   d$x    $y   e$x    $y
#   <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
# 1     5     2     0     5     2     2     2     3     0     3
# 2     0     3     0     1     4     1     2     1     2     2
# 3     0     2     3     2     1     5     2     1     0     4

Рассчитать евклидово расстояние между от по данным к к данным :

distances <- map2_df(
  df_ab,
  df_cd,
  ~ sqrt((.x$x - .y$x)^2 + (.x$y - .y$y)^2)
)

#distances
# # A tibble: 3 x 5
#       a     b     c     d     e
#   <dbl> <dbl> <dbl> <dbl> <dbl>
# 1  4.47  3.61  1.41  1     3.61
# 2  5.10  4     2     2.24  1.41
# 3  3.61  1     5     1.41  2   

Обратите внимание, что в таблице выше представлены расстояния от каждой точки для столбцов a ... e, от первой таблицы до соответствующих точек во второй таблице

Расстояния для столбца a (для проверки приближения или просто для удовольствия):

sgms <- data.frame(
  x    = df_a$a,
  y    = df_b$a,
  xend = df_c$a,
  yend = df_d$a,
  l    = round(distances$a, 1)
  ) %>%
  mutate(lx = (x + xend) / 2, ly = (y + yend) / 2)

ggplot(data = sgms, aes(x = x, y = y, xend = xend, yend = yend)) +
  geom_segment(lty = 3, arrow = arrow(10, ,'closed', ends = 'last')) +
  geom_label(aes(x = lx, y = ly, label = l)) +
  geom_point(aes(x = x, y = y), pch = 21, size = 3.5) +
  geom_text(aes(x = x, y = y, label = sprintf('(%d, %d)', x, y)), vjust = 2) +
  geom_point(aes(x = xend, y = yend), pch = 22, size = 3.5) +
  geom_text(aes(x = xend, y = yend, label = sprintf('[%d, %d]', xend, yend)), vjust = -2) +
  expand_limits(y = c(-.5, 5.5), x = c(-.5, 5.5)) +
  ggtitle('Distances btw df_ab, df_cd; col. a') +
  ggthemes::theme_tufte()

dist

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