Usi OGR e Shapely in modo più efficiente? [chiuso]


29

Sto cercando alcuni suggerimenti su come rendere il mio codice Python più efficiente. Normalmente l'efficienza non ha importanza per me, ma ora sto lavorando con un file di testo di sedi negli Stati Uniti con oltre 1,5 milioni di punti. Con la configurazione indicata sono necessari circa 5 secondi per eseguire le operazioni su un punto; Devo scendere questa cifra.

Sto usando tre diversi pacchetti GIS Python per fare alcune diverse operazioni sui punti e generare un nuovo file di testo delimitato.

  1. Uso OGR per leggere uno shapefile del confine della contea e ottenere l'accesso alla geometria del confine.
  2. Controlla formalmente per vedere se un punto è all'interno di una di queste contee.
  3. Se è all'interno di uno, uso la libreria Python Shapefile per estrarre le informazioni sugli attributi dal confine .dbf.
  4. Quindi scrivo alcune informazioni da entrambe le fonti in un file di testo.

Ho il sospetto che l'inefficienza risieda nell'avere un ciclo a 2-3 livelli ... non sono sicuro di cosa fare al riguardo. In particolare, cerco aiuto con qualcuno con esperienza nell'uso di uno di questi 3 pacchetti, poiché è la prima volta che utilizzo uno di essi.

import os, csv
from shapely.geometry import Point
from shapely.geometry import Polygon
from shapely.wkb import loads
from osgeo import ogr
import shapefile

pointFile = "C:\\NSF_Stuff\\NLTK_Scripts\\Gazetteer_New\\NationalFile_20110404.txt"
shapeFolder = "C:\NSF_Stuff\NLTK_Scripts\Gazetteer_New"
#historicBounds = "C:\\NSF_Stuff\\NLTK_Scripts\\Gazetteer_New\\US_Counties_1860s_NAD"
historicBounds = "US_Counties_1860s_NAD"
writeFile = "C:\\NSF_Stuff\\NLTK_Scripts\\Gazetteer_New\\NewNational_Gazet.txt"

#opens the point file, reads it as a delimited file, skips the first line
openPoints = open(pointFile, "r")
reader = csv.reader(openPoints, delimiter="|")
reader.next()

#opens the write file
openWriteFile = open(writeFile, "w")

#uses Python Shapefile Library to read attributes from .dbf
sf = shapefile.Reader("C:\\NSF_Stuff\\NLTK_Scripts\\Gazetteer_New\\US_Counties_1860s_NAD.dbf")
records = sf.records()
print "Starting loop..."

#This will loop through the points in pointFile    
for row in reader:
    print row
    shpIndex = 0
    pointX = row[10]
    pointY = row[9]
    thePoint = Point(float(pointX), float(pointY))
    #This section uses OGR to read the geometry of the shapefile
    openShape = ogr.Open((str(historicBounds) + ".shp"))
    layers = openShape.GetLayerByName(historicBounds)
    #This section loops through the geometries, determines if the point is in a polygon
    for element in layers:
        geom = loads(element.GetGeometryRef().ExportToWkb())
        if geom.geom_type == "Polygon":
            if thePoint.within(geom) == True:
                print "!!!!!!!!!!!!! Found a Point Within Historic !!!!!!!!!!!!"
                print str(row[1]) + ", " + str(row[2]) + ", " + str(row[5]) + " County, " + str(row[3])
                print records[shpIndex]
                openWriteFile.write((str(row[0]) + "|" + str(row[1]) + "|" + str(row[2]) + "|" + str(row[5]) + "|" + str(row[3]) + "|" + str(row[9]) + "|" + str(row[10]) + "|" + str(records[shpIndex][3]) + "|" + str(records[shpIndex][9]) + "|\n"))
        if geom.geom_type == "MultiPolygon":
            for pol in geom:
                if thePoint.within(pol) == True:
                    print "!!!!!!!!!!!!!!!!! Found a Point Within MultiPolygon !!!!!!!!!!!!!!"
                    print str(row[1]) + ", " + str(row[2]) + ", " + str(row[5]) + " County, " + str(row[3])
                    print records[shpIndex]
                    openWriteFile.write((str(row[0]) + "|" + str(row[1]) + "|" + str(row[2]) + "|" + str(row[5]) + "|" + str(row[3]) + "|" + str(row[9]) + "|" + str(row[10]) + "|" + str(records[shpIndex][3]) + "|" + str(records[shpIndex][9]) + "|\n"))
        shpIndex = shpIndex + 1
    print "finished checking point"
    openShape = None
    layers = None


pointFile.close()
writeFile.close()
print "Done"

3
Potresti considerare di pubblicare questa recensione @ Code: codereview.stackexchange.com
RyanDalton,

Risposte:


21

Il primo passo sarebbe spostare lo shapefile aperto al di fuori del loop delle righe, aprendo e chiudendo lo shapefile 1,5 milioni di volte.

Ad essere sincero, inserirei il tutto in PostGIS e lo farei usando SQL su tabelle indicizzate.


19

Una rapida occhiata al tuo codice fa venire in mente alcune ottimizzazioni:

  • Prima controlla ogni punto contro il rettangolo di selezione / inviluppo dei poligoni, per eliminare ovvi valori anomali. Potresti fare un passo ulteriore e contare il numero di bbox in cui si trova un punto, se è esattamente uno, quindi non è necessario testarlo con la geometria più complessa (beh, lo sarà effettivamente se si trova in più di uno, dovrà essere testato ulteriormente. Potresti fare due passaggi per eliminare i casi semplici dai casi complessi).

  • Invece di eseguire il ciclo attraverso ogni punto e testarlo contro i poligoni, passare attraverso i poligoni e testare ogni punto. Il caricamento / conversione della geometria è lento, quindi vuoi farlo il meno possibile. Inoltre, crea inizialmente un elenco di punti dal CSV, ancora una volta per evitare di doverlo fare più volte per punto, quindi scartando i risultati alla fine di quella iterazione.

  • Indicizza in modo spaziale i tuoi punti, il che implica la conversione in uno shapefile, in un file SpatialLite o in qualcosa come un database PostGIS / PostgreSQL . Questo ha il vantaggio che strumenti come OGR saranno in grado di fare la maggior parte del lavoro per te.

  • Non scrivere l'output fino alla fine: print () è una funzione costosa nel migliore dei casi. Conservare invece i dati come un elenco e scriverli alla fine utilizzando le funzioni di decapaggio standard di Python o le funzioni di dumping dell'elenco.


5
I primi due pagheranno alla grande. Puoi anche velocizzare un po 'le cose usando ogr per tutto invece di Shapely e Shapefile.
sgillies,

2
Per tutto ciò che riguarda "Python" e "indice spaziale", non guardare oltre Rtree in quanto è molto veloce nel trovare forme vicino ad altre forme
Mike T,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.