Çokgen Shapefile ile bir nokta CSV'sine mekansal olarak katılmanın en hızlı yolu


19

1 milyar puanlık CSV dosyam ve yaklaşık 5.000 çokgen içeren bir şekil dosyam var. Noktalara ve çokgenlere mekansal olarak katılmanın en hızlı yolu nedir? Her nokta için, içeren çokgen kimliği almak gerekiyor. (Çokgenler çakışmaz.)

Genellikle, her iki veri setini de PostGIS'e yüklerdim. İşi yapmanın daha hızlı bir yolu var mı?

Açık kaynaklı bir çözüm arıyorum.

Yanıtlar:


16

"En hızlı" miktarını içeriyorsa da harcanan zaman, çözüm için uygun olan hangi yazılım bağlıdır ve süratle kullanabilirsiniz. Aşağıdaki açıklamalar sonuç olarak mümkün olan en hızlı bilgi işlem sürelerine ulaşmak için fikirlere odaklanmaktadır .

Hazır bir program kullanırsanız, neredeyse kesinlikle yapabileceğiniz en iyi şey, performansı tipik olarak O (log (V (log (V)) olacak bir KD ağacı veya dörtlü gibi bir çokgen noktası veri yapısı oluşturmak için çokgenleri önceden işlemektir. ) * (N + V)) burada V, çokgenlerdeki toplam köşe sayısıdır ve N nokta sayısıdır, çünkü veri yapısı oluşturmak için en az O (log (V) * V) çaba alacak ve sonra her nokta için bir nokta başına maliyet O (log (V)) ile problanmalıdır.

İlk olarak çokgenleri ızgaralayarak, çakışma olmaması varsayımından yararlanarak önemli ölçüde daha iyi yapabilirsiniz. Her ızgara hücresi tamamen bir poligonun iç kısmındadır ("evrensel çokgenin" iç kısmı dahil), bu durumda hücreyi çokgenin kimliğiyle etiketleyin veya başka bir veya daha fazla çokgen kenarı içerir. Bu rasterleştirmenin maliyeti, tüm kenarları rasterleştirilirken atıfta bulunulan ızgara hücresi sayısına eşittir, buradaki c, bir hücrenin büyüklüğüdür, ancak big-O notasyonundaki örtük sabit küçüktür.

(Bu yaklaşımın bir güzelliği, standart grafik rutinlerinden yararlanabilmenizdir. Örneğin, (a) çokgenleri sanal bir ekrana (b) her bir çokgen için farklı bir renk kullanarak çizecek ve (c) hitap etmeyi düşündüğünüz herhangi bir pikselin rengini okursanız, hazırladınız.

Bu ızgara yerinde olduğunda, her bir noktayı (yalnızca birkaç saat gerektiren bir O (1) işlemi) içeren hücreyi hesaplayarak noktaları önceden tarayın. Noktalar çokgen sınırlarının etrafında kümelenmedikçe, bu genellikle belirsiz sonuçlarla sadece yaklaşık O (c) noktaları bırakacaktır. Şebeke inşa etme ve ön elemenin toplam maliyeti O (V / c + 1 / c ^ 2) + O (N) 'dir. Kalan noktaları (yani, çokgen sınırlarına yakın olanları) işlemek için O (log (V) * N * c) maliyetiyle başka bir yöntem (şimdiye kadar önerilenlerden herhangi biri gibi) kullanmanız gerekir. .

C küçüldükçe, daha az ve daha az nokta bir kenar ile aynı ızgara hücresinde olacaktır ve bu nedenle daha az ve daha az sonraki O (log (V)) işlemeyi gerektirecektir. Buna karşı hareket etmek, O (1 / c ^ 2) ızgara hücrelerini saklamak ve O (V / c + 1 / c ^ 2) zamanlarını çokgenleri rasterleştirmek için harcamaktır. Bu nedenle en uygun ızgara boyutu c olacaktır. Bunu kullanarak, toplam hesaplama maliyeti O (log (V) * K) 'dir, ancak kapalı sabit tipik bir şekilde bağlı ön-eleme O (K) hızı için, konserve prosedürler kullanılarak daha küçük.

20 yıl önce bu yaklaşımı test ettim (İngiltere ve açık denizde eşit aralıklı noktalar kullanarak ve zamanın video tamponları tarafından sunulan yaklaşık 400K hücreden oluşan nispeten ham bir ızgaradan yararlanarak) ve en iyi yayınlanan algoritmaya kıyasla iki büyüklükte hız artışı elde ettim. bulabilirsiniz. Çokgenler küçük ve basit olsa bile (üçgenler gibi), büyüklükte bir hızlanma emrinden neredeyse emin olabilirsiniz.

Deneyimlerime göre, hesaplama o kadar hızlıydı ki, tüm işlem CPU tarafından değil, veri I / O hızlarıyla sınırlıydı. G / Ç'nin bir darboğaz olacağını tahmin ederek, veri okuma sürelerini en aza indirmek için noktaları mümkün olduğunca sıkıştırılmış bir formatta depolayarak en hızlı sonuçları elde edersiniz. Ayrıca, disk yazmalarını sınırlayabilmeniz için sonuçların nasıl saklanması gerektiği konusunda biraz düşünün.


6
Hesaplama zamanına karşı çözümü gerçekleştirmek için çok iyi zaman harcanmıştır. Optimal bir çözüme ulaşmak için uzun zaman ayırmak, ancak bu tasarrufları optimizasyon yoluyla gerçekleştirdiğinizde (özellikle işveren açısından) faydalıdır.
Sasa Ivetic

5

Benim açımdan, muhtemelen bir shp dosyasına CSV verilerini yükler ve daha sonra içeren çokgen kimliğini almak ve alan değerini güncellemek için şekil dosyası ve düzgün bir şekilde bir python komut dosyası yazardım .

Geotools ve JTS'nin şekil dosyasından / düzgün bir şekilde daha hızlı olup olmadığını bilmiyorum ... Test etmek için zamanınız yok!

edit : Bu arada, değerler çokgen şekil dosyasından uzamsal nesnelerle test edilecek şekilde kolayca biçimlendirilebildiğinden şekil dosyası formatına csv dönüşümü muhtemelen gerekli değildir.


4
Doğrudan bir csv okuyucu kullanarak veri yüklemek ve bir Rtree uzamsal dizin doldurmak . Rtree ve Shapely kombinasyonu etkileyici bir performansa sahip (PostGIS'ten çok daha iyi; Java bilmediğim için JTS ile kıyaslayamıyorum).
Mike T

2
İyi bir fikir, tüm 1b noktalarını bir kerede bellekte saklamanıza gerek yoktur. Nokta başına en az 16 bayt (X / Y), 16 GB değerinde verilere bakıyorsunuz. Rtree, dizini yerel depolama üzerine kuracaksa, performansı kesinlikle artıracaktır. Tek bir şekil dosyasına 1b puan almak da çalışmaz. OGR spesifikasyonları durum şekil dosyaları 8 GB ile sınırlıdır (4 GB önerilir). Tek noktalı şekil 20 bayt kullanır.
Sasa Ivetic

4

Çokgenleri bir raster haline dönüştürdüm ve nokta konumlarında örnekledim. Çokgenlerim üst üste gelmediği ve yüksek doğruluk gerekli olmadığı için (çokgenler arazi kullanım sınıflarını temsil etti ve sınırları yine de oldukça belirsiz olarak kabul edildi) bu, karşılaşabileceğim en zaman etkili çözümdü.



3

Spatialit kullanın .

GUI'yi indirin. Shapefile ve CSV'yi sanal tablolar olarak açabilirsiniz. Bu, aslında veritabanına almadığınız anlamına gelir, ancak tablo olarak görünür ve istediğiniz şekilde birleştirebilir ve sorgulayabilirsiniz.


3

C / C ++ / Python'da OGR kullanarak oldukça hızlı bir şekilde yapabilirsiniz (Python 3'ün en yavaşı olmalıdır). Tüm çokgenler arasında geçiş yapın ve noktalara bir filtre koyun, filtrelenmiş noktaların üzerinden geçin ve geçtiğiniz noktaların her birinin geçerli çokgene ait olacağını bileceksiniz. İşte çokgenler ve filtre noktaları buna göre döngü OGR kullanarak python örnek kodu. C / C ++ kodu buna oldukça benzeyecek ve python'a karşı önemli bir hız artışı alacağınızı hayal ediyorum. Devam ederken CSV'yi güncellemek için birkaç kod satırı eklemeniz gerekir:

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 Dosyası (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 Dosyası (busstops.csv):

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

CSVT Dosyası (busstops.csvt, OGR, sütun türlerini tanımlamak için buna ihtiyaç duyar, aksi takdirde uzamsal filtreyi gerçekleştirmez):

Integer,Real,Real,String

2
Bu, 1 milyar noktadan 5000 kez geçmiyor mu (her çokgen için bir kez)?
underdark

Bir uzamsal indeks mutlak bir zorunluluktur . Daha önce Rtree'den bahsettim ve tekrar anlatacağım!
Mike T

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.