มีประสิทธิภาพมากขึ้น Spatial อวกาศเข้าร่วมใน Python โดยไม่ต้องมี QGIS, ArcGIS, PostGIS, ฯลฯ


31

ฉันกำลังพยายามทำการรวมเชิงพื้นที่เหมือนตัวอย่างที่นี่: มีตัวเลือกหลามเพื่อ "เข้าร่วมแอตทริบิวต์ตามตำแหน่งที่ตั้ง" หรือไม่ . อย่างไรก็ตามวิธีการนั้นดูเหมือนไม่มีประสิทธิภาพ / ช้าจริงๆ แม้แต่การวิ่งด้วยความสุภาพ 250 คะแนนใช้เวลาเกือบ 2 นาทีและมันล้มเหลวอย่างสิ้นเชิงกับรูปร่างที่มี> 1,000 คะแนน มีแนวทางที่ดีกว่านี้ไหม? ฉันต้องการทำสิ่งนี้ทั้งหมดใน Python โดยไม่ต้องใช้ ArcGIS, QGIS, ฯลฯ

ฉันยังสนใจที่จะทราบว่าเป็นไปได้ที่จะใช้แอตทริบิวต์ SUM (เช่นจำนวนประชากร) ของทุกจุดที่อยู่ในรูปหลายเหลี่ยมและเข้าร่วมปริมาณนั้นกับรูปหลายเหลี่ยมรูปร่างหรือไม่

นี่คือรหัสที่ฉันพยายามแปลง ฉันได้รับข้อผิดพลาดในบรรทัดที่ 9:

poly['properties']['score'] += point['properties']['score']

ซึ่งพูดว่า:

TypeError: ประเภทของตัวถูกดำเนินการที่ไม่รองรับสำหรับ + ​​=: 'NoneType' และ 'float'

ถ้าฉันแทนที่ "+ =" ด้วย "=" มันจะทำงานได้ดี แต่นั่นไม่ได้ผลรวมฟิลด์ ฉันได้ลองทำสิ่งเหล่านี้ด้วยจำนวนเต็ม แต่ก็ล้มเหลวเช่นกัน

with fiona.open(poly_shp, 'r') as n: 
  with fiona.open(point_shp,'r') as s:
    outSchema = {'geometry': 'Polygon','properties':{'region':'str','score':'float'}}
    with fiona.open (out_shp, 'w', 'ESRI Shapefile', outSchema, crs) as output:
        for point in s:
            for poly in n:
                if shape(point['geometry']).within(shape(poly['geometry'])):  
                    poly['properties']['score']) += point['properties']['score'])
                    output.write({
                        'properties':{
                            'region':poly['properties']['NAME'],
                            'score':poly['properties']['score']},
                        'geometry':poly['geometry']})

ฉันคิดว่าคุณควรแก้ไขคำถามที่สองของคุณที่นี่เพื่อให้คำถามนี้ยังคงเน้นไปที่สิ่งที่ฉันคิดว่าเป็นคำถามที่สำคัญกว่าสำหรับคุณ อื่น ๆ สามารถวิจัย / ถามแยกต่างหาก
PolyGeo

คำตอบ:


37

Fiona ส่งคืนพจนานุกรม Python และคุณไม่สามารถใช้poly['properties']['score']) += point['properties']['score'])กับพจนานุกรมได้

ตัวอย่างของการรวมแอตทริบิวต์โดยใช้การอ้างอิงที่กำหนดโดย Mike T:

ป้อนคำอธิบายรูปภาพที่นี่

# read the shapefiles 
import fiona
from shapely.geometry import shape
polygons = [pol for pol in fiona.open('poly.shp')]
points = [pt for pt in fiona.open('point.shp')]
# attributes of the polygons
for poly in polygons:
   print poly['properties'] 
OrderedDict([(u'score', 0)])
OrderedDict([(u'score', 0)])
OrderedDict([(u'score', 0)])

# attributes of the points
for pt in points:
    print i['properties']
 OrderedDict([(u'score', 1)]) 
 .... # (same for the 8 points)

ตอนนี้เราสามารถใช้สองวิธีโดยมีหรือไม่มีดัชนีเชิงพื้นที่:

1) โดยไม่ต้อง

# iterate through points 
for i, pt in enumerate(points):
     point = shape(pt['geometry'])
     #iterate through polygons
     for j, poly in enumerate(polygons):
        if point.within(shape(poly['geometry'])):
             # sum of attributes values
             polygons[j]['properties']['score'] = polygons[j]['properties']['score'] + points[i]['properties']['score']

2) ด้วยดัชนี R-tree (คุณสามารถใช้ pyrtreeหรือrtree )

# Create the R-tree index and store the features in it (bounding box)
 from rtree import index
 idx = index.Index()
 for pos, poly in enumerate(polygons):
       idx.insert(pos, shape(poly['geometry']).bounds)

#iterate through points
for i,pt in enumerate(points):
  point = shape(pt['geometry'])
  # iterate through spatial index
  for j in idx.intersection(point.coords[0]):
      if point.within(shape(multi[j]['geometry'])):
            polygons[j]['properties']['score'] = polygons[j]['properties']['score'] + points[i]['properties']['score']

ผลลัพธ์ที่ได้จากสองแนวทาง:

for poly in polygons:
   print poly['properties']    
 OrderedDict([(u'score', 2)]) # 2 points in the polygon
 OrderedDict([(u'score', 1)]) # 1 point in the polygon
 OrderedDict([(u'score', 1)]) # 1 point in the polygon

อะไรคือความแตกต่าง ?

  • หากไม่มีดัชนีคุณต้องวนซ้ำรูปทรงเรขาคณิตทั้งหมด (รูปหลายเหลี่ยมและคะแนน)
  • ด้วยดัชนีขอบเขตเชิงพื้นที่ (ดัชนีเชิงพื้นที่ RTree ) คุณวนซ้ำผ่านรูปทรงเรขาคณิตซึ่งมีโอกาสที่จะตัดกับรูปทรงเรขาคณิตปัจจุบันของคุณ ('ตัวกรอง' ซึ่งสามารถบันทึกการคำนวณและเวลาจำนวนมาก ... )
  • แต่ดัชนีอวกาศไม่ใช่ไม้เท้าวิเศษ เมื่อส่วนใหญ่ของชุดข้อมูลจะต้องถูกดึงดัชนีอวกาศไม่สามารถให้ผลประโยชน์ความเร็วใด ๆ

หลังจาก:

schema = fiona.open('poly.shp').schema
with fiona.open ('output.shp', 'w', 'ESRI Shapefile', schema) as output:
    for poly in polygons:
        output.write(poly)

หากต้องการดูเพิ่มเติมให้ดูที่การใช้การจัดทำดัชนี Rtree Spatial ด้วย OGR, Shapely, Fiona


15

นอกจากนี้ - geopandas ตอนนี้รวมrtreeเป็นทางเลือกให้อ้างอิงดูgitub repo

ดังนั้นแทนที่จะทำตามรหัส (ดีมาก) ข้างต้นคุณสามารถทำสิ่งที่ชอบ:

import geopandas
from geopandas.tools import sjoin
point = geopandas.GeoDataFrame.from_file('point.shp') # or geojson etc
poly = geopandas.GeoDataFrame.from_file('poly.shp')
pointInPolys = sjoin(point, poly, how='left')
pointSumByPoly = pointInPolys.groupby('PolyGroupByField')['fields', 'in', 'grouped', 'output'].agg(['sum'])

เพื่อให้ได้ฟังก์ชั่นโก๋นี้โปรดติดตั้งlibspatialindex C-library ก่อน

แก้ไข: นำเข้าแพคเกจที่ถูกต้อง


ฉันอยู่ภายใต้การแสดงผลrtreeเป็นตัวเลือก นั่นไม่ได้หมายความว่าคุณต้องติดตั้งrtreeเช่นเดียวกับlibspatialindexC-library?
kuanb

ไม่นานมานี้ แต่ฉันคิดว่าเมื่อฉันทำสิ่งนี้การติดตั้ง geopandas จาก github จะถูกเพิ่มโดยอัตโนมัติ rtreeเมื่อฉันติดตั้งครั้งแรกlibspatialindex... พวกเขาทำการวางตลาดครั้งใหญ่พอสมควรเนื่องจากฉันมั่นใจว่าทุกอย่างเปลี่ยนไปเล็กน้อย
claytonrsh

9

ใช้Rtreeเป็นดัชนีเพื่อทำการเชื่อมต่อที่เร็วขึ้นจากนั้น Shapely เพื่อทำปริภูมิเชิงพื้นที่เพื่อตรวจสอบว่าจุดนั้นอยู่ในรูปหลายเหลี่ยมจริงหรือไม่ หากทำอย่างถูกต้องสิ่งนี้อาจเร็วกว่า GIS อื่น ๆ ส่วนใหญ่

ดูตัวอย่างที่นี่หรือที่นี่

ส่วนที่สองของคำถามของคุณเกี่ยวกับ 'SUM' ใช้dictวัตถุเพื่อสะสมประชากรโดยใช้รูปหลายเหลี่ยม id เป็นกุญแจสำคัญ ถึงแม้ว่าสิ่งประเภทนี้จะทำอย่างมากกับ PostGIS


ขอบคุณ @Mike T ... การใช้วัตถุ dict หรือ PostGIS เป็นคำแนะนำที่ดี ฉันยังคงสับสนเล็กน้อยที่ฉันสามารถรวม Rtree ในรหัสของฉันอย่างไรก็ตาม (รวมรหัสด้านบน)
jburrfischer

1

หน้าเว็บนี้แสดงวิธีการใช้การค้นหาจุดในรูปหลายเหลี่ยมกล่อง Bounding Box ก่อนที่จะมีราคาแพงกว่าภายในแบบสอบถามเชิงพื้นที่ของ Shapely

http://rexdouglass.com/fast-spatial-joins-in-python-with-a-spatial-index/


ขอบคุณ @klewis ... โอกาสใด ๆ ที่คุณสามารถช่วยได้ในส่วนที่สอง? เพื่อสรุปคุณสมบัติของจุด (เช่นจำนวนประชากร) ที่อยู่ในรูปหลายเหลี่ยมฉันลองอะไรที่คล้ายกับโค้ดด้านล่าง แต่เกิดข้อผิดพลาด ถ้ารูปร่าง (โรงเรียน ['เรขาคณิต']) ภายใน (รูปร่าง (พื้นที่ใกล้เคียง ['เรขาคณิต'])): ละแวก ['คุณสมบัติ'] ['ประชากร'] + = โรงเรียน ['คุณสมบัติ'] ['ประชากร']
jburrfischer

หากคุณเปิดย่านที่คุ้นเคยในโหมด 'r' อาจเป็นแบบอ่านอย่างเดียว รูปร่างทั้งสองมีประชากรภาคสนามหรือไม่? บรรทัดข้อผิดพลาดอะไร # โชคดี.
klewis

ขอบคุณอีกครั้ง @klewis ... ฉันเพิ่มรหัสด้านบนแล้วและอธิบายข้อผิดพลาด นอกจากนี้ฉันได้เล่นรอบกับ rtree และฉันยังสับสนเล็กน้อยที่ฉันจะเพิ่มลงในรหัสข้างต้น ขออภัยที่ต้องเป็นเช่นรำคาญ
jburrfischer

ลองนี้ดูเหมือนว่าการเพิ่ม None ลงใน int ทำให้เกิดข้อผิดพลาด poly_score = poly ['properties'] ['score']) point_score = point ['properties'] ['score']) ถ้า point_score: ถ้า poly_score poly ['Properties'] [+ คะแนน point_score อื่น: โพลี ['คุณสมบัติ'] ['คะแนน']) = point_score
klewis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.