R - SpatialPoints(GPS坐标)和SpatialLinesDataFrame之间的空间连接

时间:2017-12-06 13:31:27

标签: r join spatial lines points

我正在开展一个将数据科学与GIS相结合的大学项目。我们需要找到一个能够从大量GPS坐标数据集中获取附加信息的开源解决方案。显然,我不能使用任何具有每日请求限制的API。

数据

您可以在这里找到教授为我们提供的数据集样本:

longitude <- c(10.86361, 10.96062, 10.93032, 10.93103, 10.93212)        
latitude <- c(44.53355, 44.63234, 44.63470, 44.63634, 44.64559)
longlat <- data.frame(longitude, latitude)
ID <- seq.int(1, 10)

第一个任务:已经完成了!

第一步是使用SpatialPoints使用SpatialPolygonsDataFrame over()加入rgeos SpatialPolygonsDataFramegetData('GADM', country='ITA', level=3)是通过rgeos的{​​{1}}获得的 对于第一个完成的任务,目标是将每个GPS坐标与其所属的CityRegion相关联。 我能够获得的结果的一个例子是:

require(sp)
require(rgeos)
my_spdf <- SpatialPointsDataFrame(coords = longlat, data = ID, proj4string = CRS(" +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 "))
italy_administrative_boundaries_level3 <- getData('GADM', country='ITA', level=3)
result <- over(my_spdf, italy_administrative_boundaries_level3)[, c("NAME_0", "NAME_1", "NAME_2", "NAME_3")]
result$ID <- ID
print(result)

第二个任务:我的问题

现在这些东西变得棘手,因为我需要关联其他更深层次的信息,例如road_nameroad_type
此信息包含在OpenStreetMap上创建的shapefile中,可从以下位置获得: download.geofabrik.de/europe/italy.html 。 我在R中加载了shapefile,获得了SpatialLinesDataFrame

require(rgdal)
shapefile_roads <- readOGR(dsn = "./road", layer = "roads")

然后,我天真地尝试应用与加入SpatialPointsSpatialPolygonsDataFrame相同的技术:

result <- over(my_spdf, shapefile_roads)

显然,结果只是NA。我想到的一个可能原因是my_df的坐标不在Lines shapefile_roads的确切位置,因此,我需要某种半径参数。但是,我不太确定。

您能否建议我在SpatialPoints和从SpatialLinesDataFrame OpenStreetMap获取的road_shapefile属性之间执行此空间连接的正确方法?

如果事情不是很清楚,请不要犹豫。

2 个答案:

答案 0 :(得分:3)

您的示例数据

library(raster)
longitude <- c(10.86361, 10.96062, 10.93032, 10.93103, 10.93212)        
latitude <- c(44.53355, 44.63234, 44.63470, 44.63634, 44.64559)
longlat <- data.frame(longitude, latitude)
ID <- data.frame(ID=1:5)
ita_gadm3 <- getData('GADM', country='ITA', level=3)[, c("NAME_0", "NAME_1", "NAME_2", "NAME_3")]
 #use `sp::over` or `raster::extract`
 result <- extract(ita_gadm3, longlat)

一些道路:

road <- spLines(cbind(longitude+.1, latitude), cbind(longitude-.1, rev(latitude)), cbind(longitude-.1, latitude+1), crs=crs(ita_gadm3))

现在找到最近的路段。您可以使用geosphere::dist2Line,因为您使用的是角度(lon / lat)坐标。

library(geosphere)
geosphere::dist2Line(longlat, road)
#     distance      lon      lat ID
#[1,] 2498.825 10.83212 44.53355  2
#[2,] 5527.646 11.03032 44.63470  1
#[3,] 5524.227 10.86062 44.63634  2
#[4,] 5577.372 10.86062 44.63634  2
#[5,] 5756.113 10.86062 44.63634  2

注意引用回道路的变量ID。问题是dist2line目前很慢,你有一个大的数据集。

另一种方法是将空间数据转换为适合意大利的平面坐标系并使用gDistance。

library(rgeos)
library(rgeos)
sp <- SpatialPoints(longlat, proj4string=crs(ita_gadm3))
spita <- spTransform(sp, "+proj=tmerc +lat_0=0 +lon_0=15 +k=0.9996 +x_0=2520000 +y_0=0 +ellps=intl +units=m")
rdita <- spTransform(road, "+proj=tmerc +lat_0=0 +lon_0=15 +k=0.9996 +x_0=2520000 +y_0=0 +ellps=intl +units=m")

gd <- gDistance(rdita, spita, byid=TRUE)
a <- apply(gd, 1, which.min)
a
#1 2 3 4 5 
#2 1 2 2 2 

即,点2最接近道路1.其他点最接近道路2。 您可能需要在批量的点或平铺中执行此操作,以避免获得太大的距离矩阵。

Sébastien建议的缓冲解决方案原则上可以工作,但由于没有良好的缓冲区大小,因此变得非常复杂。一方面,点可以在任何缓冲区之外,另一方面,它们可以与几个缓冲区重叠。如果使用缓冲区,sp::over如果有多个匹配则返回任意匹配,而raster::extract将全部返回。两者都不漂亮,我会避免这种方法。插图如下:

b <- buffer(road, width=.15, dissolve=F)
plot(b)
lines(road, col='red', lwd=2)
points(longlat, pch=20, col='blue')

extract(b, longlat)
#   point.ID poly.ID
#1         1       1
#2         1       2
#3         2       2
#4         2       1
#5         3       2
#6         3       1
#7         4       2
#8         4       1
#9         5       1
#10        5       2

over(sp, b)
#1 2 3 4 5 
#2 2 2 2 2 

答案 1 :(得分:1)

您需要使用您的点加入多边形,而不是线。为此,您可以使用rgeos::gBuffer()在线周围创建缓冲区。请注意,因为缓冲区将位于Lines的坐标系中。在您的情况下可能是度(wgs84)(验证它)。根据您的情况选择正确的距离(width)。

LinesBuffer <- rgeos::gBuffer(shapefile_roads, width = 0.01)

然后,您将能够使用over与“LinesBuffer”连接点(如果它们位于相同的坐标系中)。

result <- over(my_spdf, LinesBuffer)