【问题标题】:Calculate the length of segments within a transect计算样带内线段的长度
【发布时间】:2019-02-18 11:43:32
【问题描述】:

我有一个带纬度、经度和底物类型的样带数据。下面我提供了一个脚本,该脚本沿着从经度 -24.5 到 -23.2 的直线样带创建具有 3 种基质类型的假设数据。在该样带中有 3 种底物类型(a、b 和 c),但底物类型“a”出现 4 次,底物类型“b”出现两次。我想计算样带中每个“a”、“b”和“c”基板类型段的总长度(米)。作为示例,衬底段“a”在“b”衬底类型的第一次观察的位置处结束,并且衬底段c在第四“a”衬底类型段开始的位置处结束。我想要的长度。我已经研究了 sp 和 Rdistance 包,但我真的被困住了。提前致谢。

假设示例:每个框表示我要计算其长度的每个段

Alon<-c(-23.20, -23.30,-23.40,-24.10,-24.15, -23.95, -23.70, -23.60,-    24.20, -24.25)  
Blon<-c(-23.80, -23.85, -24.00, -24.03, -24.06)
Clon<-c(-23.47, -23.50,-23.55) 
Alat<-c(64,64,64,64,64, 64, 64, 64,64, 64)
Blat<-c(64,64, 64, 64,64)
Clat<-c(64,64, 64)
A<-as.data.frame(cbind(Alon, Alat))
B<-as.data.frame(cbind(Blon, Blat))
C<-as.data.frame(cbind(Clon, Clat))
plot(A$Alon, A$Alat, pch=97)
points(B$Blon, B$Blat, col="red", pch=98)
points(C$Clon, C$Clat, col="blue", pch=99)


A$ID<-seq.int(nrow(A))
A[,3]<-"A"
B$ID<-seq.int(nrow(B))
B[,3]<-"B"
C$ID<-seq.int(nrow(C))
C[,3]<-"C"


colnames(A)<-c("lon", "lat", "ID")
colnames(B)<-c("lon", "lat", "ID")
colnames(C)<-c("lon", "lat", "ID")

A<-as.data.frame(A)
B<-as.data.frame(B)
C<-as.data.frame(C)

pos<- rbind(A,B,C)
pos<-pos[,c("ID","lon","lat")]

【问题讨论】:

    标签: r spatial


    【解决方案1】:

    我怀疑以米为单位的长度取决于您的投影,因此我在这里计算以度为单位的长度,并将转换留给您。首先,我按经度排序(因为你的纬度都是一样的)。

    # Order data frame
    pos <- pos[order(pos$lon),]
      
    

    接下来,我使用rle 提取每个ID 的运行。我加 1 以开始对第一个元素的第一次运行,并使用 pmin 确保最终索引不大于数据框中的行数。

    # Pull out start and end points of segments
    df_seg <- pos[pmin(nrow(pos), c(1, cumsum(rle(pos$ID)$lengths) + 1)),]
    

    最后,我使用diff 来计算每次运行的开始和结束经度之间的差异。

    # Calculate difference in longitude
    data.frame(ID = df_seg$ID[1:(nrow(df_seg)-1)], diff_lon = abs(diff(df_seg$lon)))
    
    # Check data frame
    #   ID diff_lon
    # 1  A     0.19
    # 2  B     0.11
    # 3  A     0.10
    # 4  B     0.15
    # 5  A     0.15
    # 6  C     0.15
    # 7  A     0.20
    

    关于订购站

    我希望我有一个好的解决方案,但我没有。所以,在我做一些可怕的事情之前,我会先道歉......

    library(dplyr)
    library(RANN)
    
    # Temporary data frame
    df_stations <- pos 
    
    # Function for finding order of stations
    station_order <- function(){
      # If only one row, return it (i.e., it's the final station)
      if(nrow(df_stations) == 1)return(df_station)
      # Find the nearest neighbour for the first station
      r <- nn2(data = df_stations %>% select(lon, lat), k = 2)$nn.idx[1,2]
      # Bump the nearest neighbour to first in the data frame
      # This also deletes the first entry
      df_stations[1, ] <<- df_stations[r, ]
      # Drop the nearest neighbour elsewhere in the data frame
      df_stations <<- df_stations %>%  distinct
      # Return the nearest neighbour
      return(df_stations[1, ])
    }
    
    # Initialise data frame
    res <- df_stations[1,]
    
    # Loop over data frame
    for(i in 2:nrow(df_stations))res[i, ] <- station_order()
    

    此代码使用最近邻(即 nn2 来自 RANN)对您的电台进行排序。您会注意到样带是倒置的,但您可以随时使用res[nrow(res):1, ] 更改它。

    #    ID    lon lat
    # 1   A -23.20  64
    # 2   A -23.30  64
    # 3   A -23.40  64
    # 4   C -23.47  64
    # 5   C -23.50  64
    # 6   C -23.55  64
    # 7   A -23.60  64
    # 8   A -23.70  64
    # 9   B -23.80  64
    # 10  B -23.85  64
    # 11  A -23.95  64
    # 12  B -24.00  64
    # 13  B -24.03  64
    # 14  B -24.06  64
    # 15  A -24.10  64
    # 16  A -24.15  64
    # 17  A -24.20  64
    # 18  A -24.25  64
    

    【讨论】:

    • 非常有用,谢谢。我将添加转换。一个快速的问题。显然,在我的真实数据集中,样带的纬度也会发生变化。我想知道当纬度和经度都在变化时我应该如何排序。我应该例如如果样带遵循的纬度比经度更好,则按纬度排序。
    • @StefánÁkiRagnarsson 这是个好问题。我不认为单独按纬度或经度排序在所有情况下都有效,因此我在排序中添加了最近邻解决方案。就像我自己一样,它有效但不漂亮。
    • 再次感谢您的帮助。您的解决方案看起来不错。我使用您获取片段的建议得出第三种解决方案“ df_seg
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多