2016-07-13 3 views
6

Надеюсь, что мой вопрос не смешон, так как, на удивление, этот вопрос, по-видимому, пока еще не был задан (насколько мне известно) на популярных веб-сайтах.Напишите GeoDataFrame в базу данных SQL

Ситуация в том, что у меня есть несколько файлов csv, содержащих в общей сложности более 1 наблюдения Mio. Каждое наблюдение содержит, в частности, почтовый адрес. Я планирую читать все файлы в один GeoDataFrame, геокодировать адреса, выполнять пространственное соединение, задавая шейп-файл, и сохранять некоторую информацию из многоугольника для каждой строки. Довольно стандартный, я полагаю. Это часть одноразового процесса очистки данных.

Моя цель - создать базу данных с этим окончательным набором данных. Это связано с тем, что он позволяет мне легко и просто делиться и искать данные, а также, например, запечатлеть некоторые наблюдения на веб-сайте. Кроме того, довольно легко выбрать наблюдения, основанные на некоторых критериях, а затем выполнить некоторые анализы.

Проблема заключается в том, что функция вставки GeoDataFrame в базу данных, похоже, еще не реализована - по-видимому, потому, что GeoPandas должна быть базой для баз данных («GeoPandas позволяет вам легко выполнять операции на питоне, которые в противном случае требовали бы пространственная база данных, такая как PostGIS ").

Конечно, я мог проходить через каждую строку и вставлять каждую точку данных «вручную», но я ищу лучшее решение здесь. Для любого обходного пути я также опасаюсь, что тип данных может конфликтовать с типом базы данных. Есть ли «лучший способ» здесь?

Благодарим за помощь.

ответ

2

Итак, я только что реализовал это для базы данных PostGIS, и здесь я могу вставить свой метод. Для MySQL вам придется адаптировать код.

Первым шагом было преобразование геокодированных столбцов в шестнадцатеричную строку WKB, поскольку я использую SQLAlchemy с движком, основанным на pyscopg, и оба этих пакета не понимают гео-типы изначально. Следующий шаг - записать эти данные в SQL DB, как обычно (обратите внимание, что все столбцы геометрии должны быть преобразованы в текстовые столбцы, содержащие шестнадцатеричную строку WKB) и, наконец, измените тип столбцов на геометрию, выполнив запрос. Обратитесь к следующему псевдокоде:

# 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

Прохладный! Это работает при первом вызове, когда таблица не существует. Но последовательные вызовы дают мне 'DataError: (psycopg2.DataError) Geometry SRID (0) не соответствует столбцу SRID (4326)'. – j08lue

+0

'psycopg-postgis' может иметь некоторое вдохновение: https://github.com/yohanboniface/psycopg-postgis. Тем не менее, они реализуют свои собственные типы, а не в «стройном»/«геоданном». – j08lue

+0

Этот ** может ** использовать для одного вызова, а не для добавления данных, так как столбец 'geom' ожидает, что геометрия будет иметь SRID. – j08lue

5

Как упоминалось ранее, @ ответ Картик работает только для одного вызова, для добавления данных он поднимает DataError с момента geom колонки затем ожидает, геометрию, чтобы иметь SRID. Вы можете использовать GeoAlchemy для обработки всех случаев:

# 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>)})