TL;博士
这张左外连接的图像准确地描绘了我想要的:根据与另一data.table
的lat, lon
列完全匹配的两列lat, lon
删除data.table
行。
问题所在
假设我有以下data.table
"dt.master"
,其中包含超过 100 万行,其中包含某个位置lat, lon
的id
和坐标:
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 行。不知何故,它只删除了第一个"命中"。
使用快速且脏的解决方案,方法是将
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
我们可以使用data.table
中的fsetdiff
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