r - 在另一列标记的一定半径内,根据 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 等),绘图其他列中的值相互对比,并导出所有图。
解决方案
如果您计划以类似的方式处理单个帧,我通常建议您不要存储到单个帧中。(有关“框架列表”的讨论,请参阅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
推荐阅读
- python - 我正在尝试使用标记创建一个叶图,但我不断收到 TypeError: must be real number, not str
- php - 如何从 Wordpress 帖子中提取图像并将其放入 php 代码中
- git - git忽略特定目录、绝对路径或相对路径
- android - 当文本过多时,ScrollView 会遮盖我的按钮
- sql - 查找名字和姓氏不唯一的客户
- java - 创建一个返回字符串数组的方法
- sql - ORACLE SQL - 时差
- github - 如何更新我的主分支?
- javascript - 阻止来自浏览器控制台的输入详细信息或直接使其不可读
- easeljs - 如何阻止精灵移动?