将GeoDataFrame写入SQL数据库

时间:2016-07-13 20:42:51

标签: python mysql pandas geopandas

我希望我的问题不是荒谬的,因为令人惊讶的是,这个问题在热门网站上显然还没有被提及(据我所知)。

情况是我有几个csv文件,总共包含超过1个Mio观测值。每个观察都包含一个邮政地址。我计划将所有文件读入单个GeoDataFrame,对地址进行地理编码,在给定shapefile的情况下执行空间连接,并为每行保存多边形中的一些信息。我想这是相当标准的。这是一次性数据清理过程的一部分。

我的目标是使用此最终数据集设置数据库。这是因为它允许我很容易地共享和搜索数据,例如在网站上绘制一些观察结果。此外,它可以很容易地根据某些标准选择观察结果,然后进行一些分析。

我的问题是将GeoDataFrame插入数据库的功能似乎还没有实现 - 显然是因为GeoPandas应该是数据库的替代品(" GeoPandas使您能够轻松地在python中执行操作否则需要一个空间数据库,如PostGIS")。

当然,我可以遍历每一行并插入每个数据点"手动",但我在这里寻找最佳解决方案。对于任何解决方法,我也担心数据类型可能与数据库的数据类型冲突。是否有最好的方式"带到这儿?

感谢您的帮助。

4 个答案:

答案 0 :(得分:8)

如前所述,@ Kartik的答案仅适用于单个调用,因为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:password@host: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>)})

答案 1 :(得分:4)

所以,我刚刚为PostGIS数据库实现了这个,我可以在这里粘贴我的方法。对于MySQL,您必须调整代码。

第一步是将地理编码列转换为WKB十六进制字符串,因为我使用SQLAlchemy,基于pyscopg的引擎,并且这两个包本身都不理解地理类型。下一步是像往常一样将该数据写入SQL DB(请注意,所有几何列都应转换为包含WKB十六进制字符串的文本列),最后通过执行查询将列的类型更改为Geometry。请参阅以下伪代码:

# 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:password@host: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)

答案 2 :(得分:1)

Hamri Said答案的一个版本,但是使用了lambda,我认为它更好一点,因为它的功能很短:

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

geodataframe['geom'] = geodataframe['geom'].apply(lambda geom: WKTElement(geom.wkt, srid = <your_SRID>))

db_url = 'postgresql://username:password@host: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>)})

答案 3 :(得分:0)

我会回到这个来给出一个更好的答案。 geopandas.GeoDataFrame 对象有一个 .to_postgis() 方法,可以处理很多处理几何​​类型的麻烦事。