将 GeoDataFrame 写入 SQL 数据库

Write GeoDataFrame into SQL Database

我希望我的问题不是荒谬的,因为令人惊讶的是,这个问题显然还没有真正被问过(据我所知)在流行的网站上。

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

我的目标是用这个最终数据集建立一个数据库。这是因为它允许我很容易地共享和搜索数据,例如。在网站上绘制一些观察结果。此外,它使得根据某些标准 select 观察然后 运行 一些分析变得非常容易。

我的问题是,将 GeoDataFrame 插入数据库的功能似乎尚未实现 - 显然是因为 GeoPandas 应该是数据库的替代品 ("GeoPandas enables you to easily do operations in python that would otherwise require a spatial database such as PostGIS")。

当然,我可以遍历每一行并插入每个数据点 "manually",但我正在寻找最佳解决方案。对于任何解决方法,我也担心数据类型可能与数据库的数据类型冲突。这里有"a best way"可以带吗?

感谢您的帮助。

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

第一步是将经过地理编码的列转换为 WKB 十六进制字符串,因为我使用 SQLAlchemy, with an engine based on pyscopg,而这两个包本身并不理解地理类型。下一步是像往常一样将该数据写入 SQL 数据库(请注意,所有几何列都应转换为包含 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: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)

如前所述,@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 = '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>)})

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

我回到这里是为了给出更好的答案。一个 geopandas.GeoDataFrame 对象有一个 .to_postgis() 方法来处理处理几何类型的许多麻烦事。