Cara tercepat untuk secara spasial bergabung dengan CSV titik dengan Shapefile poligon

19

Saya memiliki file CSV 1 miliar poin dan sebuah shapefile dengan sekitar 5.000 poligon. Apa cara tercepat untuk menggabungkan titik dan poligon secara spasial? Untuk setiap poin, saya perlu mendapatkan id poligon yang mengandung. (Poligon tidak tumpang tindih.)

Biasanya, saya memuat kedua set data ke PostGIS. Apakah ada cara yang lebih cepat untuk menyelesaikan pekerjaan?

Saya mencari solusi open-source.

underdark
sumber

Jawaban:

16

Jika "tercepat" termasuk jumlah waktu Anda yang dihabiskan, solusinya akan tergantung pada perangkat lunak apa yang Anda sukai dan dapat digunakan dengan cepat. Pernyataan berikut secara konsekuen fokus pada ide-ide untuk mencapai waktu komputasi tercepat yang mungkin .

Jika Anda menggunakan program kalengan, hampir pasti yang terbaik yang dapat Anda lakukan adalah pra-proses poligon untuk mengatur struktur data point-in-poligon, seperti pohon KD atau quadtree, yang kinerjanya biasanya O (log (V) ) * (N + V)) di mana V adalah jumlah total simpul dalam poligon dan N adalah jumlah titik, karena struktur data akan mengambil setidaknya O (log (V) * V) upaya untuk membuat dan kemudian akan harus diperiksa untuk setiap titik dengan biaya per-titik O (log (V)).

Anda dapat melakukan jauh lebih baik dengan terlebih dahulu memasang grid pada poligon, mengeksploitasi asumsi tidak ada tumpang tindih. Setiap sel grid seluruhnya dalam interior poligon (termasuk interior "poligon universal"), dalam hal ini label sel dengan id poligon, atau mengandung satu atau lebih ujung poligon. Biaya rasterisasi ini, sama dengan jumlah sel kisi yang dirujuk saat meraster semua tepi, adalah O (V / c) di mana c adalah ukuran sel, tetapi konstanta tersirat dalam notasi O besar kecil.

(Satu keindahan dari pendekatan ini adalah bahwa Anda dapat mengeksploitasi rutin grafis standar. Misalnya, jika Anda memiliki sistem yang (a) akan menggambar poligon pada layar virtual menggunakan (b) warna yang berbeda untuk setiap poligon dan (c) memungkinkan Anda membaca warna piksel yang ingin Anda tangani, Anda membuatnya.)

Dengan kisi-kisi ini di tempat, pra-layar poin dengan menghitung sel yang mengandung setiap titik (operasi O (1) yang hanya membutuhkan beberapa jam). Kecuali jika titik-titik dikelompokkan di sekitar batas-batas poligon, ini biasanya hanya menyisakan sekitar O (c) poin dengan hasil yang ambigu. Karenanya, total biaya untuk membangun grid dan pra-penyaringan adalah O (V / c + 1 / c ^ 2) + O (N). Anda harus menggunakan beberapa metode lain (seperti yang direkomendasikan sejauh ini) untuk memproses poin yang tersisa (yaitu yang dekat dengan batas poligon), dengan biaya O (log (V) * N * c) .

Ketika c semakin kecil, semakin sedikit poin yang akan berada dalam sel grid yang sama dengan edge dan oleh karena itu semakin sedikit akan membutuhkan pemrosesan O (log (V)) berikutnya. Bertindak melawan ini adalah kebutuhan untuk menyimpan O (1 / c ^ 2) sel kisi dan untuk menghabiskan O (V / c + 1 / c ^ 2) waktu rasterisasi poligon. Oleh karena itu akan ada ukuran grid yang optimal c. Dengan menggunakannya, total biaya komputasi adalah O (log (V) * N) tetapi konstanta implisit biasanya jauh lebih kecil daripada menggunakan prosedur kalengan, karena kecepatan O (N) dari pra-penyaringan.

20 tahun yang lalu saya menguji pendekatan ini (menggunakan titik-titik yang berjarak seragam di seluruh Inggris dan lepas pantai dan mengeksploitasi jaringan yang relatif kasar sekitar 400 ribu sel yang ditawarkan oleh penyangga video saat itu) dan memperoleh dua pesanan percepatan magnitudo dibandingkan dengan algoritma terbaik yang diterbitkan yang saya bisa Temukan. Bahkan ketika poligon kecil dan sederhana (seperti segitiga), Anda benar-benar yakin akan urutan peningkatan kecepatan.

Dalam pengalaman saya, perhitungannya sangat cepat sehingga seluruh operasi dibatasi oleh kecepatan data I / O, bukan oleh CPU. Mengantisipasi bahwa I / O mungkin menjadi penghambat, Anda akan mencapai hasil yang paling cepat dengan menyimpan poin dalam format terkompresi mungkin untuk meminimalkan waktu membaca data. Juga pertimbangkan bagaimana hasil harus disimpan, sehingga Anda dapat membatasi penulisan disk.

whuber
sumber
6
Poin yang sangat baik tentang waktu yang dihabiskan untuk menyadari solusi vs waktu komputasi. Butuh waktu lama untuk mencapai solusi optimal hanya menguntungkan jika Anda menyadari penghematan tersebut melalui optimalisasi (terutama dari sudut pandang pemberi kerja).
Sasa Ivetic
5

Untuk bagian saya, saya mungkin akan memuat data CSV ke file shp dan kemudian menulis skrip python menggunakan shapefile dan rupawan untuk mendapatkan id yang mengandung poligon dan memperbarui nilai bidang.

Saya tidak tahu apakah geotool dan JTS lebih cepat daripada shapefile / rupawan ... Tidak punya waktu untuk mengujinya!

sunting : Omong-omong, konversi csv ke format shapefile mungkin tidak diperlukan, karena nilai dapat dengan mudah diformat untuk diuji dengan objek spasial dari poligon bentuk Anda.

simo
sumber
4
Saya akan langsung memuat data menggunakan pembaca csv dan mengisi indeks spasial Rtree . Kombinasi Rtree dan Shapely memiliki kinerja yang mengesankan (jauh lebih baik daripada PostGIS; saya tidak dapat dibandingkan dengan JTS karena saya tidak tahu Java).
Mike T
2
Ide bagus asalkan Anda tidak perlu menyimpan semua 1b poin dalam memori sekaligus. Minimal 16 byte per titik (X / Y), Anda sedang melihat data senilai 16GB. Jika Rtree akan membangun indeks pada penyimpanan lokal, maka itu pasti akan meningkatkan kinerja. Mengimpor 1b poin ke satu bentuk file tidak akan berfungsi. Bentuk negara spesifikasi OGR terbatas hingga 8GB (disarankan 4GB). Bentuk titik tunggal menggunakan 20 byte.
Sasa Ivetic
4

Saya akhirnya mengubah poligon menjadi raster dan mengambil sampelnya pada posisi titik. Karena poligon saya tidak tumpang tindih dan akurasi yang tinggi tidak diperlukan (poligon mewakili kelas penggunaan lahan dan perbatasan mereka dianggap agak tidak pasti) ini adalah solusi paling efisien waktu yang bisa saya buat.

underdark
sumber
3

Saya akan segera menulis sebuah program java kecil didasarkan pada pembaca shapefile dari GeoTools dan operasi mengandung dari JTS . Saya tidak tahu seberapa cepat ...

Julien
sumber
1
Jika Anda memiliki data dalam PostGIS kemudian GeoTools dapat menggunakan inti indeks dll
Ian Turton
3

Gunakan Spatialite .

Unduh GUI. Anda dapat membuka tabel Shapefile dan CSV sebagai tabel virtual. Ini berarti bahwa Anda tidak benar-benar mengimpornya ke dalam database tetapi mereka muncul sebagai tabel dan Anda dapat dengan cepat bergabung dan meminta mereka dengan cara apa pun yang Anda suka.

Sean
sumber
3

Anda dapat melakukannya dengan cukup cepat menggunakan OGR di C / C ++ / Python (Python harus menjadi yang paling lambat dari 3). Ulangi semua poligon dan atur filter pada titik-titik, loop melalui titik-titik yang disaring dan Anda akan tahu bahwa setiap titik yang Anda lewati akan menjadi milik poligon saat ini. Berikut ini contoh kode dalam python menggunakan OGR yang akan diulang melalui poligon dan memfilter poin sesuai. C / C ++ kode akan terlihat sangat mirip dengan ini, dan saya akan membayangkan Anda akan mendapatkan peningkatan kecepatan yang signifikan vs python. Anda harus menambahkan beberapa baris kode untuk memperbarui CSV saat melanjutkan:

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

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

File CSV (busstops.csv):

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

File CSVT (busstops.csvt, OGR memerlukannya untuk mengidentifikasi jenis kolom, jika tidak, ia tidak akan melakukan filter spasial):

Integer,Real,Real,String
Sasa Ivetic
sumber
2
Bukankah itu mengulangi 1 miliar poin 5000 kali (satu kali untuk setiap poligon)?
underdark
Indeks spasial adalah keharusan mutlak . Saya menyebutkan Rtree sebelumnya, dan saya akan menyebutkannya lagi!
Mike T