首页 > 解决方案 > 在另一列标记的一定半径内,根据 Lat 和 Lon 列中的值省略行并创建一个新的数据框

问题描述

我有一个如下所示的 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),同时也只将点保持在前 1 的 1 m 范围内。我希望每个新数据框都按顺序编号。我完全被这个难住了。

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

我最终将使用 10 公里的半径,我的数据集可以多达 20k 行。

编辑:为输出提供清晰度。使用截断半径为 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 文件批量加载到一个列表中,根据文件名命名列表项,使用选择的半径分隔每个列表项(文件名 1、文件名 2 等),绘图其他列中的值相互对比,并导出所有图。

标签: r

解决方案


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

为了演示使用/丢弃哪些行,我将在$row此处添加。我的任何代码都不需要(或使用)它,仅用于演示。

此外,您提到与第一个“1”保持距离,但前 4 行没有前面的“1”。由于我的其余处理假设第一行是有意义的,我将复制第一个“1”(在本例中从第 5 行)作为第一行,以便后续分组距离测量按预期工作。

我将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,尽管适应 code-unseen 是另一种冒险。

您的所有数据(除了第一行本身)都不在 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进行比较。在此数据中,有两个第一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

推荐阅读