ทำงานกับข้อมูล PostGIS ใน R หรือไม่


27

ฉันทำงานกับ R เกือบตลอดเวลาและตอนนี้ฉันใช้มันเพื่อการขุดข้อมูลเชิงพื้นที่

ฉันมีฐานข้อมูล PostGIS ที่มีข้อมูล GIS (ชัดเจน)

หากฉันต้องการทำการวิเคราะห์เชิงพื้นที่เชิงสถิติและพล็อตแผนที่เป็นวิธีที่ดีกว่าในการ:

  • ส่งออกตารางเป็นรูปร่างหรือ;
  • ทำงานโดยตรงกับฐานข้อมูลหรือไม่

คำตอบ:


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 ...
nanounanue

คุณมีหรือไม่ ฟังก์ชัน ogrDrivers () ควรบอกคุณบางที่ ถ้าไม่ใช่นั่นเป็นคำถามอื่นทั้งหมด (อาจจะดีที่สุดสำหรับ googled ก่อนแล้วถามใน R-sig-geo)
Spacedman

ใน Ubuntu ไดรเวอร์จะถูกติดตั้งตามค่าเริ่มต้น ไม่เป็นเช่นนั้นใน MacOS X ขอบคุณ!
nanounanue

ในรหัสของคุณข้างต้นเป็นไปได้ในreadOGRวิธีการใช้ sql แทนตารางเต็ม?
nanounanue

ปัจจุบันฉันคิดว่าไม่ มีเรื่องไร้สาระบางอย่างเกี่ยวกับ r-sig-geo ประมาณ 2.5 ปีที่แล้วเกี่ยวกับเรื่องนี้ แต่ดูเหมือนจะไม่มีอะไรเกิดขึ้น มันดูเรียบง่ายที่จะเพิ่มwhereข้อและผ่านที่ OGR ผ่านsetAttributeFilterแต่ที่ทุกคนจะต้องมีการทำใน C และ C ++ รหัส ...
Spacedman

8

หากคุณมีข้อมูลใน Postgis อย่าส่งออกไปยังรูปร่างไฟล์ จากมุมมองของฉันมันเป็นขั้นตอนหลัง

คุณสามารถสืบค้นฐานข้อมูล postgis ของคุณจาก R โดยใช้คำสั่ง SQL นำเข้าเป็น dataframes และเนื่องจากคุณคุ้นเคยกับ R ให้ทำ geostatistics ทั้งหมดที่คุณต้องการจากที่นั่น ฉันเชื่อว่าคุณสามารถส่งออกผลลัพธ์ทางภูมิศาสตร์ของคุณกลับไปยังตำแหน่งโพสต์

การใช้ SQL กับฟังก์ชั่น Postgis คุณสามารถทำการวิเคราะห์เชิงพื้นที่ทุกประเภทเช่นการซ้อนทับระยะทางและอื่น ๆ

สำหรับแผนที่พล็อตที่ฉันจะใช้QGISซอฟต์แวร์ OpenSource ระบบสารสนเทศภูมิศาสตร์ที่สามารถอ่าน PostGIS โดยตรง (เท่าที่ผมรู้ว่านั่นคือเป้าหมายแรกของโครงการ) และรุ่นที่จะเกิดขึ้น 2.0 มาพร้อมกับคุณสมบัติมากมายในการผลิตแผนที่ที่ดูดี


ตกลงคำแนะนำที่ดี แต่เนื่องจากฉันต้องการทำให้ทุกอย่างเป็นอัตโนมัติใน R (รวมถึงพล็อต) ไปที่ QGis หยุดไหลไม่ได้ใช่ไหม
nanounanue

ในกรณีนี้หากคุณพอใจกับมันเพียงใช้ R เพื่อพล็อตแผนที่ของคุณ ถึงกระนั้นหากการเตรียมเค้าโครงโครงการ qgis จัดทำขึ้นตามข้อมูล postgis (อัพเดต) พวกเขาก็จะอัพเดตเช่นกัน ฉันเดาว่าในท้ายที่สุดมันจะเป็นทางเลือกส่วนตัวว่าจะใช้ R หรือ QGIS
Alexandre Neto

ขอบคุณสำหรับการตอบกลับอย่างรวดเร็ว แต่ฉันจะทำพล็อตโดยใช้ R จากตารางใน Postgis ได้อย่างไร
nanounanue

ฉันไม่ค่อยมีประสบการณ์กับ R และฉันไม่รู้ว่าคุณจะพล็อตข้อมูลเวกเตอร์โดยใช้มันอย่างไร (อย่างที่ฉันบอกว่าฉันใช้ QGIS สำหรับเรื่องนั้น) คุณจะวาด shapfiles ใน R ได้อย่างไร? สำหรับการเชื่อมต่อกับ PostgresSQL จาก RI ได้เคยใช้RPostgreSQLมาก่อน ฉันคิดว่าrgdal ] โชคดี!
Alexandre Neto

5

sf-package ที่เพิ่งเปิดตัวใหม่(succesor of sp) มอบฟังก์ชั่นst_read()และ st_read_db()หลังจากบทช่วยสอนนี้และจากประสบการณ์ของฉันมันเร็วกว่าวิธีที่กล่าวถึงแล้ว เนื่องจากเอสเอฟอาจจะแทนที่ 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
นี่เป็นวิธีที่ง่ายที่สุดมี vignette cran.r-project.org/web/packages/sf/vignettes/sf2.htmlอธิบายวิธีใช้ sf
Cedric

2

คุณสามารถใช้เครื่องมือทั้งหมดในเวลาเดียวกันตามแต่ละขั้นตอนสำหรับโซลูชันของคุณ

  • หากคุณต้องการทำการวิเคราะห์ทางธรณีฟิสิกส์ให้ใช้แพ็คเกจของอาร์อาร์มากขึ้นและช่วยให้คุณได้ผลลัพธ์การวิเคราะห์ที่มากขึ้น คุณสามารถนำเข้าข้อมูลตามการสอบถาม SQL
  • หากคุณต้องการรวมข้อมูลของคุณตามหลักตรรกะคุณสามารถใช้ PostGIS คุณสามารถตอบคำถามที่ซับซ้อนเช่นมีหลายจุดที่อยู่ภายในขีด จำกัด ที่ฉันกำหนด แต่ในระดับที่ยิ่งใหญ่
  • สำหรับการทำแผนที่คุณสามารถใช้ R หรือ QGIS QGIS ตรงไปตรงมามากขึ้นด้วย R คุณอาจดิ้นรนเพื่อให้ได้ผลลัพธ์ที่ต้องการ

เราสามารถให้คำตอบที่เฉพาะเจาะจงมากขึ้นถ้าคุณต้องการให้รายละเอียดเพิ่มเติมจากปัญหาของคุณ


คุณช่วยยกตัวอย่างจุดสุดท้ายฉันหมายถึงฉันจะทำอย่างไรถ้าฉันต้องการพล็อตแผนที่ด้วย R จากตารางใน Postgis
nanounanue

@nanounanue แน่ใจว่า: library ("rgdal") mydata = readOGR (dsn = "PG: dbname = <myds", layer = "schema.table") ชื่อเรื่อง (mydata, axes = TRUE) ("My Plot")
nickves

ดูที่หน้านี้: wiki.intamap.org/index.php/PostGIS
nickves

2

ฉันจะไปรวมกันของ rgdal และ RPostgreSQL ดังนั้นรหัสเดียวกันกับ @Guillaume ยกเว้นด้วย tryCatch ที่จัดการกับสายได้มากขึ้นชื่อตารางแบบหลอกเทียมและการใช้ตารางที่ไม่ถูกบล็อกเพื่อประสิทธิภาพที่ดีขึ้น (หมายเหตุถึงตัวเอง: เราไม่สามารถใช้ตาราง 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 สาขา):

ส่วน postgis:

user  system elapsed
0.001   0.000   0.008

ส่วน readOGR:

user  system elapsed
0.313   0.021   1.436


1

คุณยังสามารถรวม rgdal และ RPostreSQL ฟังก์ชันตัวอย่างนี้สร้างตารางชั่วคราวด้วย RPostgreSQL และส่งไปยัง readOGR สำหรับผลลัพธ์ของวัตถุเชิงพื้นที่ มันไม่มีประสิทธิภาพและน่าเกลียดจริงๆ แต่มันใช้งานได้ดี โปรดทราบว่าแบบสอบถามจะต้องมีแบบสอบถามแบบใช้เลือกข้อมูลและผู้ใช้จำเป็นต้องมีการเข้าถึงเพื่อเขียนไปยังฐานข้อมูล

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 geoms ในการทดสอบ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.