如何过滤掉 data.table 中的坐标(纬度、经度)?

How can I filter out coordinates (lat, lon) in a data.table?

TL;DR

左外连接的

This image 恰好描述了我想要的:根据两列 lat, lon 删除 data.table 的行, 正好 [=62] =] 匹配另一个 data.table.

lat, lon

问题

假设我有以下 data.table "dt.master",超过 100 万行包含 id 和某个位置的坐标 lat, lon:

id    lat      lon
1     43.23    5.43
2     43.56    4.12
3     52.14   -9.85
4     43.56    4.12
5     43.83    9.43
...   ...      ...

我想做的是删除与某对坐标匹配的行。你可以认为那对坐标被放入以下黑名单(同样是一个名为 "dt.blacklist"data.table):

lat      lon
43.56    4.12
11.14   -5.85

在这种情况下,在应用黑名单时,答案必须是:

id    lat      lon
1     43.23    5.43
3     52.14   -9.85
5     43.83    9.43
...   ...      ...  

虽然看起来很简单,但我做不对。

到目前为止我做了什么

  • 使用merge,像这样:

    dt.result <- merge(dt.master, dt.blacklist[, c("lat", "lon")], by.x=c("lat", "lon"), by.y=c("lat", "lon"))
    

    但这会产生匹配的行,因此是内部联接。我考虑过使用 subset:

    基于此结果删除行
    subset(dt.master, lat != dt.result$lat & lon != dt.result$lon)
    

    但问题是它部分工作,因为上面示例中只有 1 行被删除,而不是我想要的 2 行。它以某种方式只删除了第一个 "hit".

  • 通过将 lat, lon 连接到两个数据表中名为 "C" 的新列,然后将其删除,从而使用快速而肮脏的解决方案:

    dt.master[C != dt.blacklist$C]
    

    然而,同样的问题出现在两行中只有 1 行被删除的情况下。

我想你正在寻找这个:

dt.master[!dt.blacklist, on = .(lat,lon)]

输出:

   id   lat   lon
1:  1 43.23  5.43
2:  3 52.14 -9.85
3:  5 43.83  9.43

感谢绿色智者的警告,加入浮点数可能会产生意想不到的副作用。通过转换为整数,您可以防止这种情况发生。结果,连接看起来有点复杂:

dt.master[, (2:3) := lapply(.SD,function(x) as.integer(x*100)), .SDcols = 2:3
          ][!dt.blacklist[, (1:2) := lapply(.SD,function(x) as.integer(x*100))], on = .(lat,lon)
            ][, (2:3) := lapply(.SD, `/`, 100), .SDcols = 2:3][]

输出相同:

   id   lat   lon
1:  1 43.23  5.43
2:  3 52.14 -9.85
3:  5 43.83  9.43

我们可以使用 fsetdiff 来自 data.table

fsetdiff(df1[,-1], df2)

或者可以使用 dplyr

中的 anti_join
library(dplyr)
anti_join(df1, df2)
#  id   lat   lon
#1  1 43.23  5.43
#2  3 52.14 -9.85
#3  5 43.83  9.43