R для ГИС – расчет проксимальных плотностей

Недавно я начал использовать R для приложений ГИС, и мне нужна помощь в расчете проксимальных плотностей — концепция, с которой я почти не знаком. Для иллюстрации предположим, что мне предоставлены данные о местоположении школ и игровых площадок, для которых я хотел бы рассчитать проксимальную плотность в радиусах 0,25 мили, 0,50 мили, 0,75 мили и 1 милю. Как этого можно добиться с помощью программы R? Это то, что я пробовал до сих пор.

# load required packages
library(sp)
library(sf)

# create standard rectangular non-spatial data frames
schools <- data.frame(Location = c("Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL"), Place = c("Albertville Middle School", "Albertville High School", "Albertville Intermediate School", "Albertville Elementary School", "Albertville Kindergarten and PreK", "Albertville Primary School"), Lat = c(34.25996, 34.260509, 34.27279, 34.25182, 34.29161, 34.25321), Long = c(-86.2074, -86.205116, -86.220818, -86.22271, -86.19384, -86.22192))
playgrounds <- data.frame(Location = c("Albertville, AL", "Albertville, AL", "Albertville, AL"), Place = c("Graham Park", "Sand Mountain Park", "Pecan Grove Playground"), Lat = c(34.26358, 34.275471, 34.27294), Long = c(-86.20289, -86.229111, -86.2264))

# define the coordinates
schools_coords <- cbind(schools$Long, schools$Lat)
playgrounds_coords <- cbind(playgrounds$Long, playgrounds$Lat)

# create the SpatialPointsDataFrame
schools_sp <- SpatialPointsDataFrame(schools_coords, data = schools, proj4string = CRS("+proj= longlat"))
playgrounds_sp <- SpatialPointsDataFrame(playgrounds_coords, data = playgrounds, proj4string = CRS("+proj= longlat"))

# convert to sf
schools_sf <- st_as_sf(schools_sp)
playgrounds_sf <- st_as_sf(playgrounds_sp)

Для меня это тоже только отправная точка. При необходимости я могу собирать дополнительные общедоступные данные.

Ваша ссылка требует аутентификации, вместо этого добавьте прямые ссылки. Также, пожалуйста, включите код, который у вас есть на данный момент. Это даст другим отправную точку для ответов. Например, являются ли ваши кадры данных данными или пространственные объекты (созданные с использованием пакетов sf, sp и др.)? Гораздо легче ответить на ответы, которые представляют собой минимальные, воспроизводимые примеры . По этой ссылке есть действительно полезные рекомендации о том, как создать MRE и, в частности, о том, как делиться примерами данных. Спасибо

L Tyrone 10.08.2024 04:08

@LTyrone, спасибо за ваш комментарий. Я добавил свои данные в код R. Я также включил некоторый код, который, по моему мнению, должен стать отправной точкой.

StatisticsFanBoy 10.08.2024 04:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Рабочий процесс:

  • определите подходящую CRS зоны UTM (или используйте тот, который, как вы знаете, подходит). Предполагается, что ваши координаты WGS84/EPSG:4326.
  • создать научно-фантастические объекты для школ и игровых площадок и спроектировать CRS, определенный на предыдущем шаге
  • создавать буферы на указанных расстояниях в метрах (радиусах), например. 400 == ~0,25 мили и сумма количества игровых площадок на школьный буфер.
  • объединить все буферные файлы SF и рассчитать проксимальную плотность

Необходимо спроецировать ваши данные в систему координат проекции (PCS), чтобы гарантировать, что расчеты буферной площади остаются относительно постоянными для ваших буферов на всей территории вашего исследования. Если ваши данные находятся на национальном уровне или охватывают несколько зон UTM, вам может потребоваться выполнить отдельные расчеты для каждой зоны UTM. Вы также можете предварительно вычислить значения площади и присвоить их файлам buff*, но давайте пока оставим все просто.

library(sf)
library(dplyr)
library(tidyr)

# Your sample data
schools <- data.frame(
  Location = c("Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL", "Albertville, AL"),
  Place = c("Albertville Middle School", "Albertville High School", "Albertville Intermediate School", "Albertville Elementary School", "Albertville Kindergarten and PreK", "Albertville Primary School"),
  Lat = c(34.25996, 34.260509, 34.27279, 34.25182, 34.29161, 34.25321),
  Long = c(-86.2074, -86.205116, -86.220818, -86.22271, -86.19384, -86.22192)
  )

playgrounds <- data.frame(
  Location = c("Albertville, AL", "Albertville, AL", "Albertville, AL"),
  Place = c("Graham Park", "Sand Mountain Park", "Pecan Grove Playground"),
  Lat = c(34.26358, 34.275471, 34.27294),
  Long = c(-86.20289, -86.229111, -86.2264)
  )

# Get UTM zone 
floor((schools$Long + 180) / 6) + 1
# [1] 16 16 16 16 16 16
floor((playgrounds$Long + 180) / 6) + 1
# [1] 16 16 16

# Create sf objects and project to correct UTM zone (or whatever CRS is appropriate)
# EPSG codes can be found @ https://epsg.io/
sf_schools <- schools %>%
  st_as_sf(coords = c("Long", "Lat"), crs = 4326) %>%
  st_transform(32616)

sf_playgrounds <- playgrounds %>%
  st_as_sf(coords = c("Long", "Lat"), crs = 4326) %>%
  st_transform(32616)

# School buffers
buff25 <- st_buffer(sf_schools, 400) %>%
  st_join(., sf_playgrounds, join = st_contains) %>%
  group_by(Place.x) %>%
  summarise(pg_count = sum(!is.na(Place.y)), .groups = 'drop') %>%
  mutate(buff = "buff025")

buff50 <- st_buffer(sf_schools, 800) %>%
  st_join(., sf_playgrounds, join = st_contains) %>%
  group_by(Place.x) %>%
  summarise(pg_count = sum(!is.na(Place.y)), .groups = 'drop') %>%
  mutate(buff = "buff050")

buff75 <- st_buffer(sf_schools, 1200) %>%
  st_join(., sf_playgrounds, join = st_contains) %>%
  group_by(Place.x) %>%
  summarise(pg_count = sum(!is.na(Place.y)), .groups = 'drop') %>%
  mutate(buff = "buff075")

buff10 <- st_buffer(sf_schools, 1600) %>%
  st_join(., sf_playgrounds, join = st_contains) %>%
  group_by(Place.x) %>%
  summarise(pg_count = sum(!is.na(Place.y)), .groups = 'drop') %>%
  mutate(buff = "buff100")

# Combine buffers, calculate area as square miles, calculate proximal density,
# convert to dataframe, pivot to wide and reorder buffers from smallest to largest
buff_all <- do.call(rbind, mget(ls(pattern = "^buff\\d{2}$"))) %>%
  mutate(area_sq_mile = as.numeric(st_area(.)) * 3.861e-7,
         pd = pg_count / area_sq_mile) %>%
  rename(Place = Place.x) %>%
  data.frame() %>%
  pivot_wider(id_cols = Place,
              names_from = buff,
              values_from = pd) %>%
  relocate(buff100, .after = last_col())

buff_all
# # A tibble: 6 × 5
#   Place                             buff025 buff050 buff075 buff100
#   <chr>                               <dbl>   <dbl>   <dbl>   <dbl>
# 1 Albertville Elementary School        0       0      0       0    
# 2 Albertville High School              5.16    1.29   0.573   0.322
# 3 Albertville Intermediate School      0       1.29   1.15    0.644
# 4 Albertville Kindergarten and PreK    0       0      0       0    
# 5 Albertville Middle School            0       1.29   0.573   0.322
# 6 Albertville Primary School           0       0      0       0

Значения в столбцах «buff*» представляют собой проксимальную плотность игровых площадок вокруг каждой школы на квадратную милю.

Спасибо за подробный ответ. Это мне очень помогает. Не могли бы вы поделиться советами о том, как определить подходящий CRS?

StatisticsFanBoy 12.08.2024 01:44

@StatisticsFanBoy - пожалуйста. Использование зон UTM в большинстве случаев является надежным подходом. Итак, запускаем unique(floor((schools$Long + 180) / 6) + 1), а затем выполняем поиск в Интернете «EPSG UTM зона x», где x — результат предыдущего кода. Первый результат обычно приходит с epsg.io . Кроме того, эта ссылка и шпаргалка в формате PDF по этой ссылке являются хорошей отправной точкой.

L Tyrone 12.08.2024 03:12

@StatisticsFanBoy — если вам нужен рабочий процесс для управления данными в нескольких зонах UTM, вы можете сделать df$UTM <- floor((schools$Long + 180) / 6) + 1, а затем запустить анализ для каждой группы в df$UTM. Трудно описать полный рабочий процесс в комментарии, поэтому, если вам нужна дополнительная помощь, найдите существующий ответ SO относительно данных в нескольких зонах UTM. Если ни один из них не поможет в вашем случае использования, задайте новый вопрос. Я или другой житель ТАК с радостью помогу.

L Tyrone 12.08.2024 03:20

творческое использование mget() +1

D.J 12.08.2024 13:37

Другие вопросы по теме