R'de PostGIS verisiyle çalışmak?


27

Neredeyse her zaman R ile çalışıyorum ve şimdi mekansal veri madenciliği yapmak için kullanıyorum.

(Açıkçası) GIS verilerini içeren bir PostGIS veri tabanına sahibim.

İstatistiksel mekansal analiz yapmak ve harita çizmek istersem, daha iyi bir yoldur:

  • tabloları şekil dosyaları olarak ver veya;
  • doğrudan veritabanına çalışmak?

Yanıtlar:


34

Eğer rgdal paketinde PostGIS sürücü özelliği varsa, bu sadece bir bağlantı dizesi yaratma ve bunu kullanma meselesidir. Burada gisvarsayılan kimlik bilgileri kullanarak yerel veritabanıma bağlanıyorum , bu nedenle DSN'm oldukça basit. Bir ana bilgisayar, kullanıcı adı veya şifre eklemeniz gerekebilir. Bilgi için gdal belgelerine bakın.

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

Bu veritabanında hangi tablolar var?

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

Birini almak:

> 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

Elimde ne var?

> 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  

Aksi takdirde R'nin veritabanı işlevini kullanabilir ve tabloları doğrudan sorgulayabilirsiniz.

> 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)

Bu , bir şey yapmak df$geomiçin spsınıf nesnelerine (SpatialPolygons, SpatialPoints, SpatialLines) dönüştürmeniz gereken özellik geometrisini döndürür . Rgeos içindeki readWKT işlevi bu konuda yardımcı olabilir.

Dikkat edilmesi gerekenler, genellikle R veri türleriyle eşlenemeyen veritabanı sütunları gibidir. SQL'i dönüşüm, filtreleme veya sınırlama yapmak için sorguya dahil edebilirsiniz. Bu olsa seni başlatmalı.


Harika cevap, ancak yeteneği (Postgis sürücüsü) nasıl etkinleştirebilirim rgadl? Ubuntu'dayım 13.04 ...
nanounanue

Sende var mı? OgrDrivers () işlevi size bir yerde söyleyecektir. Eğer değilse o zaman bu başka bir soru (muhtemelen en iyisi ilk önce
googledim

Ubuntu'da sürücü varsayılan olarak kurulur. MacOS X'te durum böyle değil. Teşekkürler!
nanounanue

Yukarıdaki kodunuzda, readOGRyöntemde tam tablo yerine bir sql kullanılması mümkün mü ?
nanounanue

Şu anda sanmıyorum. Bu konuda yaklaşık 2.5 yıl önce r-sig-geo’de bazı konuşmalar oldu, ancak hiçbir şey yapılmamış gibi görünüyor. Bir wherecümle eklemek ve OGR'ye geçmek çok basit görünüyor setAttributeFilterama hepsinin C ve C ++ kodunda yapılması gerekiyor ...
Spacedman

8

Postgis'te verileriniz varsa, bunu shapefile dosyasına dışa aktarmayın. Benim açımdan, geri adım gibi bir adım.

Postgis veritabanınızı R'den SQL ifadeleri kullanarak sorgulayabilir, bunları veri çerçeveleri olarak alabilirsiniz ve R'ye aşina olduğunuzdan, ihtiyacınız olan tüm geostatistikleri oradan yapabilirsiniz. Jeostatistik sonucunuzu postgis'e geri verebileceğinize inanıyorum.

Postgis İşlevleri ile SQL'i kullanarak, bindirme işlemleri, mesafeler vb. Gibi her türlü uzamsal analizi de yapabilirsiniz.

Ben kullanırım komplo haritası için QGIS (O projenin ilk hedefi oldu bildiğimiz kadarıyla) doğrudan PostGIS okuyabilir, bir açık kaynak kodlu CBS yazılımı, ve yaklaşan sürüm 2.0 üretmek için birçok özellik ile birlikte geliyor harika görünümlü haritalar .


Tamam, harika bir tavsiye, ancak QGis'e giden R'deki (araziler dahil) her şeyi otomatikleştirmek istediğim için akışı bozuyor, değil mi?
nanounanue

Bu durumda, rahat ederseniz, haritalarınızı çizmek için R kullanın. Buna rağmen, qgis projeleri ile postgis (güncellenen) verilere dayanarak hazırlanan düzenler düzenlenirken, bunlar da güncellenir. Sonunda, R veya QGIS kullanıp kullanmamanın kişisel bir seçim olacağını tahmin ediyorum.
Alexandre Neto,

Hızlı cevabınız için teşekkür ederim, ancak Postgis'deki bir masadan R kullanarak nasıl arsa yapabilirim?
nanounanue

R konusunda çok tecrübeli değilim ve bunu kullanarak vektör verilerini nasıl çizeceğinizi bilmiyorum (bunun için QGIS kullandığımı söylediğim gibi), R'de shapfileleri nasıl çizersiniz? RI'den PostgresSQL'e bağlanmak için daha önce RPostgreSQL kullandık . Bence rgdal ]. İyi şanslar!
Alexandre Neto,

5

Yeni tanıtılan sf paketi (sp'in başarılı) işlevi st_read()ve st_read_db()işlevlerini sağlar. Bu dersten sonra ve tecrübelerime göre, belirtilen yöntemlerden daha hızlı . Sf muhtemelen bir gün sp yerini alacak gibi şimdi bakmak için de iyi bir çağrı;)

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

DB'ye RPostgreSQL kullanarak da erişebilirsiniz:

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)

İle st_write()veri yükleyebilirsiniz.


1
Bu en basit çözüm, sf
Cedric

2

Çözümünüz için her adımı temel alarak tüm araçları aynı anda kullanabilirsiniz.

  • Geostaticstical analiz yapmak istiyorsanız, R kullanın. R's paketleri daha sağlamdır ve daha analitik bir sonuç almanızı sağlar. SQL sorgularına göre verileri içe aktarabilirsiniz.
  • Verilerinizi mantıklı bir temelde toplamak istiyorsanız, PostGIS'i kullanabilirsiniz. Öngörülen sınırlarım içerisinde hangi noktaların olduğu gibi karmaşık soruları cevaplayabilirsiniz? Ama büyük ölçekte.
  • Haritalama için R veya QGIS kullanabilirsiniz. QGIS daha yalındır, R ile istediğiniz sonucu elde etmek için boğulabilir.

Bize probleminizden daha fazla ayrıntı verirseniz, size daha spesifik bir cevap verebiliriz.


Son noktaya bir örnek verebilir misiniz, demek istiyorum ki, Postgis'teki bir tablodan R ile bir harita çizmek istersem nasıl yapabilirim?
nanounanue

@ nanounanue sure: library ("rgdal") mydata = readOGR (dsn = "PG: dbname = <mydb>", layer = "schema.table") arsa (mydata, axes = TRUE) title ("My Plot").
nicks

ayrıca bu sayfaya bir göz atın: wiki.intamap.org/index.php/PostGIS
nickves

2

Ayrıca rgdal ve RPostgreSQL'in bir kombinasyonuna devam ediyorum. Bu nedenle, @Guillaume ile aynı kod, daha fazla satır işleyen bir tryCatch, sözde rasgele bir tablo adı ve daha iyi performans için unlog edilmiş bir tablonun kullanılması dışında. (Kendime not: TEMP tablosunu kullanamayız, çünkü readOGR'dan görülemez)

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)
  })
}

Kullanımı:

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

Ancak, bu hala acı verici bir şekilde yavaş:

Küçük bir çokgen grubu için (6 özellik, 22 alan):

postgis kısmı:

user  system elapsed
0.001   0.000   0.008

readOGR bölümü:

user  system elapsed
0.313   0.021   1.436


1

Ayrıca rgdal ve RPostreSQL'i de birleştirebilirsiniz. Bu örnek işlev, RPostgreSQL ile geçici bir tablo oluşturur ve onu uzaysal bir nesnenin çıktısı için readOGR'ye gönderir. Bu gerçekten verimsiz ve çirkin, ama oldukça iyi çalışıyor. Sorgunun bir SELECT sorgusu olması gerektiğini ve kullanıcının veritabanına yazma erişimi olması gerektiğini unutmayın.

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)
}

Buna şöyle bir şey diyebilirsin:

> 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' olarak bir sorgu döndürürseniz ve sonucu verilere alırsanız, şunları kullanabilirsiniz:

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))
}

Hala acı yavaş yavaş .... Bir testte 100 geom için 1 saniye.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.