วิธีที่เร็วที่สุดในการรวมจุด CSV เข้ากับรูปหลายเหลี่ยม Shapefile


19

ฉันมีไฟล์ CSV 1 พันล้านจุดและไฟล์รูปร่างที่มีประมาณ 5,000 รูปหลายเหลี่ยม อะไรจะเป็นวิธีที่เร็วที่สุดในการเข้าร่วมจุดและรูปหลายเหลี่ยมเชิงพื้นที่? สำหรับแต่ละจุดฉันจำเป็นต้องได้รับ polygon id ที่มี (รูปหลายเหลี่ยมไม่ทับซ้อนกัน)

โดยปกติฉันจะโหลดชุดข้อมูลทั้งสองลงใน PostGIS มีวิธีที่เร็วกว่าในการทำให้งานเสร็จหรือไม่?

ฉันกำลังมองหาโซลูชันโอเพนซอร์ซ

คำตอบ:


16

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

หากคุณใช้โปรแกรมกระป๋องแน่นอนว่าสิ่งที่ดีที่สุดที่คุณสามารถทำได้คือการประมวลผลรูปหลายเหลี่ยมล่วงหน้าเพื่อตั้งค่าโครงสร้างข้อมูลแบบจุดในรูปหลายเหลี่ยมเช่นต้นไม้ KD หรือควอดทรีซึ่งโดยทั่วไปประสิทธิภาพการทำงานจะเป็น O (log (V ) * (N + V)) โดยที่ V คือจำนวนทั้งหมดของจุดยอดในรูปหลายเหลี่ยมและ N คือจำนวนคะแนนเนื่องจากโครงสร้างข้อมูลจะใช้เวลาอย่างน้อย O (log (V) * V) ความพยายามในการสร้างและจากนั้นจะ จะต้องมีการตรวจสอบสำหรับแต่ละจุดที่ราคาต่อจุด O (บันทึก (V))

คุณสามารถทำได้ดีขึ้นอย่างมีนัยสำคัญโดยการ gridding รูปหลายเหลี่ยมก่อนใช้ประโยชน์จากสมมติฐานที่ไม่ทับซ้อนกัน เซลล์กริดแต่ละเซลล์จะอยู่ในรูปหลายเหลี่ยมด้านใน (รวมถึงด้านในของ "รูปหลายเหลี่ยมสากล") ซึ่งในกรณีนี้จะติดฉลากเซลล์ด้วย id ของรูปหลายเหลี่ยมหรืออย่างอื่นก็มีขอบรูปหลายเหลี่ยมหนึ่งรูปหรือมากกว่า ราคาของการแรสเตอร์นี้เท่ากับจำนวนของกริดเซลล์ที่อ้างอิงในขณะที่ทำการแรสเตอร์ทั้งหมดขอบคือ O (V / c) โดยที่ c คือขนาดของเซลล์ แต่ค่าคงที่โดยนัยในสัญกรณ์โอใหญ่

(ความสวยงามอย่างหนึ่งของวิธีการนี้คือคุณสามารถใช้ประโยชน์จากกราฟิกรูทีนมาตรฐานได้ตัวอย่างเช่นหากคุณมีระบบที่ (a) จะวาดรูปหลายเหลี่ยมบนหน้าจอเสมือนโดยใช้ (b) สีที่แตกต่างสำหรับแต่ละรูปหลายเหลี่ยมและ (c) อนุญาต ให้คุณอ่านสีของพิกเซลที่คุณสนใจตามที่คุณต้องการ

ด้วยตารางนี้ในสถานที่คัดกรองจุดล่วงหน้าโดยการคำนวณเซลล์ที่มีการดำเนินการแต่ละจุด (การดำเนินการ O (1) ที่ต้องใช้นาฬิกาเพียงไม่กี่) นอกเสียจากว่าจะมีการจัดกลุ่มจุดล้อมรอบรูปหลายเหลี่ยมขอบเขตนี้โดยทั่วไปแล้วจะเหลือเฉพาะจุด O (c) ที่มีผลลัพธ์ที่ไม่ชัดเจน ต้นทุนรวมของการสร้างกริดและการคัดกรองล่วงหน้าจึงเป็น O (V / c + 1 / c ^ 2) + O (N) คุณต้องใช้วิธีอื่น (เช่นที่แนะนำมาจนถึงตอนนี้) เพื่อดำเนินการกับคะแนนที่เหลืออยู่ (นั่นคือวิธีที่อยู่ใกล้กับรูปหลายเหลี่ยม) ในราคา O (log (V) * N * c) .

เมื่อ c มีขนาดเล็กลงคะแนนที่น้อยลงและน้อยลงจะอยู่ในเซลล์กริดเดียวกันที่มีขอบและดังนั้นจึงน้อยลงและน้อยลงจะต้องใช้การประมวลผล O (บันทึก (V)) ต่อมา การทำเช่นนี้จำเป็นที่จะต้องเก็บเซลล์กริด O (1 / c ^ 2) และต้องใช้เวลา O (V / c + 1 / c ^ 2) เวลาในการแรสเตอร์รูปหลายเหลี่ยม ดังนั้นจะมีขนาดกริดที่เหมาะสมที่สุด ใช้มัน, ค่าใช้จ่ายในการคำนวณรวมเป็น O (เข้าสู่ระบบ (V) * N) แต่คงนัยโดยทั่วไปจะมีวิธีที่มีขนาดเล็กกว่าโดยใช้วิธีการบรรจุกระป๋องเนื่องจากความเร็ว O (N) ของการตรวจคัดกรองก่อน

20 ปีที่แล้วฉันทดสอบวิธีการนี้ (ใช้จุดเว้นระยะอย่างสม่ำเสมอทั่วทั้งอังกฤษและนอกชายฝั่งและใช้ตารางที่ค่อนข้างหยาบของเซลล์ประมาณ 400K ที่นำเสนอโดยบัฟเฟอร์วิดีโอในเวลานั้น) และได้รับคำสั่งสองขนาดของการเร่งความเร็วเมื่อเทียบกับอัลกอริทึมที่ดีที่สุด หา. แม้ว่ารูปหลายเหลี่ยมจะมีขนาดเล็กและเรียบง่าย (เช่นรูปสามเหลี่ยม) แต่คุณสามารถมั่นใจได้ถึงลำดับความสำคัญของการเร่งความเร็ว

จากประสบการณ์ของฉันการคำนวณเร็วมากจนการดำเนินการทั้งหมดถูก จำกัด ด้วยความเร็วข้อมูล I / O ไม่ใช่โดย CPU เมื่อคาดหวังว่า I / O อาจเป็นคอขวดคุณจะได้ผลลัพธ์ที่เร็วที่สุดโดยการเก็บคะแนนไว้ในรูปแบบที่บีบอัดให้ได้มากที่สุดเพื่อลดเวลาในการอ่านข้อมูล ให้คิดด้วยว่าควรเก็บผลลัพธ์อย่างไรเพื่อให้คุณสามารถ จำกัด การเขียนดิสก์ได้


6
จุดเวลาที่ดีมากใช้เวลาตระหนักถึงวิธีการแก้ปัญหาและเวลาในการคำนวณ ใช้เวลานานในการหาทางออกที่ดีที่สุดจะเป็นประโยชน์เฉพาะเมื่อคุณตระหนักถึงการประหยัดเหล่านั้นผ่านการปรับให้เหมาะสม (โดยเฉพาะจากมุมมองของนายจ้าง)
Sasa Ivetic

5

สำหรับในส่วนของฉันฉันอาจจะโหลดข้อมูล CSV ลงในไฟล์shpแล้วเขียนสคริปต์ไพ ธ อนโดยใช้shapefileและหุ่นดีเพื่อให้ได้รูปหลายเหลี่ยมที่มีรหัสและอัปเดตค่าฟิลด์

ฉันไม่รู้ว่า geotools และ JTS นั้นเร็วกว่ารูปร่างไฟล์ / หุ่นดี ... ไม่มีเวลาทดสอบเลย!

แก้ไข : โดยวิธีการแปลงรูปแบบ csv เป็น shapefile อาจไม่จำเป็นเนื่องจากค่าสามารถจัดรูปแบบได้อย่างง่ายดายเพื่อทดสอบกับวัตถุเชิงพื้นที่จากรูปหลายเหลี่ยมรูปร่างของคุณ


4
ฉันจะโหลดข้อมูลโดยตรงโดยใช้เครื่องอ่าน csvและเติมดัชนีRtree spatial การรวมกันของ Rtree และ Shapely มีประสิทธิภาพที่น่าประทับใจ (ดีกว่า PostGIS มากฉันไม่สามารถเปรียบเทียบกับ JTS ได้เพราะฉันไม่รู้ Java)
Mike T

2
เป็นความคิดที่ดีหากคุณไม่จำเป็นต้องเก็บคะแนน 1b ทั้งหมดไว้ในหน่วยความจำพร้อมกัน อย่างน้อย 16 ไบต์ต่อจุด (X / Y) คุณกำลังดูข้อมูลที่มีค่า 16GB ถ้า Rtree จะสร้างดัชนีในที่จัดเก็บในตัวเครื่องมันจะช่วยเพิ่มประสิทธิภาพได้อย่างแน่นอน การนำเข้าคะแนน 1b ไปยังไฟล์รูปร่างเดียวจะไม่ทำงานเช่นกัน ข้อกำหนดรูปร่างของ OGR นั้น จำกัด อยู่ที่ 8GB (แนะนำให้ 4GB) รูปร่างจุดเดียวใช้ 20 ไบต์
Sasa Ivetic

4

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


3

ฉันได้อย่างรวดเร็วจะเขียนโปรแกรม Java ขนาดเล็กขึ้นอยู่กับผู้อ่าน shapefileของgeotoolsและการดำเนินงานมีของJTS ฉันไม่รู้ว่ามันจะเร็วแค่ไหน ...


1
หากคุณมีข้อมูลใน PostGIS แล้ว GeoTools สามารถใช้ประโยชน์จากดัชนีส่วนสำคัญอื่น ๆ ได้
Ian Turton

3

ใช้ Spatialite

ดาวน์โหลด GUI คุณสามารถเปิดทั้ง Shapefile และ CSV เป็นตารางเสมือนได้ ซึ่งหมายความว่าคุณไม่ได้นำเข้าลงในฐานข้อมูล แต่จะปรากฏเป็นตารางและคุณสามารถเข้าร่วมและค้นหาได้อย่างรวดเร็วตามที่คุณต้องการ


3

คุณสามารถทำได้อย่างรวดเร็วโดยใช้ OGR ใน C / C ++ / Python (Python ควรช้าที่สุดใน 3) วนรอบรูปหลายเหลี่ยมทั้งหมดและตั้งค่าตัวกรองบนจุดวนรอบจุดที่กรองแล้วคุณจะรู้ว่าแต่ละจุดที่คุณวนซ้ำจะเป็นของรูปหลายเหลี่ยมปัจจุบัน นี่คือตัวอย่างโค้ดในไพ ธ อนโดยใช้ OGR ซึ่งจะวนซ้ำผ่านรูปหลายเหลี่ยมและจุดกรองตามลำดับ รหัส C / C ++ จะมีลักษณะคล้ายกับนี้และฉันคิดว่าคุณจะได้รับความเร็วที่เพิ่มขึ้นอย่างมากเมื่อเทียบกับงูใหญ่ คุณจะต้องเพิ่มโค้ดสองสามบรรทัดเพื่ออัปเดต CSV ตามที่คุณต้องการ:

from osgeo import ogr
from osgeo.gdalconst import *

inPolyDS = ogr.Open("winnipeg.shp", GA_ReadOnly)
inPolyLayer = inPolyDS.GetLayer(0)
inPointDS = ogr.Open("busstops.vrt", GA_ReadOnly)   
inPointLayer = inPointDS.GetLayerByName("busstops")

inPolyFeat = inPolyLayer.GetNextFeature()
while inPolyFeat is not None:
  inPtFeat = inPointLayer.GetNextFeature()
  while inPtFeat is not None:
    ptGeom = inPtFeat.GetGeometryRef()
    # Do work here...

    inPtFeat = inPointLayer.GetNextFeature()

  inPolyFeat = inPolyLayer.GetNextFeature()

ไฟล์ VRT (busstops.vrt):

<OGRVRTDataSource>
  <OGRVRTLayer name="busstops">
    <SrcDataSource>busstops.csv</SrcDataSource>
    <GeometryType>wkbPoint</GeometryType>
    <LayerSRS>WGS84</LayerSRS>
    <GeometryField encoding="PointFromColumns" x="X" y="Y" reportSrcColumn="FALSE" />
  </OGRVRTLayer>
</OGRVRTDataSource>

ไฟล์ CSV (busstops.csv):

FID,X,Y,stop_name
1,-97.1394781371062,49.8712241633646,Southbound Osborne at Mulvey

ไฟล์ CSVT (busstops.csvt, OGR ต้องการระบุประเภทคอลัมน์มิฉะนั้นจะไม่ทำการกรองเชิงพื้นที่):

Integer,Real,Real,String

2
นั่นไม่วนซ้ำ 1 พันล้านคะแนน 5,000 ครั้ง (หนึ่งครั้งสำหรับแต่ละรูปหลายเหลี่ยม)?
underdark

ดัชนีเชิงพื้นที่เป็นที่แน่นอนต้อง ฉันพูดถึงRtreeมาก่อนและฉันจะพูดถึงอีกครั้ง!
Mike T

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