Làm việc với dữ liệu PostGIS trong R?


27

Tôi làm việc với R gần như mọi lúc, và bây giờ tôi đang sử dụng nó để thực hiện khai thác dữ liệu không gian.

Tôi có một cơ sở dữ liệu PostGIS với (rõ ràng) dữ liệu GIS.

Nếu tôi muốn thực hiện phân tích không gian thống kê và bản đồ lô là cách tốt hơn để:

  • xuất các bảng dưới dạng shapefiles hoặc;
  • Làm việc trực tiếp với cơ sở dữ liệu?

Câu trả lời:


34

Nếu bạn có khả năng trình điều khiển PostGIS trong gói rgdal thì đó chỉ là câu hỏi tạo chuỗi kết nối và sử dụng chuỗi đó. Ở đây tôi đang kết nối với cơ sở dữ liệu cục bộ của mình gisbằng thông tin đăng nhập mặc định, vì vậy DSN của tôi khá đơn giản. Bạn có thể cần thêm máy chủ, tên người dùng hoặc mật khẩu. Xem tài liệu gdal để biết thông tin.

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

Những bảng nào trong cơ sở dữ liệu đó?

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

Lấy một cái:

> 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

Tôi có gì?

> 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  

Nếu không, bạn có thể sử dụng chức năng cơ sở dữ liệu của R và truy vấn các bảng trực tiếp.

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

Điều đó trả về hình dạng tính năng df$geom, trong đó bạn sẽ cần chuyển đổi thành spcác đối tượng lớp (SpatialPolygons, SpatialPoints, SpatialLines) để làm bất cứ điều gì với. Hàm readWKT trong rgeos có thể giúp với điều đó.

Những thứ cần cẩn thận thường là những thứ như cột cơ sở dữ liệu không thể ánh xạ tới các kiểu dữ liệu R. Bạn có thể bao gồm SQL trong truy vấn để thực hiện chuyển đổi, lọc hoặc giới hạn. Điều này sẽ giúp bạn bắt đầu mặc dù.


Câu trả lời tuyệt vời, nhưng làm thế nào tôi kích hoạt khả năng (trình điều khiển Postgis) trong rgadl? Tôi đang ở Ubuntu 13.04 ...
nanounanue

Bạn có không? Hàm ogrDrivers () sẽ cho bạn biết ở đâu đó. Nếu không thì đó là một câu hỏi hoàn toàn khác (có lẽ là câu hỏi hay nhất được đặt ra trước tiên và sau đó được hỏi trên R-sig-Geo)
Spacesman

Trong Ubuntu, trình điều khiển được cài đặt theo mặc định. Đó không phải là trường hợp trong MacOS X. Cảm ơn!
nanounanue

Trong mã của bạn ở trên, có thể trong readOGRphương thức sử dụng sql thay vì bảng đầy đủ không?
nanounanue

Hiện tại tôi nghĩ là không. Có một vài cuộc trò chuyện trên r-sig-Geo khoảng 2,5 năm trước về điều này, nhưng dường như không có gì được thực hiện. Có vẻ đơn giản để thêm một wheremệnh đề và chuyển nó đến OGR thông qua setAttributeFilternhưng tất cả phải được thực hiện bằng mã C và C ++ ...
Spainedman

8

Nếu bạn có dữ liệu trong Postgis, đừng xuất dữ liệu sang shapefile. Theo quan điểm của tôi, đó là một bước lùi.

Bạn có thể truy vấn cơ sở dữ liệu postgis của mình từ R bằng cách sử dụng các câu lệnh SQL, nhập chúng dưới dạng dataframes và, vì bạn đã quen thuộc với R, hãy thực hiện tất cả các điều chỉnh địa lý bạn cần từ đó. Tôi tin rằng bạn cũng có thể xuất kết quả kiểm soát địa lý của bạn trở lại postgis.

Sử dụng SQL với Hàm Postgis, bạn cũng có thể thực hiện tất cả các loại phân tích không gian, như các hoạt động lớp phủ, khoảng cách, v.v.

Để vẽ sơ đồ, tôi sẽ sử dụng QGIS , một phần mềm OpenSource GIS, có thể đọc trực tiếp các postgis (theo như tôi biết đó là mục tiêu ban đầu của dự án) và phiên bản 2.0 sắp tới có rất nhiều tính năng để tạo ra các bản đồ tuyệt vời .


Được rồi, lời khuyên tuyệt vời, nhưng vì tôi muốn tự động hóa mọi thứ trong R (bao gồm cả các lô) sẽ đến QGis, phá vỡ dòng chảy, phải không?
nanounanue

Trong trường hợp đó, nếu bạn cảm thấy thoải mái với nó, chỉ cần sử dụng R để vẽ sơ đồ của bạn. Mặc dù vậy, có các bố trí dự án qgis được chuẩn bị dựa trên dữ liệu postgis (đã cập nhật), họ cũng sẽ cập nhật. Tôi đoán rằng cuối cùng nó sẽ là một lựa chọn cá nhân cho dù nên sử dụng R hay QGIS.
Alexandre Neto

Cảm ơn bạn đã phản hồi nhanh chóng, nhưng làm cách nào tôi có thể tạo một cốt truyện bằng R, từ một bảng trong Postgis?
nanounanue

Tôi không có nhiều kinh nghiệm với R và tôi không biết làm thế nào bạn vẽ biểu đồ dữ liệu vectơ bằng cách sử dụng nó (như tôi đã nói tôi sử dụng QGIS cho điều đó), làm thế nào để bạn vẽ biểu đồ shapfiles trong R? Để kết nối với PostgresSQL từ RI, bạn đã sử dụng RPostgreSQL trước đây. Tôi nghĩ rằng rgdal ]. Chúc may mắn!
Alexandre Neto

5

Gói sf mới được giới thiệu (thành công của sp) cung cấp các chức năng st_read()st_read_db(). Sau hướng dẫn này và từ kinh nghiệm của tôi, nó nhanh hơn các cách đã được đề cập. Vì sf có thể sẽ thay thế sp một ngày nào đó, đây cũng là một cuộc gọi tốt để xem bây giờ;)

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

bạn cũng có thể truy cập DB bằng 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)

Với st_write()bạn có thể tải lên dữ liệu.


1
Đây là giải pháp đơn giản nhất, có một họa tiết cran.r-project.org/web/packages/sf/vignettes/sf2.html giải thích cách sử dụng sf
Cedric

2

Bạn có thể sử dụng tất cả các công cụ cùng một lúc dựa trên từng bước cho giải pháp của mình.

  • Nếu bạn muốn thực hiện phân tích địa tĩnh, hãy sử dụng các gói của R. R mạnh mẽ hơn và cho phép bạn có kết quả phân tích nhiều hơn. Bạn có thể nhập dữ liệu dựa trên các câu lệnh SQL.
  • Nếu bạn muốn tổng hợp dữ liệu của mình dựa trên cơ sở logic, bạn có thể sử dụng PostGIS. Bạn có thể trả lời các truy vấn phức tạp như có bao nhiêu điểm nằm trong giới hạn quy định của tôi không? Nhưng trên quy mô lớn.
  • Để ánh xạ, bạn có thể sử dụng R hoặc QGIS. QGIS thẳng thắn hơn, với R bạn có thể chiến đấu để đạt được kết quả mong muốn.

Chúng tôi có thể cung cấp cho bạn câu trả lời cụ thể hơn nếu bạn cung cấp cho chúng tôi thêm chi tiết từ vấn đề của bạn


Bạn có thể cung cấp một ví dụ về điểm cuối cùng, ý tôi là, làm thế nào tôi có thể làm gì nếu tôi muốn vẽ một bản đồ với R từ một bảng trong Postgis?
nanounanue

@nanounanue chắc chắn: library ("rgdal") mydata = readOGR (dsn = "PG: dbname = <mydb>", layer = "giản đồ.table") âm mưu (mydata, axes = TRUE) title ("My Plot").
biệt danh

cũng hãy xem trang này: wiki.intamap.org/index.php/PostGIS
biệt danh

2

Tôi cũng sẽ kết hợp rgdal và RPostgreSQL. Vì vậy, cùng mã với @Guillaume, ngoại trừ với một tryCatch xử lý nhiều dòng hơn, tên bảng giả ngẫu nhiên và sử dụng bảng không được đăng ký để có hiệu suất tốt hơn. (Lưu ý với bản thân tôi: chúng tôi không thể sử dụng bảng TEMP, vì nó không hiển thị từ 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)
  })
}

Sử dụng:

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

Nhưng, điều này vẫn chậm một cách đau đớn:

Đối với một tập hợp đa giác nhỏ (6 tính năng, 22 trường):

phần hậu kỳ:

user  system elapsed
0.001   0.000   0.008

phần readOGR:

user  system elapsed
0.313   0.021   1.436

2

Hiện tại đã có gói RPostGIS có thể nhập địa lý PostGIS vào R bằng các truy vấn SQL.


1

Bạn cũng có thể kết hợp rgdal và RPostreSQL. Hàm ví dụ này tạo một bảng tạm thời với RPostgreSQL và gửi nó tới readOGR để xuất ra một đối tượng không gian. Điều này thực sự không hiệu quả và xấu, nhưng nó hoạt động khá tốt. Lưu ý rằng truy vấn phải là truy vấn CHỌN và người dùng cần có quyền truy cập ghi vào cơ sở dữ liệu.

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

Bạn có thể gọi nó với một cái gì đó như:

> 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

Nếu bạn trả về một truy vấn với 'ST_AsText (geom) là geomwkt' và tìm nạp kết quả vào dữ liệu, bạn có thể sử dụng:

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

Vẫn chậm một cách đau đớn .... 1 giây cho 100 geoms trong một bài kiểm tra.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.