根据另一列中特定标记半径内纬度和经度列中的值省略行,并创建一个新的数据框

问题描述

我有一个如下所示的excel工作表设置,并已作为df加载:

GPS_Lat     GPS_Lon     Location
50.70528    -120.44984  0
50.70528    -120.44984  0
50.70527    -120.44984  0
50.70527    -120.44984  0
50.70526    -120.44984  1
50.70526    -120.44984  1
50.70525    -120.44984  1
50.70525    -120.44984  0
50.70524    -120.44984  0
50.70524    -120.44984  0
50.70523    -120.44984  0
50.70523    -120.44984  0
50.70522    -120.44984  0
50.70522    -120.44984  0
50.70521    -120.44984  1
50.70521    -120.44984  1
50.7052     -120.44985  1
50.7052     -120.44985  1
50.70519    -120.44985  0
50.70519    -120.44986  0
50.70518    -120.44986  0
50.70518    -120.44986  0
50.70517    -120.44987  0
50.70517    -120.44987  0

我希望将值保留在向下定位列时遇到的第一个“ 1”以内1 m之内,并将这些值放入新的数据帧(名为df-n)中。如果还有其他具有1个值的部分,我想将其拆分为单独的数据帧(名称为:df-n + 1),同时也仅将这些点保持在第一个1m之内。我希望每个新数据帧都按顺序编号。我完全被这个困扰。

自动识别下面的点,并创建新的数据框,并在这些点的1 m以内(或任何其他定义的距离)的行中具有原始数据框名称和顺序后缀的行。因此,原始的“ df”第二个“ df-1”和“ df-2”

我最终将使用10 km的半径,并且我的数据集最多可包含2万行。

编辑:为输出提供清晰度。使用半径截止值为2 m的假设距离。

   Row  GPS_Lat    GPS_Lon     Location hypothetical_dist_1 hypothetical_dist_2 
    1   50.70528    -120.44984  0   4   14
    2   50.70528    -120.44984  0   3   13
    3   50.70527    -120.44984  0   2   12
    4   50.70527    -120.44984  0   1   11
    5   50.70526    -120.44984  1   0   10
    6   50.70526    -120.44984  1   1   9
    7   50.70525    -120.44984  1   2   8
    8   50.70525    -120.44984  0   3   7
    9   50.70524    -120.44984  0   4   6
    10  50.70524    -120.44984  0   5   5
    11  50.70523    -120.44984  0   6   4
    12  50.70523    -120.44984  0   7   3
    13  50.70522    -120.44984  0   8   2
    14  50.70522    -120.44984  0   9   1
    15  50.70521    -120.44984  1   10  0
    16  50.70521    -120.44984  1   11  1
    17  50.7052     -120.44985  1   12  2
    18  50.7052     -120.44985  1   13  3
    19  50.70519    -120.44985  0   14  4
    20  50.70519    -120.44986  0   15  5
    21  50.70518    -120.44986  0   16  6
    22  50.70518    -120.44986  0   17  7
    23  50.70517    -120.44987  0   18  8
    24  50.70517    -120.44987  0   19  9

输出:

df-1
Row GPS_Lat     GPS_Lon    Location hypothetical_dist_1 
3   50.70527    -120.44984  0       2
4   50.70527    -120.44984  0       1
5   50.70526    -120.44984  1       0
6   50.70526    -120.44984  1       1
7   50.70525    -120.44984  1       2

df-2
Row GPS_Lat     GPS_Lon    Location hypothetical_dist_2
13  50.70522    -120.44984  0       2
14  50.70522    -120.44984  0       1
15  50.70521    -120.44984  1       0
16  50.70521    -120.44984  1       1
17  50.7052     -120.44985  1       2

基本上,工作流程如下:将多个.csv文件批量加载到列表中,根据文件名命名列表项,使用所选的半径将每个列表项分开(分为filename-1,filename-2等)。 ),将其他列中的值相互绘制,然后导出所有图。

解决方法

在前面,如果计划以类似方式处理单个帧,通常建议将反对存储到单个帧中。 (有关“框架列表”的讨论,请参见https://stackoverflow.com/a/24376207/3358272。)

为演示使用/丢弃的行,我将在此处添加$row

此外,您还提到了与第一个“ 1”的距离,但对于前4行没有前置的“ 1”。由于我的其余处理都假定第一行是有意义的行,因此我将复制第一个“ 1”(在本例中为第5行)复制为第一行,以便随后的分组距离测量按预期方式进行。 / p>

在这里我将使用dplyr进行分组。

library(dplyr)
if (dat$Location[1] != 1) {
  prepended1 <- TRUE # in case we want to discard this copied row later
  # bring the first "1" to the top
  dat <- bind_rows(dat[which(dat$Location == 1)[1],drop = FALSE],dat)
  dat$row[1] <- 0L
} else prepended1 <- FALSE

dat2 <- dat %>%
  mutate(grp = cumsum(c(TRUE,diff(Location) > 0))) %>%
  group_by(grp) %>%
  mutate(dist = geosphere::distVincentyEllipsoid(cbind(GPS_Lon,GPS_Lat),cbind(cbind(GPS_Lon[1],GPS_Lat[1])))) %>%
  ungroup()
dat2
# # A tibble: 25 x 6
#    GPS_Lat GPS_Lon Location   row   grp  dist
#      <dbl>   <dbl>    <int> <int> <int> <dbl>
#  1    50.7   -120.        1     0     1  0   
#  2    50.7   -120.        0     1     1  2.22
#  3    50.7   -120.        0     2     1  2.22
#  4    50.7   -120.        0     3     1  1.11
#  5    50.7   -120.        0     4     1  1.11
#  6    50.7   -120.        1     5     2  0   
#  7    50.7   -120.        1     6     2  0   
#  8    50.7   -120.        1     7     2  1.11
#  9    50.7   -120.        0     8     2  1.11
# 10    50.7   -120.        0     9     2  2.22
# # ... with 15 more rows

这提供了距“组中的第一个1”的距离(请注意grp变量)。从这里开始,按dist过滤并按grp分割就很容易了。

根据后续流程的不同,最好使用dplyr::group_by保持这种单帧格式,尽管改编看不见的代码是另一回事。

您的所有数据(第一行本身除外)都在1m以内,因此为了演示,我将使用“ 2m”。

dat2 %>%
  filter(dist <= 2)
# # A tibble: 11 x 6
#    GPS_Lat GPS_Lon Location   row   grp  dist
#      <dbl>   <dbl>    <int> <int> <int> <dbl>
#  1    50.7   -120.        1     0     1  0   
#  2    50.7   -120.        0     3     1  1.11
#  3    50.7   -120.        0     4     1  1.11
#  4    50.7   -120.        1     5     2  0   
#  5    50.7   -120.        1     6     2  0   
#  6    50.7   -120.        1     7     2  1.11
#  7    50.7   -120.        0     8     2  1.11
#  8    50.7   -120.        1    15     3  0   
#  9    50.7   -120.        1    16     3  0   
# 10    50.7   -120.        1    17     3  1.32
# 11    50.7   -120.        1    18     3  1.32

同样,我将其保留为帧的list,而不是分解成单个变量。

lst_of_frames <- dat2 %>%
  filter(dist <= 2) %>%
  split(.,.$grp)
lst_of_frames
# $`1`
# # A tibble: 3 x 6
#   GPS_Lat GPS_Lon Location   row   grp  dist
#     <dbl>   <dbl>    <int> <int> <int> <dbl>
# 1    50.7   -120.        1     0     1  0   
# 2    50.7   -120.        0     3     1  1.11
# 3    50.7   -120.        0     4     1  1.11
# $`2`
# # A tibble: 4 x 6
#   GPS_Lat GPS_Lon Location   row   grp  dist
#     <dbl>   <dbl>    <int> <int> <int> <dbl>
# 1    50.7   -120.        1     5     2  0   
# 2    50.7   -120.        1     6     2  0   
# 3    50.7   -120.        1     7     2  1.11
# 4    50.7   -120.        0     8     2  1.11
# $`3`
# # A tibble: 4 x 6
#   GPS_Lat GPS_Lon Location   row   grp  dist
#     <dbl>   <dbl>    <int> <int> <int> <dbl>
# 1    50.7   -120.        1    15     3  0   
# 2    50.7   -120.        1    16     3  0   
# 3    50.7   -120.        1    17     3  1.32
# 4    50.7   -120.        1    18     3  1.32

如果您需要对其进行细分,可以轻松手动进行分配(例如lst_of_frames[[2]])。


让我们尝试不同的逻辑:

比较 每个 点和 每个第一点-1 。在此数据中,有两个 first-1 点(第5行和第15行),因此我们将所有24行与这两个点进行比较。

compare_points <- filter(dat,Location == 1 & lag(Location) == 0)
compare_points
#    GPS_Lat   GPS_Lon Location row
# 1 50.70526 -120.4498        1   5
# 2 50.70521 -120.4498        1  15

一个比较:

lapply(seq_len(nrow(compare_points)),function(ind) {
  dat %>%
    mutate(dist = geosphere::distVincentyEllipsoid(compare_points[ind,2:1],cbind(GPS_Lon,GPS_Lat))) %>%
    filter(dist <= 2)
})
# [[1]]
#    GPS_Lat   GPS_Lon Location row     dist
# 1 50.70527 -120.4498        0   3 1.112426
# 2 50.70527 -120.4498        0   4 1.112426
# 3 50.70526 -120.4498        1   5 0.000000
# 4 50.70526 -120.4498        1   6 0.000000
# 5 50.70525 -120.4498        1   7 1.112426
# 6 50.70525 -120.4498        0   8 1.112426
# [[2]]
#    GPS_Lat   GPS_Lon Location row     dist
# 1 50.70522 -120.4498        0  13 1.112426
# 2 50.70522 -120.4498        0  14 1.112426
# 3 50.70521 -120.4498        1  15 0.000000
# 4 50.70521 -120.4498        1  16 0.000000
# 5 50.70520 -120.4498        1  17 1.317768
# 6 50.70520 -120.4498        1  18 1.317768
,

您可以使用基数R的dist(...)函数获得所有点之间的距离。纬度分钟中的100m大约为0.009,因此您可以查看distance_matrix对象以确定哪些点相距

请注意,这使用的是欧氏距离,对于纬度/经度的短距离来说是可以的,但是如果将其用于几英里以上的长距离,则会遇到问题。

我为所有想尝试解决方案的人提供了reprex-随时将其添加到您的问题中。

latlong <- c(50.70528,50.70528,50.70527,50.70526,50.70525,50.70524,50.70523,50.70522,50.70521,50.7052,50.70519,50.70518,50.70517,-120.44984,-120.44985,-120.44986,-120.44987,1,0)
latlong <- matrix(latlong,nrow = 24)
    
distance_matrix <- as.matrix(dist(latlong[,c(1,2)],method = "euclidean"))

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...