Bekerja dengan data PostGIS di R?


27

Saya bekerja dengan R hampir sepanjang waktu, dan sekarang saya menggunakannya untuk melakukan penambangan data spasial.

Saya memiliki database PostGIS dengan (jelas) data GIS.

Jika saya ingin membuat analisis spasial statistik dan plot peta adalah cara yang lebih baik untuk:

  • ekspor tabel sebagai shapefile atau;
  • bekerja langsung ke database?

Jawaban:


34

Jika Anda memiliki kemampuan driver PostGIS dalam paket rgdal maka itu hanya masalah membuat string koneksi dan menggunakannya. Di sini saya terhubung ke database lokal saya gismenggunakan kredensial default, jadi DSN saya agak sederhana. Anda mungkin perlu menambahkan host, nama pengguna, atau kata sandi. Lihat gdal docs untuk info.

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

Tabel apa yang ada di database itu?

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

Dapatkan Satu:

> 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

Apa yang saya dapatkan?

> 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  

Kalau tidak, Anda dapat menggunakan fungsionalitas database R dan meminta tabel secara langsung.

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

Yang mengembalikan geometri fitur df$geom, yang Anda harus mengkonversi ke spobjek kelas (SpatialPolygons, SpatialPoints, SpatialLines) untuk melakukan apa saja dengan. Fungsi readWKT di rgeos dapat membantu dengan itu.

Hal-hal yang perlu diperhatikan biasanya adalah hal-hal seperti kolom basis data yang tidak dapat dipetakan ke tipe data R. Anda dapat memasukkan SQL dalam kueri untuk melakukan konversi, pemfilteran, atau pembatasan. Ini seharusnya membantu Anda memulai.


Jawaban bagus, tetapi bagaimana saya mengaktifkan kapabilitas (driver Postgis) rgadl? Saya di Ubuntu 13.04 ...
nanounanue

Apakah kamu memilikinya? Fungsi ogrDrivers () harus memberi tahu Anda di suatu tempat. Jika tidak maka itu adalah pertanyaan lain (mungkin yang terbaik di-google-kan dulu dan kemudian ditanyakan pada R-sig-geo)
Spacedman

Di Ubuntu, driver diinstal secara default. Itu tidak terjadi di MacOS X. Terima kasih!
nanounanue

Dalam kode Anda di atas, Apakah mungkin dalam readOGRmetode ini menggunakan sql, bukan tabel lengkap?
nanounanue

Saat ini saya pikir tidak. Ada beberapa obrolan di r-sig-geo sekitar 2.5 tahun yang lalu tentang ini, tetapi tampaknya tidak ada yang dilakukan. Tampaknya sederhana untuk menambahkan whereklausa dan meneruskannya ke OGR melalui setAttributeFiltertetapi semua harus dilakukan dalam kode C dan C ++ ...
Spacedman

8

Jika Anda memiliki data di Postgis, jangan mengekspornya ke shapefile. Dari sudut pandang saya, ini semacam langkah mundur.

Anda dapat meminta database postgis Anda dari R menggunakan pernyataan SQL, mengimpornya sebagai kerangka data dan, karena Anda terbiasa dengan R, lakukan semua geostatistik yang Anda butuhkan dari sana. Saya yakin Anda juga dapat mengekspor hasil geostatistik Anda kembali ke postgis.

Menggunakan SQL dengan Fungsi Postgis Anda juga dapat melakukan semua jenis analisis spasial, seperti operasi overlay, jarak, dan sebagainya.

Untuk memetakan peta, saya akan menggunakan QGIS , sebuah perangkat lunak OpenSource GIS, yang dapat membaca postgis secara langsung (sejauh yang saya tahu itu adalah tujuan awal proyek), dan versi 2.0 yang akan datang hadir dengan banyak fitur untuk menghasilkan peta yang tampak hebat .


Ok saran bagus, tapi karena saya ingin mengotomatiskan semua yang ada di R (termasuk plot) ke QGis, hentikan alurnya, bukan?
nanounanue

Dalam hal ini, jika Anda merasa nyaman dengan itu, cukup gunakan R untuk memetakan peta Anda. Meski begitu, dengan menyiapkan layout proyek qgis berdasarkan data postgis (diperbarui), mereka juga akan memperbarui. Saya kira pada akhirnya itu akan menjadi pilihan pribadi apakah akan menggunakan R atau QGIS.
Alexandre Neto

Terima kasih atas tanggapan cepat Anda, tetapi bagaimana saya bisa membuat plot menggunakan R, dari tabel di Postgis?
nanounanue

Saya tidak terlalu berpengalaman dengan R dan saya tidak tahu bagaimana Anda memplot data vektor menggunakannya (seperti saya katakan saya menggunakan QGIS untuk itu), bagaimana Anda merencanakan shapfile di R? Untuk menghubungkan ke PostgresSQL dari RI telah menggunakan RPostgreSQL sebelumnya. Saya pikir rgdal ]. Semoga berhasil!
Alexandre Neto

5

Paket sf yang baru diperkenalkan (succesor sp) menyediakan st_read()dan st_read_db()fungsinya. Setelah tutorial ini dan dari pengalaman saya, ini lebih cepat daripada cara yang telah disebutkan. Karena sf mungkin akan menggantikan sp suatu hari itu juga merupakan panggilan yang baik untuk melihat sekarang;)

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

Anda juga dapat mengakses DB menggunakan 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)

Dengan st_write()Anda dapat mengunggah data.


1
Ini adalah solusi paling sederhana, ada sketsa vignette cran.r-project.org/web/packages/sf/vignettes/sf2.html menjelaskan cara menggunakan sf
Cedric

2

Anda dapat menggunakan semua alat pada saat yang sama berdasarkan untuk setiap langkah untuk solusi Anda.

  • Jika Anda ingin melakukan analisis geostatis, gunakan paket R.R lebih kuat dan memungkinkan Anda untuk hasil yang lebih analitis. Anda dapat mengimpor data berdasarkan kueri SQL.
  • Jika Anda ingin menggabungkan data Anda berdasarkan logika Anda dapat menggunakan PostGIS. Anda dapat menjawab pertanyaan kompleks seperti mana banyak poin dalam batas yang ditentukan saya? Namun dalam skala besar.
  • Untuk pemetaan, Anda dapat menggunakan R atau QGIS. QGIS lebih lurus ke depan, dengan R Anda mungkin berjuang untuk mencapai hasil yang diinginkan.

Kami dapat memberi Anda jawaban yang lebih spesifik jika Anda memberi kami lebih banyak detail dari masalah Anda


Bisakah Anda memberikan contoh poin terakhir, maksud saya, bagaimana saya bisa melakukannya jika saya ingin memetakan peta dengan R dari sebuah tabel di Postgis?
nanounanue

@nanounanue yakin: perpustakaan ("rgdal") mydata = readOGR (dsn = "PG: dbname = <mydb>", layer = "schema.table") plot (mydata, axes = TRUE) judul ("My Plot").
nickes

lihat juga halaman ini: wiki.intamap.org/index.php/PostGIS
nickves

2

Saya juga akan menggunakan kombinasi rgdal dan RPostgreSQL. Jadi, kode yang sama dengan @Guillaume, kecuali dengan tryCatch yang menangani lebih banyak baris, nama tabel pseudo-acak dan penggunaan tabel yang tidak di-log untuk kinerja yang lebih baik. (Catatan untuk diri saya: kita tidak bisa menggunakan tabel TEMP, karena itu tidak terlihat dari 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)
  })
}

Pemakaian:

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

Tapi, ini masih sangat lambat:

Untuk sekelompok kecil poligon (6 fitur, 22 bidang):

bagian postgis:

user  system elapsed
0.001   0.000   0.008

bagian readOGR:

user  system elapsed
0.313   0.021   1.436


1

Anda juga dapat menggabungkan rgdal dan RPostreSQL. Fungsi contoh ini membuat tabel sementara dengan RPostgreSQL dan mengirimkannya ke readOGR untuk output objek spasial. Ini benar-benar tidak efisien dan jelek, tetapi bekerja dengan cukup baik. Perhatikan bahwa kueri harus menjadi kueri SELECT dan pengguna harus memiliki akses tulis ke database.

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

Anda dapat menyebutnya dengan sesuatu seperti:

> 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

Jika Anda mengembalikan kueri dengan 'ST_AsText (geom) sebagai geomwkt' dan mengambil hasilnya menjadi data, Anda dapat menggunakan:

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

Masih sangat lambat .... 1 detik selama 100 geom pada tes.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.