r - 将 sf::st_within 的输出转换为向量

7

我正在尝试使用R中的sf包,并使用st_within函数查看sf对象是否在另一个sf对象内部。我的问题在于这个函数的输出是稀疏几何二元谓词-sgbp,我需要一个向量作为输出,以便之后可以使用dplyr包进行过滤。以下是一个简化的示例:

# object 1: I will test if it is inside object 2
df <- data.frame(lon = c(2.5, 3, 3.5), lat = c(2.5, 3, 3.5), var = 1) %>% 
st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>%
  summarise(var = sum(var), do_union = F) %>% st_cast("LINESTRING")

# object 2: I will test if it contains object 1
box <- data.frame(lon = c(2, 4, 4, 2, 2), lat = c(2, 2, 4, 4,2), var = 1) %>%
  st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>% 
  summarise(var = sum(var), do_union = F) %>% st_cast("POLYGON")

# test 1
df$indicator <- st_within(df$geometry, box$geometry) # gives geometric binary predicate on pairs of sf sets which cannot be used 
df <- df %>% filter(indicator == 1)

这会报错:错误:列 indicator 必须是一维原子向量或列表。

我尝试以下方法解决此问题:

# test 2
df$indicator <- st_within(df$geometry, box$geometry, sparse = F) %>% 
  diag() # gives matrix that I convert with diag() into vector
df <- df %>% filter(indicator == FALSE)

这个方法可以移除包含TRUE值的行,但是由于我的真实数据包含很多观测值,所以制作矩阵的过程非常缓慢。有没有一种方法可以将st_within的输出变成字符向量,或者可能有一种方法可以将sgbp转换为与dplyr兼容的字符向量而不制作矩阵?

3个回答

14

以下是从稀疏几何二元谓词中获取逻辑向量的方法:

df$indicator <- st_within(df, box) %>% lengths > 0

或者在不创建新变量的情况下对子集进行操作:

df <- df[st_within(df, box) %>% lengths > 0,]

很遗憾,我无法在你的大型数据集上进行测试,但如果它比矩阵方法更快,请告诉我。


1

is_within 的结果实际上是一个列表列,因此您可以通过“取消列出”来解决这个问题。像这样的东西会起作用:

library(dplyr)
library(sf)

# object 1: I will test if it is inside object 2 - to make this more interesting
# I added a second not-contained line
df <- data.frame(lon = c(2.5, 3, 3.5), lat = c(2.5, 3, 3.5), var = 1) %>% 
  st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>%
  summarise(var = sum(var), do_union = F) %>% st_cast("LINESTRING")

df2 <- data.frame(lon = c(4.5, 5, 6), lat = c(4.5, 5, 6), var = 2) %>% 
  st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>%
  summarise(var = sum(var), do_union = F) %>% st_cast("LINESTRING")
df3 <- rbind(df, df2)

# object 2: I will test if it contains object 1
box <- data.frame(lon = c(2, 4, 4, 2, 2), lat = c(2, 2, 4, 4,2), var = 1) %>%
  st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>% 
  summarise(var = sum(var), do_union = F) %>% st_cast("POLYGON")

plot(df3) 
plot(st_geometry(box), add = TRUE)

# see if the lines are within the box and build a data frame with results
is_within <- st_within(df3$geometry, box$geometry) %>% 
  lapply(FUN = function(x) data.frame(ind = length(x))) %>% 
  bind_rows()

# add the "indicator" to df3
df3 <- dplyr::mutate(df3, indicator = is_within$ind) 
df3
#> Simple feature collection with 2 features and 2 fields
#> geometry type:  LINESTRING
#> dimension:      XY
#> bbox:           xmin: 2.5 ymin: 2.5 xmax: 6 ymax: 6
#> epsg (SRID):    4326
#> proj4string:    +proj=longlat +datum=WGS84 +no_defs
#>   var indicator                       geometry
#> 1   3         1 LINESTRING (2.5 2.5, 3 3, 3...
#> 2   6         0 LINESTRING (4.5 4.5, 5 5, 6 6)

HTH

本文于2018年03月15日由reprex包(v0.2.0)创建。


1

不要直接使用st_within函数,尝试使用空间连接。看看以下示例如何使用st_joins

library(sf)
library(tidyverse)

lines <-
data.frame(id=gl(3,2), x=c(-3,2,6,11,7,10), y=c(-1,6,-5,-9,10,5)) %>%
  st_as_sf(coords=c("x","y"), remove=F) %>% 
  group_by(id) %>% 
  summarise() %>%
  st_cast("LINESTRING")

yta10 <-
    st_point(c(0, 0)) %>%
    st_buffer(dist = 10) %>%
    st_sfc() %>%
    st_sf(yta = "10m")

使用左连接可以保留所有行,但您可以看到哪些行位于多边形内部

lines %>% st_join(yta10, left=TRUE)

内连接(left = FALSE)只保留内部的内容。
lines %>% st_join(yta10, left=FALSE)

后者也可以通过以下方式获得

lines[yta10,]

st_join只是合并线和框,但它不会检查一个几何图形是否在另一个几何图形内,这就是我所问的。我需要从st_within或可能从另一个函数输出逻辑或字符向量。 - adl
@Hans Gardfjell,st_join函数仅检查y中的几何形状是否完全包含在x中,还是检查重叠/相交的几何形状?R中'sf'包的文档相当缺乏。 - Francis Barton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接