2016-07-13 7 views
6

Ich hoffe, dass meine Frage nicht lächerlich ist, da diese Frage (nach meinem besten Wissen) auf den populären Webseiten überraschenderweise noch nicht wirklich gestellt wurde.GeoDataFrame in SQL-Datenbank schreiben

Die Situation ist, dass ich mehrere CSV-Dateien mit insgesamt mehr als 1 Mio Beobachtungen habe. Jede Beobachtung enthält unter anderem eine Postanschrift. Ich plane, alle Dateien in einem einzigen GeoDataFrame zu lesen, die Adressen zu geocodieren, einen räumlichen Join bei einem Shapefile durchzuführen und einige Informationen aus dem Polygon für jede Zeile zu speichern. Ganz normal, nehme ich an. Dies ist ein Teil eines einmaligen Datenreinigungsprozesses.

Mein Ziel ist es, eine Datenbank mit diesem endgültigen Datensatz einzurichten. Dies ist, weil es mir erlaubt, die Daten ziemlich leicht zu teilen und zu durchsuchen, sowie z.B. Zeichnen Sie einige Beobachtungen auf einer Website. Es ist auch sehr einfach, Beobachtungen anhand einiger Kriterien auszuwählen und dann einige Analysen durchzuführen.

Mein Problem ist, dass die Funktion des Einfügens eines GeoDataFrame in eine Datenbank noch nicht implementiert zu sein scheint - offenbar weil GeoPandas ein Ersatz für Datenbanken sein soll ("GeoPandas ermöglicht Ihnen einfach Operationen in Python zu machen, die sonst benötigt würden eine räumliche Datenbank wie PostGIS ").

Natürlich könnte ich jede Zeile durchlaufen und jeden Datenpunkt "manuell" einfügen, aber ich suche hier nach der besten Lösung. Bei jeder Problemumgehung hätte ich auch Angst, dass der Datentyp mit dem der Datenbank in Konflikt geraten könnte. Gibt es "einen besten Weg", hier zu nehmen?

Danke für Ihre Hilfe.

Antwort

2

Also, ich habe dies nur für eine PostGIS-Datenbank implementiert, und ich kann meine Methode hier einfügen. Für MySQL müssen Sie den Code anpassen.

Der erste Schritt bestand darin, die geocodierten Spalten in WKB Hexadezimalstring zu konvertieren, weil ich SQLAlchemy benutze, mit einer Engine basierend auf pyscopg, und beide Pakete verstehen geo-Typen nativ nicht. Der nächste Schritt besteht darin, diese Daten wie üblich in eine SQL-Datenbank zu schreiben (beachten Sie, dass alle Geometrie-Spalten in Textspalten mit der WKB-Hex-Zeichenfolge konvertiert werden sollen) und schließlich den Typ der Spalten in Geometry durch Ausführen einer Abfrage zu ändern. Siehe folgenden Pseudo-Code:

# Imports 
import sqlalchemy as sal 
import geopandas as gpd 

# Function to generate WKB hex 
def wkb_hexer(line): 
    return line.wkb_hex 

# Convert `'geom'` column in GeoDataFrame `gdf` to hex 
    # Note that following this step, the GeoDataFrame is just a regular DataFrame 
    # because it does not have a geometry column anymore. Also note that 
    # it is assumed the `'geom'` column is correctly datatyped. 
gdf['geom'] = gdf['geom'].apply(wkb_hexer) 

# Create SQL connection engine 
engine = sal.create_engine('postgresql://username:[email protected]:socket/database') 

# Connect to database using a context manager 
with engine.connect() as conn, conn.begin(): 
    # Note use of regular Pandas `to_sql()` method. 
    gdf.to_sql(table_name, con=conn, schema=schema_name, 
       if_exists='append', index=False) 
    # Convert the `'geom'` column back to Geometry datatype, from text 
    sql = """ALTER TABLE schema_name.table_name 
       ALTER COLUMN geom TYPE Geometry(LINESTRING, <SRID>) 
       USING ST_SetSRID(geom::Geometry, <SRID>)""" 
    conn.execute(sql) 
+0

Cool! Dies funktioniert beim ersten Aufruf, wenn die Tabelle nicht existiert. Aber aufeinanderfolgende Aufrufe geben mir eine 'DataError: (psycopg2.DataError) Geometrie SRID (0) stimmt nicht überein Spalte SRID (4326)'. – j08lue

+0

'psycopg-postgis' könnte etwas Inspiration haben: https://github.com/yohanboniface/psycopg-postgis. Sie implementieren jedoch ihre eigenen Typen und nicht die in "formschönen"/"Geopandas". – j08lue

+0

Dieses ** kann ** für einen einzelnen Aufruf, nicht für das Anhängen von Daten funktionieren, da die Spalte "geom" dann erwartet, dass die Geometrie über eine SRID verfügt. – j08lue

5

Wie bereits erwähnt, @ Kartik Antwort nur für einen einzigen Aufruf arbeitet, um Daten anhängen ein DataError seit der geom Spalte hebt erwartet dann die Geometrie eine SRID haben. Sie können GeoAlchemy verwenden, um alle Fälle zu behandeln:

# Imports 
from geoalchemy2 import Geometry, WKTElement 
from sqlalchemy import * 

# Use GeoAlchemy's WKTElement to create a geom with SRID 
def create_wkt_element(geom): 
    return WKTElement(geom.wkt, srid = <your_SRID>) 

geodataframe['geom'] = geodataframe['geom'].apply(create_wkt_element) 

db_url = create_engine('postgresql://username:[email protected]:socket/database') 
engine = create_engine(db_url, echo=False) 

# Use 'dtype' to specify column's type 
# For the geom column, we will use GeoAlchemy's type 'Geometry' 
your_geodataframe.to_sql(table_name, engine, if_exists='append', index=False, 
         dtype={geom: Geometry('POINT', srid= <your_srid>)})