在Google Map叠加克里金插值数据遇性能问题及等高线需求
解决ggmap叠加克里金插值等高线时内存占用过高的问题
我明白你遇到的困扰:用ggmap()叠加meuse数据集的克里金插值结果时,get_map()运行一切正常,但调用stat_contour()绘制等高线时,内存直接飙升到7G导致无法正常运行;换成stat_summary_2d()虽然能跑,但没法实现你想要的等高线效果。下面给你两个可行的解决方案:
问题根源
stat_contour()搭配geom = "polygon"处理克里金生成的10000个点时,会尝试为每个等高线层级生成大量多边形面,再加上经纬度转换后的点分布细节,直接把内存撑爆了——不规则散点的等高线计算复杂度本身就很高,大量数据叠加后内存压力自然剧增。
方案1:先转规则栅格再画等高线(推荐)
把克里金插值结果转换成规则栅格,能大幅降低等高线计算的复杂度,用ggplot2的geom_contour_filled(或geom_contour)就能轻松生成平滑的等高线,内存占用也会低很多:
# 加载依赖包 suppressMessages(library(sp)) suppressMessages(library(automap)) suppressMessages(library(ggmap)) suppressMessages(library(raster)) # 预处理meuse数据并执行克里金插值 data(meuse) coordinates(meuse) <- ~ x + y proj4string(meuse) <- CRS("+proj=stere +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.999908 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +no_defs +towgs84=565.2369,50.0087,465.658, -0.406857330322398,0.350732676542563,-1.8703473836068, 4.0812") # 生成规则网格并插值 set.seed(42) grid <- spsample(meuse, type = "regular", n = 10000) krg <- autoKrige(formula = copper ~ 1, input_data = meuse, new_data = grid) # 关键步骤:将插值结果转为栅格,再转经纬度投影 krg_raster <- raster(krg$krige_output) krg_raster_longlat <- projectRaster(krg_raster, crs = CRS("+init=epsg:4326")) # 转成ggplot可用的数据框 krg_raster_df <- as.data.frame(krg_raster_longlat, xy = TRUE) names(krg_raster_df) <- c("x", "y", "pred") # 获取地图并叠加等高线 lon <- range(krg_raster_df$x) lat <- range(krg_raster_df$y) meuse_map <- get_map(location = c(lon = mean(lon), lat = mean(lat)), zoom = 13) print(ggmap(meuse_map, extent = "normal", maprange = FALSE) + geom_contour_filled(aes(x = x, y = y, z = pred), alpha = 0.5, color = "gray80", data = krg_raster_df) + scale_fill_viridis_d(name = "Copper (ppm)") + coord_cartesian(xlim = lon, ylim = lat, expand = 0) + theme(aspect.ratio = 1))
方案2:降采样插值点
如果不想折腾栅格转换,可以直接减少克里金插值的点数,降低stat_contour()的计算压力。比如把网格点数从10000降到2500:
# 修改网格生成步骤 set.seed(42) grid <- spsample(meuse, type = "regular", n = 2500) # 后续步骤和你原来的代码一致,换回stat_contour即可 krg <- autoKrige(formula = copper ~ 1, input_data = meuse, new_data = grid) krg_df <- data.frame(krg$krige_output@coords, pred = krg$krige_output@data$var1.pred) names(krg_df) <- c("x", "y", "pred") krg_spdf <- krg_df coordinates(krg_spdf) <- ~ x + y proj4string(krg_spdf) <- proj4string(meuse) krg_spdf <- spTransform(krg_spdf, CRS("+init=epsg:4326")) krg_df <- data.frame(krg_spdf@coords, pred = krg_spdf@data$pred) lon <- range(krg_df$x) lat <- range(krg_df$y) meuse_map <- get_map(location = c(lon = mean(lon), lat = mean(lat)), zoom = 13) print(ggmap(meuse_map, extent = "normal", maprange = F) + stat_contour(aes(x = x, y = y, z = pred, fill = ..level..), alpha = 0.5, color = "gray80", geom = "polygon", data = krg_df) + scale_fill_gradient(low = "yellow", high = "red", name = "Copper") + coord_cartesian(xlim = lon, ylim = lat, expand = 0) + theme(aspect.ratio = 1))
小提示
- 方案1的栅格方法生成的等高线更平滑,内存占用也更可控,是优先推荐的方式;
- 方案2的降采样会损失一点插值精度,但胜在简单快速,适合测试场景。
内容的提问来源于stack exchange,提问作者Manojit
相关产品推荐
相关产品推荐

