Робота з даними PostGIS в R?


27

Я працюю з R майже весь час, і зараз я використовую його для пошуку просторових даних.

У мене база даних PostGIS із (очевидно) даними ГІС.

Якщо я хочу зробити статистичний просторовий аналіз та графічні карти - це кращий спосіб:

  • експортуйте таблиці у формі файлів або;
  • працювати безпосередньо в базі даних?

Відповіді:


34

Якщо у вас є можливість драйвера PostGIS в пакеті rgdal, то це лише питання створення рядка з'єднання та його використання. Тут я підключаюсь до моєї локальної бази даних gisза допомогою облікових даних за замовчуванням, тому мій DSN досить простий. Можливо, вам доведеться додати хост, ім’я користувача або пароль. Інформацію див. У документах gdal.

> require(rgdal)
> dsn="PG:dbname='gis'"

Які таблиці знаходяться в цій базі даних?

> ogrListLayers(dsn)
 [1] "ccsm_polygons"         "nongp"                 "WrldTZA"              
 [4] "nongpritalin"          "ritalinmerge"          "metforminmergev"      

Отримати один:

> polys = readOGR(dsn="PG:dbname='gis'","ccsm_polygons")
OGR data source with driver: PostgreSQL 
Source: "PG:dbname='gis'", layer: "ccsm_polygons"
with 32768 features and 4 fields
Feature type: wkbMultiPolygon with 2 dimensions

Що я маю?

> summary(polys)
Object of class SpatialPolygonsDataFrame
Coordinates:
        min      max
x -179.2969 180.7031
y  -90.0000  90.0000
Is projected: NA 
proj4string : [NA]
Data attributes:
      area         perimeter       ccsm_polys      ccsm_pol_1   
 Min.   :1.000   Min.   :5.000   Min.   :    2   Min.   :    1  
 1st Qu.:1.000   1st Qu.:5.000   1st Qu.: 8194   1st Qu.: 8193  
 Median :1.000   Median :5.000   Median :16386   Median :16384  
 Mean   :1.016   Mean   :5.016   Mean   :16386   Mean   :16384  
 3rd Qu.:1.000   3rd Qu.:5.000   3rd Qu.:24577   3rd Qu.:24576  
 Max.   :2.000   Max.   :6.000   Max.   :32769   Max.   :32768  

В іншому випадку ви можете використовувати функціональну базу даних R і безпосередньо запитувати таблиці.

> require(RPostgreSQL)
Loading required package: RPostgreSQL
Loading required package: DBI
> m <- dbDriver("PostgreSQL")
> con <- dbConnect(m, dbname="gis")
> q="SELECT ST_AsText(the_geom) AS geom from ccsm_polygons LIMIT 10;"
> rs = dbSendQuery(con,q)
> df = fetch(rs,n=-1)

Це повертає геометрію функції в df$geom, яку вам потрібно буде перетворити на spоб'єкти класу (SpatialPolygons, SpatialPoints, SpatialLines), щоб робити з чим завгодно. Функція readWKT в rgeos може допомогти у цьому.

Те, на що слід остерігатися, - це зазвичай такі речі, як стовпці бази даних, які неможливо відобразити на типи даних R Ви можете включити SQL до запиту, щоб зробити перетворення, фільтрування чи обмеження. З цього варто почати.


Чудова відповідь, але як я вмикаю можливість (драйвер Postgis) rgadl? Я в Ubuntu 13.04 ...
нанонауноване

Ти маєш це? Функція ogrDrivers () повинна вам десь сказати. Якщо ні, то це зовсім інше питання (напевно, найкраще спочатку
гуглити,

В Ubuntu драйвер встановлений за замовчуванням. Це не так у MacOS X. Дякую!
nanounanue

У вашому коді вище, чи можливо в readOGRметоді використовувати sql замість повної таблиці?
nanounanue

В даний час я думаю, що ні. Близько 2,5 років тому про r-sig-geo про це говорилося, але нічого, здається, ще не було зроблено. Дуже просто додати whereпункт і передати його OGR через, setAttributeFilterале все це потрібно зробити в коді C і C ++ ...
Spacedman

8

Якщо у вас є дані в Postgis, не експортуйте їх у shapefile. З моєї точки зору, це свого роду крок назад.

Ви можете запитувати вашу базу даних postgis з R за допомогою SQL-висловлювань, імпортуючи їх у вигляді фреймів даних і, оскільки ви знайомі з R, зробіть звідти всю необхідну геостатистику. Я вірю, що ви також можете експортувати свої геостатистичні результати до постгігів.

Використовуючи SQL з функціями Postgis, ви також можете робити всі види просторового аналізу, такі як операції з накладанням, відстані тощо.

Для побудови карти я б використав QGIS , програмне забезпечення GIS OpenSource, яке може читати постгігісти безпосередньо (наскільки я знаю, що це було початковою метою проекту), а майбутня версія 2.0 поставляється з безліччю функцій для створення чудових карт .


Гаразд чудова порада, але оскільки я хочу автоматизувати все в R (включаючи сюжети), що йде до QGis, порушує потік, чи не так?
nanounanue

У такому випадку, якщо вам це зручно, просто використовуйте R для побудови карт. Незважаючи на це, підготувавши макети проектів qgis на основі даних postgis (оновлених), вони також будуть оновлені. Я здогадуюсь, що врешті-решт буде особистим вибором використовувати R чи QGIS.
Олександр Нето

Дякую за швидку відповідь, але як я можу зробити сюжет за допомогою R із таблиці в Postgis?
nanounanue

Я не дуже досвідчений з R, і я не знаю, як би ви побудували векторні дані, використовуючи його (як я вже сказав, що я використовую QGIS для цього), як ви будуєте шаблони в R? Для підключення до PostgresSQL від RI раніше використовували RPostgreSQL . Я думаю rgdal ]. Удачі!
Олександр Нето

5

Нещодавно представлений sf-пакет (наступник sp) забезпечує функції st_read()та st_read_db()функції. Після цього підручника і з мого досвіду це швидше, ніж уже згадані способи. Оскільки sf, ймовірно, замінить sp одного дня, це також добре зателефонувати зараз;)

require(sf)
dsn = "PG:dbname='dbname' host='host' port='port' user='user' password='pw'"
st_read(dsn, "schema.table")

Ви також можете отримати доступ до БД за допомогою RPostgreSQL:

require(sf)
require(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, dbname = dbname, user = user, host = host, port = port, password = pw)

st_read_db(con, table = c("schema", "table"))
# or:
st_read_db(con, query = "SELECT * FROM schema.table")

dbDisconnect(con)
dbUnloadDriver(drv)

За допомогою st_write()вас можна завантажувати дані.


1
Це найпростіше рішення, є віньєтка cran.r-project.org/web/packages/sf/vignettes/sf2.html, що пояснює, як використовувати sf
Седрік

2

Ви можете використовувати всі інструменти одночасно на основі кожного кроку для свого рішення.

  • Якщо ви хочете зробити геостатичний аналіз, використовуйте пакети R. R більш надійні та дозволяють отримати більш аналітичний результат. Ви можете імпортувати дані на основі SQL-запитів.
  • Якщо ви хочете агрегувати свої дані на логічній основі, ви можете використовувати PostGIS. Ви можете відповісти на складні запити, на зразок яких багато балів знаходяться в моїх встановлених межах? Але в масштабному масштабі.
  • Для картографування можна використовувати або R, або QGIS. QGIS більш прямий вперед, з R ви можете боротися за досягнення бажаного результату.

Ми можемо надати вам більш конкретну відповідь, якщо ви дасте нам більше деталей щодо вашої проблеми


Чи можете ви навести приклад останньої точки, я маю на увазі, як я можу зробити, якщо хочу побудувати карту з R із таблиці в Postgis?
nanounanue

@nanounanue sure: бібліотека ("rgdal") mydata = readOGR (dsn = "PG: dbname = <mydb>", layer = "schema.table") plot (mydata, axes = TRUE) title ("Мій сюжет").
ніки

також погляньте на цю сторінку: wiki.intamap.org/index.php/PostGIS
nickves

2

Я б також перейшов на комбінацію rgdal і RPostgreSQL. Отже, той самий код, що і @Guillaume, за винятком пробного вибору, який обробляє більше рядків, псевдослучайного імені таблиці та використання незакритої таблиці для кращої продуктивності. (Зауважте собі: ми не можемо використовувати таблицю TEMP, оскільки це не видно з readOGR)

dbGetSp <- function(dbInfo,query) {
 if(!require('rgdal')|!require(RPostgreSQL))stop('missing rgdal or RPostgreSQL')
  d <- dbInfo
  tmpTbl <- sprintf('tmp_table_%s',round(runif(1)*1e5))
  dsn <- sprintf("PG:dbname='%s' host='%s' port='%s' user='%s' password='%s'",
    d$dbname,d$host,d$port,d$user,d$password
    )
  drv <- dbDriver("PostgreSQL")
  con <- dbConnect(drv, dbname=d$dbname, host=d$host, port=d$port,user=d$user, password=d$password)
  tryCatch({
    sql <- sprintf("CREATE UNLOGGED TABLE %s AS %s",tmpTbl,query)
    res <- dbSendQuery(con,sql)
    nr <- dbGetInfo(res)$rowsAffected
    if(nr<1){
      warning('There is no feature returned.');
      return()
    }
    sql <- sprintf("SELECT f_geometry_column from geometry_columns WHERE f_table_name='%s'",tmpTbl)
    geo <- dbGetQuery(con,sql)
    if(length(geo)>1){
      tname <- sprintf("%s(%s)",tmpTbl,geo$f_geometry_column[1])
    }else{
      tname <- tmpTbl;
    }
    out <- readOGR(dsn,tname)
    return(out)
  },finally={
    sql <- sprintf("DROP TABLE %s",tmpTbl)
    dbSendQuery(con,sql)
    dbClearResult(dbListResults(con)[[1]])
    dbDisconnect(con)
  })
}

Використання:

d=list(host='localhost', dbname='spatial_db', port='5432', user='myusername', password='mypassword')
spatialObj<-dbGetSp(dbInfo=d,"SELECT * FROM spatial_table")

Але це все ще болісно повільно:

Для невеликого набору багатокутників (6 можливостей, 22 поля):

постгігійна частина:

user  system elapsed
0.001   0.000   0.008

частина readOGR:

user  system elapsed
0.313   0.021   1.436

2

Зараз існує пакет RPostGIS, який може імпортувати геометри PostGIS в R за допомогою SQL-запитів.


1

Ви також можете комбінувати rgdal і RPostreSQL. Ця прикладна функція створює тимчасову таблицю з RPostgreSQL і відправляє її в readOGR для виведення просторового об'єкта. Це дійсно неефективно і некрасиво, але це працює досить добре. Зауважте, що запит повинен бути SELECT-запитом, і користувач повинен мати доступ до запису до бази даних.

RPostGIS <- function(coninfo,query) {
  dsn=paste("PG:dbname='",coninfo$dbname,"' host='",coninfo$host,"' port='",coninfo$port,"' user='",coninfo$user,"' password='",coninfo$password,"'", sep='')
  drv <- dbDriver("PostgreSQL")
  con <- dbConnect(drv, user=coninfo$user, password=coninfo$password, dbname=coninfo$dbname)
  res <- dbSendQuery(con,paste('CREATE TABLE tmp1209341251dva1 AS ',query,sep=''))
  geo <- dbGetQuery(con,"SELECT f_geometry_column from geometry_columns WHERE f_table_name='tmp1209341251dva1'")
  if(length(geo)>1){
    tname=paste("tmp1209341251dva1(",geo$f_geometry_column[1],")")
  }else{
    tname="tmp1209341251dva1";
  }
  out <- tryCatch(readOGR(dsn,tname), finally=dbSendQuery(con,'DROP TABLE tmp1209341251dva1'))
  dbDisconnect(con)
  return(out)
}

Ви можете назвати це чимось на зразок:

> require('rgdal')
> require('RPostgreSQL')
> coninfo=list(host='localhost',dbname='spatial_db',port='5432',user='myusername',password='mypassword')
> spatial_obj<-RPostGIS(coninfo,"SELECT * FROM spatial_table")

0

Якщо ви повернете запит із "ST_AsText (geom) як geomwkt" і отримаєте результат у дані, ви можете використовувати:

library(rgeos);library(sp)
wkt_to_sp <- function(data) {
  #data is data.frame from postgis with geomwkt as only geom
  SpP <- SpatialPolygons(lapply(1:length(data$geomwkt), 
           function(x) Polygons(list(Polygon(readWKT(data$geomwkt[x]))),x)))
  data <- data[,!(names(data) == "geomwkt")]
  return(SpatialPolygonsDataFrame(SpP, data))
}

Ще болісно повільно .... 1 секунда на 100 гемів на тесті.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.