R:根据其他数据框的值添加索引列

R: Add index column based on values from other dataframe

我正在尝试给坐标值一个标签。

我有一个带坐标的数据框,看起来类似于

   lat               lng
    1                 10
    3                 11
    2                 12

我还有一个格子的上下左右坐标数据

 id     left    right   bottom      top
 a      0.5      1.5      9          11      
 b      1.5      2.5      9          11  
 c      2.5      3.5     10          11  

id 列是每个矩形网格的 id。

我想根据网格的经纬度范围将id合并到第一个dataframe。

所以预期输出的第一行应该是这样的

   lat               lng       id
    1                 10        a
    

如果不一一指定范围,我将如何实现。我在考虑某种子集函数,但我不确定如何编写它。

非常感谢您的帮助。

仅供参考,“纬度”通常是 North/South,对我来说通常意味着“顶部”和“底部”会更有意义。该代码与您的框架匹配,但似乎有点不同。

这是基于范围的联接或“非等值”联接。这在 dplyr 中不受原生支持,但它可以在 R 中与至少三个其他包一起完成:

模糊连接

fuzzyjoin::fuzzy_left_join(
  df1, df2,
  by = c("lat" = "left", "lat" = "right", "lng" = "bottom", "lng" = "top"),
  match_fun = list(`>=`, `<=`, `>=`, `<=`)
)[, c("lat", "lng", "id")]
#   lat lng   id
# 1   1  10    a
# 2   3  11    c
# 3   2  12 <NA>

(还有 fuzzyjoin::fuzzy_inner_join,如果您希望将底行放在此处。)

fuzzyjoin 中的“动词”函数有意(我相信)命名为与 dplyr 连接函数一致,因此这可以在 dplyr 管道中内联完成:

library(dplyr)
df1 %>%
  fuzzyjoin::fuzzy_left_join(
    ., df2,
    by = c("lat" = "left", "lat" = "right", "lng" = "bottom", "lng" = "top"),
    match_fun = list(`>=`, `<=`, `>=`, `<=`)
  ) %>%
  select(lat, lng, id)

data.table

library(data.table)
DT1 <- as.data.table(df1)
DT2 <- as.data.table(df2)
DT2[DT1, on = .(left <= lat, right >= lat, bottom <= lng, top >= lng)][, .(lat=left, lng=top, id)]
#      lat   lng     id
#    <int> <int> <char>
# 1:     1    10      a
# 2:     3    11      c
# 3:     2    12   <NA>

我应该注意,列名 post-merge 不一定是人们所期望的:例如,您不会看到 latlng,因为输出列名取自合并的“右侧”,即 DT2DT2[DT1,...] 的合并语法类似于 left_join(DT1, DT2, ...),因此名称与人们可能期望的相反。没有用于内部或完全合并的 data.table::[ 语法,也没有用于从另一个参数中获取名称的语法。 (在我看来,左合并应该使用“左”框架中的名称,但可能有充分的理由这样做。)

sqldf

SQL 原生支持它,因此如果您在某处使用 DBMS,则可以在那里完成查询和连接。缺少它,sqldf 包允许 SQL 访问本地 R 对象(使用 SQLite 引擎)。

sqldf::sqldf(
  "select df1.lat, df1.lng, df2.id
   from df1
     left join df2 on df1.lat between df2.left and df2.right
                  and df1.lng between df2.bottom and df2.top"
)
#   lat lng   id
# 1   1  10    a
# 2   3  11    c
# 3   2  12 <NA>

数据

df1 <- structure(list(lat = c(1L, 3L, 2L), lng = 10:12), class = "data.frame", row.names = c(NA, -3L))
df2 <- structure(list(id = c("a", "b", "c"), left = c(0.5, 1.5, 2.5), right = c(1.5, 2.5, 3.5), bottom = c(9L, 9L, 10L), top = c(11L, 11L, 11L)), class = "data.frame", row.names = c(NA, -3L))