【问题标题】:Calculating distance between coordinates in different dataframes计算不同数据框中坐标之间的距离
【发布时间】:2020-02-01 09:21:35
【问题描述】:

假设我有以下两个数据框

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 的第一个单元格之间的距离,以及第二个数据帧之间的距离dfAB 的单元格和 dfCD 的第 2 个单元格等;即调用列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等之间的距离。

当我尝试使用时

dist(dfAB,dfCD)

我收到错误:dist(dfAB,dfCD) 中的错误:距离方法无效

非常感谢任何帮助

【问题讨论】:

    标签: r coordinates distance


    【解决方案1】:

    关于错误信息的说明

    • 您的dist(dfAB, dfCD) 槽错误,因为dist() 的第二个参数是描述距离计算方法的字符串(例如“欧几里得”);
    • dfABdfCD 数据帧中的坐标元组是字符串。因此,即使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 
    

    解决方案

    a...e 列创建两个小标题,其中每列包含数据帧,其中x, y 列对应于数据帧df_adf_b 中的数据;和df_cdf_d。第一个结果表对应于 from points,第二个 tibble 对应于 to points

    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()
    

    【讨论】:

    • 感谢您提供此解决方案。如果我的初始数据帧的行不均匀并且我想将 df 1 的单元格 C1R1 中的值应用于 df 2 中 C1 的每个 R,您是否还有建议?即:df_c
    【解决方案2】:

    同意@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 所提到的,您的坐标需要有数值。例如,您可以这样做:

    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)
    

    这将为您提供两个数字矩阵,每个矩阵有 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(.)))
    

    【讨论】:

      猜你喜欢
      • 2014-04-06
      • 2021-09-08
      • 2017-06-26
      • 2018-07-27
      • 2020-06-02
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多