如何过滤掉 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
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