首页 > 解决方案 > 将数据框粘合在一起

问题描述

    V1            V2
1   0   58.3354616 15.1455364
2   0   58.3360446 15.1457141
3   0   58.3364476 15.1458118
4   0   58.3368139 15.1459143
5   0   58.3372234 15.1459975
6   0   58.3380975 15.1460381
7   0   58.339002 15.1459897
8   0   58.339663 15.1457799
9   0   58.3402414 15.145495
10  0   58.3411902 15.1447415
11  0   58.3422411 15.1436215
12  0   58.3433313 15.1419505
13  0   58.3464673 15.136081
14  0   58.3508979 15.1277296
113 9   58.3541105 11.9237896
114 9   58.3534139 11.9305822
10  9693    58.3534139 11.9305822
11  9693    58.3533332 11.9313722
14  9693    58.3532568 11.9321196
12  9693    58.353248 11.9322061

在上面的数据集中,我有一组 V2 坐标(纬度和经度),它们属于某些字符串,显示在 V1 中。我想将那些在结尾和开头分别具有相同坐标的字符串粘合在一起。例如: 9 的结尾坐标与 9693 的开头坐标相同,可以说 9698 是字符串 9 的延续。如何将它们粘合在一起?新字符串的名称无关紧要。

上面的数据集是我拥有的数据集的一个样本。我正在寻找一种方法将我的数据集中包含> 10 ^ 6个观察值的所有此类字符串粘合在一起。

标签: r

解决方案


这是一个显示您的状况的示例数据集:

dat <- data.frame(
  v1 = c(rep(1L, 3) , rep(2L, 3) , rep(3L, 3)) ,
  v2 = c(c(1,2,3)   , c(3,4,5)   , c(6,7,8)  ) ,
  v3 = c(c(11,12,13), c(13,14,15), c(16,17,18))
)

浮点数相等性的任何测试都存在问题,因为它的基本假设是您可以保证相等(提示:您不能,安全地;请参阅R FAQ 7.31,您可以搜索任何 IEEE-754)。最好的缓解措施是在容忍范围内测试不平等。您需要问自己的问题是“离零差有多接近才足够接近?” ,只有您可以根据您的数据和分析需求来回答这个问题。为了这个论点,我将使用1e-9; 如果您的数据是纬度/经度,那么这相当于该数据所指示的世界部分的大约 0.15 米(如果那真的是瑞典......如果在其他地方,它可能小于 0.15m)。

无论哪种方式,这是dplyr一种组合连续“字符串”的方法,我们希望 1 和 2 加入,3 保持不同:

library(dplyr)
tol <- 1e-9

dat %>%
  mutate(
    lastv1 = dplyr::lag(v1),
    same = c(FALSE, diff(v2) < tol & diff(v3) < tol)
  ) %>%
  group_by(v1) %>%
  mutate(lastv1 = if_else(any(same), lastv1[1], v1[1])) %>%
  ungroup() %>%
  mutate(v1 = lastv1) %>%
  # filter(!same) %>%
  select(-same, -lastv1)
# # A tibble: 9 x 3
#      v1    v2    v3
#   <int> <dbl> <dbl>
# 1     1     1    11
# 2     1     2    12
# 3     1     3    13
# 4     1     3    13
# 5     1     4    14
# 6     1     5    15
# 7     3     6    16
# 8     3     7    17
# 9     3     8    18

我在那里留下了一个注释filter:如果你需要减少重复的点,那么取消注释它就会有一个连续的字符串。

解决此问题的另一种方法是计算每组点之间的距离,并根据低于阈值的距离确定您的“相同性”。例如,geosphere::distHaversine或者更准确地说geosphere::distVincentyEllipsoid会给你每对点之间的距离。


代替我意识到您只是在比较字符串:(1)我撤回了浮点讨论,因为您在回避它;(2)它稍微改变了一些东西,因为我们没有使用diff(或公差)。

dat2 <- read.table(header = TRUE, stringsAsFactors = FALSE, text = "
V1            V2
0       58.3354616_15.1455364
0       58.3360446_15.1457141
0       58.3464673_15.136081
0       58.3508979_15.1277296
9       58.3541105_11.9237896
9       58.3534139_11.9305822
9693    58.3534139_11.9305822
9693    58.3533332_11.9313722
9693    58.3532568_11.9321196
9693    58.353248_11.9322061")
dat2$V2 <- gsub("_", " ", dat2$V2)
dat2 %>%
  mutate(
    same = dplyr::lag(V2, default = FALSE) == V2,
    lastV1 = dplyr::lag(V1)
  ) %>%
  group_by(V1) %>%
  mutate(newV1 = if (any(same)) lastV1[1] else V1[1]) %>%
  ungroup() %>%
  mutate(V1 = newV1) %>%
  # filter(!same) %>%
  select(-lastV1, -newV1, -same)
# # A tibble: 10 x 2
#       V1 V2                   
#    <int> <chr>                
#  1     0 58.3354616 15.1455364
#  2     0 58.3360446 15.1457141
#  3     0 58.3464673 15.136081 
#  4     0 58.3508979 15.1277296
#  5     9 58.3541105 11.9237896
#  6     9 58.3534139 11.9305822
#  7     9 58.3534139 11.9305822
#  8     9 58.3533332 11.9313722
#  9     9 58.3532568 11.9321196
# 10     9 58.353248 11.9322061 

推荐阅读