我有44,000个美国邮政编码,并且在R中是对应的重心纬度/经度。这是从R中的“ zipcode”包中获得的。我需要计算每个邮政编码之间的距离,并保持这些距离小于5英里。问题是要计算邮政编码之间的所有距离,我必须创建一个大小为44,000x44,0000的矢量,由于空间问题我不能这样做。
我检查了R中的帖子,最接近我的要求的是它用纬度/经度吐出两个数据集之间的最小距离
DB1 <- data.frame(location_id=1:7000,LATITUDE=runif(7000,min = -90,max = 90),LONGITUDE=runif(7000,min = -180,max = 180))
DB2 <- data.frame(location_id=7001:12000,LATITUDE=runif(5000,min = -90,max = 90),LONGITUDE=runif(5000,min = -180,max = 180))
DistFun <- function(ID){
TMP <- DB1[DB1$location_id==ID,]
TMP1 <- distGeo(TMP[,3:2],DB2[,3:2])
TMP2 <- data.frame(DB1ID=ID,DB2ID=DB2[which.min(TMP1),1],DistanceBetween=min(TMP1) )
print(ID)
return(TMP2)
}
DistanceMatrix <- rbind_all(lapply(DB1$location_id, DistFun))
即使我们可以修改上面的代码以包含所有小于等于5英里的距离(例如),执行起来也非常慢。
是否有一种有效的方法来得出彼此重心小于等于5英里的所有邮政编码组合?
一次生成整个距离矩阵将非常耗费RAM,并且循环遍历唯一邮政编码的每种组合-非常耗时。让我们找到一些妥协。
我建议将zipcode
data.frame
(例如)100行分成多块(借助chunk
package的功能bit
),然后计算44336与100点之间的距离,根据目标距离阈值进行过滤,然后继续进行下一个数据块。在我的示例中,我将zipcode
数据转换为data.table
可以提高速度并节省RAM。
library(zipcode)
library(data.table)
library(magrittr)
library(geosphere)
data(zipcode)
setDT(zipcode)
zipcode[, dum := NA] # we'll need it for full outer join
仅供参考-这是RAM中每个数据的大概大小。
merge(zipcode, zipcode[1:100], by = "dum", allow.cartesian = T) %>%
object.size() %>% print(unit = "Mb")
# 358.2 Mb
代码本身。
lapply(bit::chunk(1, nrow(zipcode), 1e2), function(ridx) {
merge(zipcode, zipcode[ridx[1]:ridx[2]], by = "dum", allow.cartesian = T)[
, dist := distGeo(matrix(c(longitude.x, latitude.x), ncol = 2),
matrix(c(longitude.y, latitude.y), ncol = 2))/1609.34 # meters to miles
][dist <= 5 # necessary distance treshold
][, dum := NULL]
}) %>% rbindlist -> zip_nearby_dt
zip_nearby_dt # not the whole! for first 10 chunks only
zip.x city.x state.x latitude.x longitude.x zip.y city.y state.y latitude.y longitude.y dist
1: 00210 Portsmouth NH 43.00590 -71.01320 00210 Portsmouth NH 43.00590 -71.01320 0.000000
2: 00210 Portsmouth NH 43.00590 -71.01320 00211 Portsmouth NH 43.00590 -71.01320 0.000000
3: 00210 Portsmouth NH 43.00590 -71.01320 00212 Portsmouth NH 43.00590 -71.01320 0.000000
4: 00210 Portsmouth NH 43.00590 -71.01320 00213 Portsmouth NH 43.00590 -71.01320 0.000000
5: 00210 Portsmouth NH 43.00590 -71.01320 00214 Portsmouth NH 43.00590 -71.01320 0.000000
---
15252: 02906 Providence RI 41.83635 -71.39427 02771 Seekonk MA 41.84345 -71.32343 3.688747
15253: 02912 Providence RI 41.82674 -71.39770 02771 Seekonk MA 41.84345 -71.32343 4.003095
15254: 02914 East Providence RI 41.81240 -71.36834 02771 Seekonk MA 41.84345 -71.32343 3.156966
15255: 02916 Rumford RI 41.84325 -71.35391 02769 Rehoboth MA 41.83507 -71.26115 4.820599
15256: 02916 Rumford RI 41.84325 -71.35391 02771 Seekonk MA 41.84345 -71.32343 1.573050
在我的机器上,处理10个块花了1.7分钟,因此整个处理过程可能需要70-80分钟,虽然不算很快,但可能令人满意。我们可以将块大小增加到200或300行,具体取决于可用的RAM容量,这将分别缩短2或3倍的处理时间。
该解决方案的缺点是,结果data.table
包含“重复的”行-我的意思是,从点A到点B以及从点B到A都存在距离。这可能需要一些额外的过滤。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句