океан широта долгота точка расстояние от берега

Я начал «бесплатный» проект с открытым исходным кодом, чтобы создать новый набор данных для рН земных океанов.

Я начал с открытого набора данных от NOAA и создал набор данных из 2,45 миллионов строк с этими столбцами:

colnames(NOAA_NODC_OSD_SUR_pH_7to9)
[1] "Year"  "Month" "Day"   "Hour"  "Lat"   "Long"  "Depth" "pH"   

Документ с методом ЗДЕСЬ.

Набор данных ЗДЕСЬ.

Моя цель сейчас состоит в том, чтобы «квалифицировать» каждый ряд (2,45 м)... для этого мне нужно рассчитать расстояние от каждой точки широты/долготы до ближайшего берега.

Итак, я ищу метод, который будет принимать In: Lat/Long Out: Distance (km from берег)

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

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

Если кто-то захочет помочь, буду признателен. Или, если вы знаете простой (бесплатный) способ сделать это, пожалуйста, дайте мне знать...

Я могу работать в программировании R, скриптах Shell, но не эксперт в этом....


person Simon Filiatrault    schedule 29.12.2014    source источник
comment
Делает ли это это помочь? или это?   -  person jlhoward    schedule 30.12.2014
comment
Хорошо, читая это, кажется, в R есть несколько способов сделать это. Я еще почитаю об этом, но я далек от понимания всего этого. Я надеялся, что кто-нибудь может помочь мне, но если это невозможно, я могу учиться! Спасибо!   -  person Simon Filiatrault    schedule 30.12.2014
comment
Вы можете опубликовать это на gis.stackexchange.com.   -  person jlhoward    schedule 30.12.2014


Ответы (1)


Итак, здесь происходит несколько вещей. Во-первых, в вашем наборе данных, кажется, есть зависимость pH от глубины. Таким образом, в то время как есть ~ 2,5 мм строк, есть только ~ 200 000 строк с глубиной = 0 - все еще много.

Во-вторых, чтобы получить расстояние до ближайшего побережья, вам нужен шейп-файл береговых линий. К счастью, он доступен здесь, на отличном сайте Natural Earth.

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

library(rgdal)   # for readOGR(...); loads package sp as well
library(rgeos)   # for gDistance(...)

setwd(" < directory with all your files > ")
# WGS84 long/lat
wgs.84    <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
# ESRI:54009 world mollweide projection, units = meters
# see http://www.spatialreference.org/ref/esri/54009/
mollweide <- "+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
df        <- read.csv("OSD_All.csv")
sp.points <- SpatialPoints(df[df$Depth==0,c("Long","Lat")], proj4string=CRS(wgs.84))

coast  <- readOGR(dsn=".",layer="ne_10m_coastline",p4s=wgs.84)
coast.moll <- spTransform(coast,CRS(mollweide))
point.moll <- spTransform(sp.points,CRS(mollweide))

set.seed(1)   # for reproducible example
test   <- sample(1:length(sp.points),10)  # random sample of ten points
result <- sapply(test,function(i)gDistance(point.moll[i],coast.moll))
result/1000   # distance in km
#  [1]   0.2185196   5.7132447   0.5302977  28.3381043 243.5410571 169.8712255   0.4182755  57.1516195 266.0498881 360.6789699

plot(coast)
points(sp.points[test],pch=20,col="red")

Итак, это считывает ваш набор данных, извлекает строки, где Depth==0, и преобразует их в объект SpatialPoints. Затем мы читаем базу данных береговых линий, загруженную по ссылке выше, в объект SpatialLines. Затем мы преобразуем оба в проекцию Моллвейде, используя spTransform(...), затем мы используем gDistance(...) в пакете rgeos для расчета минимального расстояния между каждой точкой и ближайшим побережьем.

Опять же, важно помнить, что, несмотря на все десятичные знаки, эти расстояния являются приблизительными.

Одна очень большая проблема — скорость: этот процесс занимает ~ 2 минуты на 1000 дистанций (в моей системе), так что пробежать все 200 000 дистанций займет около 6,7 часов. Теоретически одним из вариантов было бы найти базу данных береговой линии с более низким разрешением.

Приведенный ниже код рассчитает все 201 000 расстояний.

## not run
## estimated run time ~ 7 hours
result <- sapply(1:length(sp.points), function(i)gDistance(sp.points[i],coast))

EDIT: комментарий OP о ядрах заставил меня подумать, что это может быть тот случай, когда улучшение от параллелизма может стоить затраченных усилий. Итак, вот как вы могли бы запустить это (в Windows), используя параллельную обработку.

library(foreach)   # for foreach(...)
library(snow)      # for makeCluster(...)
library(doSNOW)    # for resisterDoSNOW(...)

cl <- makeCluster(4,type="SOCK")  # create a 4-processor cluster
registerDoSNOW(cl)                # register the cluster

get.dist.parallel <- function(n) {
  foreach(i=1:n, .combine=c, .packages="rgeos", .inorder=TRUE, 
          .export=c("point.moll","coast.moll")) %dopar% gDistance(point.moll[i],coast.moll)
}
get.dist.seq <- function(n) sapply(1:n,function(i)gDistance(point.moll[i],coast.moll))

identical(get.dist.seq(10),get.dist.parallel(10))  # same result?
# [1] TRUE
library(microbenchmark)  # run "benchmark"
microbenchmark(get.dist.seq(1000),get.dist.parallel(1000),times=1)
# Unit: seconds
#                     expr       min        lq      mean    median        uq       max neval
#       get.dist.seq(1000) 140.19895 140.19895 140.19895 140.19895 140.19895 140.19895     1
#  get.dist.parallel(1000)  50.71218  50.71218  50.71218  50.71218  50.71218  50.71218     1

Использование 4-х ядер повышает скорость обработки примерно в 3 раза. Таким образом, поскольку 1000 расстояний занимает около минуты, 100 000 должно занимать чуть меньше 2 часов.

Обратите внимание, что использование times=1 на самом деле является злоупотреблением microbenchmark(...), поскольку весь смысл в том, чтобы запустить процесс несколько раз и усреднить результаты, но у меня просто не хватило терпения.

person jlhoward    schedule 30.12.2014
comment
Вау... Я просто смеялся, читая это, потому что половину понял с первого прочтения... Мужчины! Вы волшебник в этом! Я понимаю, что нужно взять только глубину = 0, но мне нужно будет применить это расстояние ко всем точкам данных... Я могу настроить его. Еще одна вещь, которую я могу сделать, это извлечь отдельные значения широты и долготы в отдельный DF и запустить на нем код. Затем используйте его в качестве поиска, чтобы применить к 2,4 mRows... Я использую 4-ядерный быстрый процессор с 8Gig @ 64bit... Надеюсь, это сработает. Я попробую это завтра и дам отзыв. - person Simon Filiatrault; 31.12.2014
comment
Только что подсчитал, у меня 116 тыс. строк различных широт/долгот. Я начну с этого. - person Simon Filiatrault; 31.12.2014
comment
Да, на самом деле распараллеливание очень помогает. Смотрите мои правки (в конце). - person jlhoward; 31.12.2014
comment
Это отличный ответ. Это моя первая заметка за 2015 год. - person jazzurro; 31.12.2014
comment
Ух ты! Вы действительно волшебник! Счастливого 2015 года вам и семье. Я хочу упомянуть одну вещь: мой исходный набор данных, извлеченный из NOAA, вызвал здесь настоящую дискуссию: wattsupwiththat.com/2014/12/30/ph-sampling-density Я надеюсь, что с добавлением «Расстояния от берега» это еще больше поможет обсуждению и анализу. - person Simon Filiatrault; 01.01.2015