Соединение многоугольников в R


29

Мне интересно, как соединить пространственные полигоны, используя код R?

Я работаю с данными переписи, где определенные области меняются с течением времени, и я хочу объединить полигоны и соответствующие данные и просто отчитываться по объединенным областям. Я веду список полигонов, которые переписывают изменения в перепись и которые я планирую объединить. Я хотел бы использовать этот список названий областей в качестве справочного списка для применения к данным переписи за разные годы.

Мне интересно, какую функцию R использовать для объединения выбранных полигонов и соответствующих данных. Я погуглил это, но просто запутался в результатах.


Ответом на большинство геометрических операций, таких как растворение полигонов, наложение, точка-полигон, пересечение, объединение и т. Д., Является пакет rgeos.
Космонавт

1
Бюро переписей США публикует таблицы для этого за 1990-2000 и 2000-2010 годы. Им можно управлять с помощью соединений с базой данных , которые реализуются Rс помощью mergeфункции.
whuber

Ответы:


39

Следующее решение основано на посте Роджера Биванда о R-sig-Geo . Я взял его пример, заменив немецкий шейп-файл некоторыми данными переписи из Орегона, которые вы можете скачать здесь (возьмите все компоненты шейп- файла из «Графства Орегона и данные переписи»).

Начнем с загрузки необходимых пакетов и импорта шейп-файла в R.

# Required packages
libs <- c("rgdal", "maptools", "gridExtra")
lapply(libs, require, character.only = TRUE)

# Import Oregon census data
oregon <- readOGR(dsn = "path/to/data", layer = "orcounty")
oregon.coords <- coordinates(oregon)

Далее вам нужна некоторая группирующая переменная для агрегирования данных. В нашем примере группировка просто основана на координатах одного округа. См. Изображение ниже, черные границы обозначают исходные многоугольники, тогда как красные границы представляют многоугольники, сгруппированные oregon.id.

# Generate IDs for grouping
oregon.id <- cut(oregon.coords[,1], quantile(oregon.coords[,1]), include.lowest=TRUE)

# Merge polygons by ID
oregon.union <- unionSpatialPolygons(oregon, oregon.id)

# Plotting
plot(oregon)
plot(oregon.union, add = TRUE, border = "red", lwd = 2)

Оригинальный и сгруппированный шейп-файл Oregon

Все идет нормально. Однако атрибуты данных, связанные с субрегионами исходного шейп-файла (например, плотность населения, площадь и т. Д.), Теряются при выполнении unionSpatialPolygons. Полагаю, вы хотели бы объединить данные переписи, связанные с шейп-файлом, поэтому вам потребуется промежуточный шаг.

Сначала вы должны преобразовать свои полигоны в фрейм данных, чтобы выполнить агрегацию. Теперь давайте возьмем столбцы атрибутов данных с шести по восемь («AREA», «POP1990», «POP1997») и агрегируем их в соответствии с вышеуказанными идентификаторами, применяя функцию sum.

# Convert SpatialPolygons to data frame
oregon.df <- as(oregon, "data.frame")

# Aggregate and sum desired data attributes by ID list
oregon.df.agg <- aggregate(oregon.df[, 6:8], list(oregon.id), sum)
row.names(oregon.df.agg) <- as.character(oregon.df.agg$Group.1)

Наконец, верните ваш фрейм данных обратно SpatialPolygonsDataFrameв ранее предоставленный унифицированный шейп-файл, oregon.unionи вы получите как обобщенные полигоны, так и данные вашей переписи, полученные из вышеупомянутого этапа агрегирования.

# Reconvert data frame to SpatialPolygons
oregon.shp.agg <- SpatialPolygonsDataFrame(oregon.union, oregon.df.agg)

# Plotting
grid.arrange(spplot(oregon, "AREA", main = "Oregon: original county area"), 
             spplot(oregon.shp.agg, "AREA", main = "Oregon: aggregated county area"), ncol = 1)

Орегонские районы


10

Вот решение с использованием пакета sf:

library(tidycensus)
library(dplyr)
library(sf)
library(ggplot2)

# get data from tindycensus for demonstration (note you need an API key, folow instructions here: https://walkerke.github.io/tidycensus/articles/basic-usage.html)
census <- tidycensus::get_acs(geography = "tract", variables = "B19013_001",
                           state = "TX", county = "Tarrant", geometry = TRUE) %>% 
  arrange(NAME)

# reduce dataset size
census <- census[1:8,]

# create grouping variable
group_1 <- census$GEOID[1:2]
group_2 <- census$GEOID[6:8]

census <- census %>% mutate(group = case_when(GEOID %in% group_1 ~ 'newgroup1',
                                              GEOID %in% group_2 ~ 'newgroup2',
                                              TRUE ~ GEOID))

# summarise by grouping variable (performs a union on grouped polygons and sums 'estimate')
census2 <- group_by(census, group) %>% 
  summarise(estimate = sum(estimate), do_union = TRUE)

# visualise using ggplot2 development version and facet by merged/unmerged datasets
plot_data <- rbind(census %>% select(group, estimate) %>%
                     mutate(facet = "unmerged"), 
                   census2 %>% mutate(facet = "merged"))

gp <- ggplot() + 
      geom_sf(data = plot_data, aes(fill = estimate), color = 'white') + 
      scale_fill_viridis_c() + 
      facet_wrap(~facet, ncol = 1)

введите описание изображения здесь


Я подумал, что просто добавлю небольшое предупреждение на всякий случай: остерегайтесь использования summarise()производных с do_unionаргументом, как я только что сделал что-то подобное summarise_if(shapefile, predic.function, sum, na.rm = TRUE, do_union = TRUE), что в итоге также суммировало ИСТИНА в каждой ячейке (т.е. +1 для всех операций). Нужно исследовать больше, чтобы выяснить, следует ли об этом сообщать (хотя бы для дополнительного предупреждения) ...?
Страгу
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.