【问题标题】:Getting the centroids of Lat and Longitude in a data frame在数据框中获取纬度和经度的质心
【发布时间】:2016-12-06 14:06:29
【问题描述】:

我有一个数据框 (df),它有三列,如下所示:(所有数字都是随机的)

ID  Lat    Lon
1   25.32 -63.32
1   25.29 -64.21
1   24.12 -62.43
2   12.42  54.64
2   12.11  53.43
.   ....   ....

基本上我希望每个 ID 的质心如下所示:

ID  Lat    Lon    Cent_lat   Cent_lon
1   25.32 -63.32  25.31      -63.25
1   25.29 -64.21  25.31      -63.25
1   24.12 -62.43  25.31      -63.25
2   12.42  54.64  12.20       53.60
2   12.11  53.43  12.20       53.60

我厌倦了以下内容:

library(geosphere)
library(rgeos)
library(dplyr)

df1 <- by(df,df$ID,centroid(df$Lat, df$Long))

但这给了我这个错误:

(函数(类、fdef、mtable)中的错误: 无法为签名“numeric”找到函数“centroid”的继承方法

我什至累了

df1 <- by(df,df$ID,centroid(as.numeric(df$Lat), as.numeric(df$Long)))

但这给了我这个错误:

(函数(类,fdef,mtable)中的错误: 无法为签名“函数”找到函数“质心”的继承方法

【问题讨论】:

  • 三点的质心不就是它们分量的平均值吗(mean(long), mean(lat))?
  • 在大多数情况下,我们有超过三个点,如果地球是平的,平均方法会起作用:-)
  • 要使用centroid,您需要一个 poligon 作为矩阵对象,或者一个为每个点提供适当行名的数据框

标签: r dataframe


【解决方案1】:

来自?centroid,它说它只需要一个 2 列矩阵作为它的参数。您拥有的 ID 信息使矩阵变为三列。

df &lt;- rbind(c(25.32,-63.32),c(25.29,-64.32),c(24.12,-62.43),c(12.42,54.64),c(12.11,53.43) centroid(df)

  lon       lat
[1,] 24.27109 -60.37098

【讨论】:

    【解决方案2】:
    library(geosphere)
    library(ggplot2)
    library(dplyr)
    
    states <- map_data("state")
    
    head(states)
    ##        long      lat group order  region subregion
    ## 1 -87.46201 30.38968     1     1 alabama      <NA>
    ## 2 -87.48493 30.37249     1     2 alabama      <NA>
    ## 3 -87.52503 30.37249     1     3 alabama      <NA>
    ## 4 -87.53076 30.33239     1     4 alabama      <NA>
    ## 5 -87.57087 30.32665     1     5 alabama      <NA>
    ## 6 -87.58806 30.32665     1     6 alabama      <NA>
    
    cntrd <- function(x) {
      data.frame(centroid(as.matrix(x[,c("long", "lat")])))
    }
    
    by(states, states$group, cntrd) %>% head()
    ## $`1`
    ##         lon      lat
    ## 1 -86.82976 32.82735
    ## 
    ## $`2`
    ##         lon      lat
    ## 1 -111.6698 34.34309
    ## 
    ## $`3`
    ##         lon      lat
    ## 1 -92.43826 34.92167
    ## 
    ## $`4`
    ##         lon      lat
    ## 1 -119.6713 37.40289
    ## 
    ## $`5`
    ##         lon      lat
    ## 1 -105.5526 39.02653
    ## 
    ## $`6`
    ##         lon      lat
    ## 1 -72.72553 41.62706
    
    group_by(states, group) %>%
      do(cntrd(.))
    ## Source: local data frame [63 x 3]
    ## Groups: group [63]
    ## 
    ##    group        lon      lat
    ##    <dbl>      <dbl>    <dbl>
    ## 1      1  -86.82976 32.82735
    ## 2      2 -111.66978 34.34309
    ## 3      3  -92.43826 34.92167
    ## 4      4 -119.67130 37.40289
    ## 5      5 -105.55264 39.02653
    ## 6      6  -72.72553 41.62706
    ## 7      7  -75.51543 39.00879
    ## 8      8  -77.03411 38.91083
    ## 9      9  -82.51260 28.69498
    ## 10    10  -83.46361 32.67562
    ## # ... with 53 more rows
    

    【讨论】:

      【解决方案3】:

      要使用centroid,您需要按顺序包含经度和纬度的多边形。看这个例子:

      df<-rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20),
      c(-100,-50), c(-160,-60), c(-180, -10), c(-160,10), c(-60,0),c(-100,-50))
      df<-data.frame(ID=rep(c(1,2),times=c(5,6)),Lon=df[,1],Lat=df[,2])
      df1 <- by(df[,c("Lon", "Lat")],df$ID,centroid)
      df1
      df[,c("Cent_lon","Cent_lat")]<-NA
      for(i in names(df1))df[df$ID==i,c("Cent_lat","Cent_lon")]<-df1[[i]]
      df
      
         ID  Lon Lat   Cent_lon   Cent_lat
      1   1 -180 -20  -23.89340 -133.33333
      2   1 -160   5 -133.33333  -23.89340
      3   1  -60   0  -23.89340 -133.33333
      4   1 -160 -60 -133.33333  -23.89340
      5   1 -180 -20  -23.89340 -133.33333
      6   2 -100 -50 -127.66065 -127.66065
      7   2 -160 -60  -26.10686  -26.10686
      8   2 -180 -10 -127.66065 -127.66065
      9   2 -160  10  -26.10686  -26.10686
      10  2  -60   0 -127.66065 -127.66065
      11  2 -100 -50  -26.10686  -26.10686
      

      你可以使用plotArrows查看多边形

      pol<-split(df[,2:3],df$ID)
      #plotArrows(pol[[1]])
      plotArrows(as.matrix(pol[[1]]))
      points(df1[[1]],col=4)
      

      【讨论】:

      • 谢谢你的回答,你用情节来展示答案,值得我投赞成票
      【解决方案4】:

      geosphere 包的函数centroid 采用矩阵 作为数据参数:"Arguments : xa 2-column matrix (longitude/latitude)" p>

      https://cran.r-project.org/web/packages/geosphere/geosphere.pdf

      另外,longitude 是第一列,latitude 是第二列,而不是相反:)

      所以你的代码可能是这样的:

      library(geosphere)
      
      df <- data.frame(ID = c(1,1,1,2,2,2,2)
                      , Lon = c(-63.32, -64.43, -62.43, 54.64, 53.43, 54.64, 53.43)
                      , Lat = c(25.32, 25.29, 24.12, 12.42, 12.11, 11.11, 10.55))
      mx <- as.matrix(df)
      
      (mx1 <- by(mx[,2:3], mx[,1], centroid))
      

      输出:

      > INDICES: 1
      > lon      lat
      > [1,] -63.39333 24.91126
      > ----------------------------------------------------------------- 
      > INDICES: 2
      > lon lat
      > [1,] Inf  90
      

      【讨论】:

        【解决方案5】:

        这是一种 data.table 方法。正如@czeinerb 提到的,Lon 是 centroid 函数的第一个参数,而 Lat 是第二个。我们在下面重新定义了 centroid 函数,以便在 data.table 聚合中接收一个包含 2 列 (Lat|Lon) 的矩阵,这是地理圈的 centroid 函数所需的输入。

        # Import packages
        library(geosphere)
        library(data.table) # Using a data.table approach
        
        # Sample data
        df = data.frame("ID" = c(1, 1, 1, 2, 2, 2), "Lat" = c(25.32, 25.29, 24.12, 12.42, 12.11, 12.22), "Lon" = c(-63.32, -64.21, -62.43, 54.64, 53.43, 53.23))
        
        df
        
          ID   Lat    Lon
        1  1 25.32 -63.32
        2  1 25.29 -64.21
        3  1 24.12 -62.43
        4  2 12.42  54.64
        5  2 12.11  53.43
        6  2 12.22  53.23
        
        # Convert to data.table
        setDT(df)
        
        # Re-define centroid function - Lon is first argument and Lat is second
        # Geosphere takes a matrix with two columns: Lon|Lat, so we use cbind to coerce the data to this form
        findCentroid <- function(Lon, Lat, ...){
          centroid(cbind(Lon, Lat), ...)
        }
        
        # Find centroid Lon and Lat by ID, as required
        df[, c("Cent_lon", "Cent_lat") := as.list(findCentroid(Lon, Lat)), by = ID]
        df
        
           ID   Lat    Lon  Cent_lon Cent_lat
        1:  1 25.32 -63.32 -63.32000 24.91126
        2:  1 25.29 -64.21 -63.32000 24.91126
        3:  1 24.12 -62.43 -63.32000 24.91126
        4:  2 12.42  54.64  53.76667 12.25003
        5:  2 12.11  53.43  53.76667 12.25003
        6:  2 12.22  53.23  53.76667 12.25003
        

        【讨论】:

        • 非常感谢,我喜欢 cmets 和结构
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-04
        • 2019-03-25
        • 2016-09-29
        • 1970-01-01
        相关资源
        最近更新 更多