#python #pandas #geopandas
Вопрос:
У меня есть требование прочитать ок. 10 миллионов записей из базы данных PostGIS в фрейм данных GeoPandas. Чтение данных непосредственно из базы данных занимает ок. 15 минут с помощью следующих:
geopandas.GeoDataFrame.from_postgis(sql, engine)
Это приемлемо, но я пытался улучшить производительность чтения, используя команду копирования PostgreSQL вместе с функцией SQLAlchemy copy_export. Чтение данных с помощью этого метода в фрейм данных Pandas занимает около 60 секунд, что является огромным улучшением:
def read_data(engine, sql):
with tempfile.TemporaryFile() as tmpFile:
copy_sql = "COPY ({query}) TO STDOUT WITH CSV {head}".format(
query=sql, head='HEADER'
)
con = engine.raw_connection()
cur = con.cursor()
cur.copy_expert(copy_sql, tmpFile)
tmpFile.seek(0)
df = pandas.read_csv(tmpFile)
return df
При попытке сделать то же самое, но считывании данных в фрейм данных GeoPandas, я сталкиваюсь с проблемами, связанными с временным файлом, используемым другим процессом:
def read_data(engine, sql):
with tempfile.NamedTemporaryFile(suffix='.csv') as tmpFile:
copy_sql = "COPY ({query}) TO STDOUT WITH CSV {head}".format(
query=sql, head='HEADER'
)
con = engine.raw_connection()
cur = con.cursor()
cur.copy_expert(copy_sql, tmpFile)
tmpFile.seek(0)
gdf = geopandas.read_file(tmpFile.name)
return gdf
fiona.errors.DriverError: C:Temp4tmpiuu6dvl4.csv: file used by other process
Я пробовал различные способы снятия блокировки с временного файла, но безуспешно, поэтому я вернулся к чтению данных в фрейм данных Pandas, а затем преобразовал столбец геометрии. Это работает, но занимает столько же времени, сколько просто чтение данных непосредственно из базы данных в фрейм данных GeoPandas:
def read_data(engine, sql):
with tempfile.TemporaryFile() as tmpFile:
copy_sql = "COPY ({query}) TO STDOUT WITH CSV {head}".format(
query=sql, head='HEADER'
)
con = engine.raw_connection()
cur = con.cursor()
cur.copy_expert(copy_sql, tmpFile)
tmpFile.seek(0)
df = pandas.read_csv(tmpFile)
df['geom'] = geopandas.GeoSeries.from_wkt(df['geom'])
return geopandas.GeoDataFrame(df, geometry='geom', crs='EPSG:3857')
Часть, которая занимает очень много времени, — это преобразование WKT в геосерии:
df['geom'] = geopandas.GeoSeries.from_wkt(df['geom'])
Кто-нибудь знает решение для решения проблемы с заблокированными файлами или для ускорения преобразования WKT в GeoSeries?
Спасибо
Комментарии:
1. Не могли бы вы извлечь несколько строк из вашего csv-файла, пожалуйста?
Ответ №1:
ГеоПандас должен создавать геометрические объекты, вот что требует времени. Не имеет значения, используете ли вы GeoDataFrame.from_postgis
или ваш пользовательский код, потому что даже если бы вы read_data
работали, вы закончили бы представлением геометрии WKT/WKB и все равно должны были бы позвонить from_wkt
.
В настоящее время преобразование GeoPandas зависит от shapely, но у него есть экспериментальная поддержка pygeos, которая, вероятно, будет быстрее. Убедитесь, что в вашем окружении есть pygeo, и повторите GeoDataFrame.from_postgis
попытку. Этот код уже достаточно хорошо оптимизирован, поэтому я не уверен, что вы можете легко ускорить работу с помощью пользовательского кода.
Чтобы получить pygeos:
# conda
conda install pygeos --channel conda-forge
# pip
pip install pygeos
Комментарии:
1. Я знал, что GeoPandas должен создавать геометрию, полагаю, я надеялся, что, возможно, было что-то, что я мог бы сделать лучше для повышения производительности. Ранее я пытался установить pygeos, но мне было трудно сделать это в Windows. Наконец-то я смог установить и настроить pygeos, но производительность совсем не улучшилась. Похоже, что скорость, которую я сейчас набираю, — это лучшее, на что я могу надеяться, спасибо.