You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言st_intersection处理多边形与点相交运行过慢如何解决

问题背景

我有两个sf对象执行相交操作时耗时极长:

  • D_sf:633条POLYGON几何观测
  • Temp_points_sf:11266条POINT几何观测
    目标是计算每个多边形内部所有对应点的温度平均值,原代码如下:
# Code for one layer of the grib (layer=days temperatures)
N_days = 365

#Create veCtors with the dates to label later data
Date <- seq(as.Date("2018-01-01"), as.Date("2018-12-31"), by="days")

# Import Temp 2018 ore 13 era5 skin temperature
file <- "Data/Raw/Temperature/adaptor.mars.internal-1602054929.639875-5679-35-5d951960-05b1-4e42-8f0f-b42b0b69ad7f.grib"
GRIB<- stack(file) 

# Convert D in a spatial polygon dataframe
D <- as_Spatial(D)

# Begin the dataset (just index now, then attaChes every variable at eaCh iteration). 
Average_temperatures_URAU <- data.frame(D@data[, 1])
colnames(Average_temperatures_URAU)[1] <- "URAU_CODE"

# take the ith layer of the file (first day of 2018 to last day of 2018)
Grib_layer <- GRIB@layers[[1]]

# original data are Centered on the paCifiC. Use the rotate() funCtion to Center on europe, in this way it is not Cut
Grib_layer <- rotate(Grib_layer)

# Change the crs of D to use it as a mask in the Cycle
D2 <- spTransform(x = D, CRSobj = crs(Grib_layer))

# Extract D from world map
masked <- mask(x = Grib_layer, mask = D2)
cropped <- crop(x = masked, y = extent(D2))

# Transform the raster file to be a point one
layer_cropped  <- rasterToPoints(cropped, spatial="TRUE")

# Go baCk to normal Coordinates
layer_cropped_points <- spTransform(x = layer_cropped, CRSobj = crs(D))

# Change name
names(layer_cropped_points) <- "Temperature"

# Intersection of D and temps, sf is faster so we convert them
D_sf <- st_as_sf(D)
Temp_points_sf <- st_as_sf(layer_cropped_points)

#as often the case the geometry is invalid due to small irreg. make it valid
D_sf <- st_make_valid(D_sf)
Intersection_D_temp_sf <- st_intersection(D_sf, Temp_points_sf)

Intersection_D_temp_sf <- Intersection_D_temp_sf[, c("URAU_CODE", "Temperature" )]

# Sorting Now we Can average out the multiple points in the areas (apply mean by group)
yyy <- ddply(Intersection_D_temp_sf, .(URAU_CODE), summarize, Avg_temp=mean(Temperature))

# Change the name of the variable to "Avg_temp_Month_Year"
yyy_sorted <-  yyy[order(as.numeriC(yyy$URAU_CODE)),] 


# Convert to Celsius
yyy_sorted$Avg_temp <- yyy_sorted$Avg_temp - 273.15


# Add the dates from the veCtor dates to the variable name
colnames(yyy_sorted)[2] <- as.character(Date[i])

# AttaCh the iterations' month to the whole dataset
Average_temperatures_URAU <- merge(Average_temperatures_URAU, yyy_sorted, by = "URAU_CODE")

print(i)
gc()

逐行调试后发现st_intersection函数是性能瓶颈,请问该如何优化解决该问题?


优化方案

核心问题

你完全不需要用st_intersection做面和点的匹配,st_intersection会计算几何相交后的新几何,对于点面归属场景属于过度计算,耗时自然很高。

第一层优化:替换点面匹配逻辑

直接用空间连接匹配点所属的多边形,性能提升至少10倍以上:

# 原st_intersection代码替换为以下内容
# 先给点数据匹配所属的多边形URAU_CODE
point_with_poly <- st_join(Temp_points_sf, D_sf["URAU_CODE"], join = st_within)
# 过滤掉不在任何多边形内的点
point_with_poly <- point_with_poly[!is.na(point_with_poly$URAU_CODE), ]
# 分组求平均
yyy <- aggregate(Temperature ~ URAU_CODE, data = point_with_poly, FUN = mean)

如果追求更快的速度,可以用st_intersects先获取匹配索引,直接计算均值,跳过属性连接的步骤:

# 获取每个多边形包含的点的索引
point_index <- st_intersects(D_sf, Temp_points_sf)
# 直接计算每个多边形的平均温度
yyy <- data.frame(
  URAU_CODE = D_sf$URAU_CODE,
  Avg_temp = sapply(point_index, function(idx) mean(Temp_points_sf$Temperature[idx], na.rm = TRUE))
)

第二层优化:跳过转点步骤,直接用栅格提取

你当前的逻辑是把栅格转成点再做匹配,完全可以直接用栅格的extract函数计算每个多边形的均值,省去转点和空间匹配两步,性能提升更高:

# 不需要执行rasterToPoints、转sf、空间匹配的相关代码
# 直接在裁剪后的栅格上提取每个多边形的均值
temp_mean <- extract(cropped, D2, fun = mean, na.rm = TRUE)
# 直接和结果表拼接即可
yyy_sorted <- data.frame(
  URAU_CODE = D$URAU_CODE,
  Avg_temp = temp_mean - 273.15
)

另外可以提前把D的sf对象、坐标转换这些操作放到循环外,不要每次迭代都重复执行,进一步减少冗余计算。

内容的提问来源于stack exchange,提问作者nflore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 09:24:05