PostGIS टेबल में जियोपांडास डेटाफ्रेम जोड़ना?


17

मेरे पास एक साधारण जियोपैन्डस डेटाफ्रेम है:

यहाँ छवि विवरण दर्ज करें

मैं इस GeoDataframe को एक PostGIS टेबल पर अपलोड करना चाहूंगा। मेरे पास पहले से ही PostGIS एक्सटेंशन के साथ एक डेटाबेस सेटअप है, लेकिन इस डेटाफ्रेम को तालिका के रूप में जोड़ने के लिए प्रतीत नहीं हो सकता है।

मैंने निम्नलिखित कोशिश की है:

engine = <>
meta = MetaData(engine)
eld_test = Table('eld_test', meta, Column('id', Integer, primary_key=True), Column('key_comb_drvr', Text), 
                 Column('geometry', Geometry('Point', srid=4326))) 
eld_test.create(engine) 
conn = engine.connect() 
conn.execute(eld_test.insert(), df.to_dict('records'))

मैंने निम्नलिखित कोशिश की है: इंजन = <> # बनाएँ तालिका मेटा = मेटाडेटा (इंजन) eld_test = तालिका ('eld_test', मेटा, कॉलम ('आईडी'), पूर्णांक, प्रायमरी_की + सही: कॉलम ('key_comb_drvr', पाठ) , कॉलम ('ज्योमेट्री', ज्योमेट्री ('पॉइंट', श्रीड = 4326))) eld_test.create (इंजन) # DBAPI की निष्कासन dicts con की सूची के साथ = engine.connect () conn.execute (eld_test.insert) (), df .to_dict ('रिकॉर्ड'))
द स्ट्रॉमैन

1
जीआईएस एसई में आपका स्वागत है, कृपया हमारे दौरे के बारे में पढ़ें ! क्या आप अपनी पोस्ट को टिप्पणियों में पोस्ट किए गए कोड को शामिल करने के लिए संपादित कर सकते हैं ?
जिओसिड

जवाबों:


33

पांडा की to_sql विधि और SQLAlchemy का उपयोग करके आप Postgres में डेटाफ़्रेम संग्रहीत कर सकते हैं। और जब से आप जियोडेटफ्रेम जमा कर रहे हैं, जियोआल्केमी आपके लिए जियोम कॉलम को संभाल लेगा। यहाँ एक कोड नमूना है:

# Imports
from geoalchemy2 import Geometry, WKTElement
from sqlalchemy import *
import pandas as pd
import geopandas as gpd

# Creating SQLAlchemy's engine to use
engine = create_engine('postgresql://username:password@host:socket/database')


geodataframe = gpd.GeoDataFrame(pd.DataFrame.from_csv('<your dataframe source>'))
#... [do something with the geodataframe]

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

#drop the geometry column as it is now duplicative
geodataframe.drop('geometry', 1, inplace=True)

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

ध्यान देने योग्य बात यह है कि 'if_exists' पैरामीटर आपको डेटाफ़्रेम को आपके पोस्टग्रेज टेबल में जोड़ने के तरीके को संभालने की अनुमति देता है:

    if_exists = replace: If table exists, drop it, recreate it, and insert data.
    if_exists = fail: If table exists, do nothing.
    if_exists = append: If table exists, insert data. Create if does not exist.

क्या ज्यामिति के कॉलम में एक से भिन्न SRID को निर्दिष्ट करके यहां पुन: अस्वीकृत करने का अवसर है, या क्या वर्तमान SRID का उपयोग किया जाना है? यह भी ज्यामिति स्तंभ से पूर्णांक SRID प्राप्त करने का सबसे अच्छा तरीका क्या है ?
रोजी

इस पद्धति का उपयोग करने के कारण मेरे पास sqlalchemy.exc.InvalidRequestError है: यह प्रतिबिंबित नहीं कर सकता: अनुरोधित तालिका (तालिकाएँ) इंजन त्रुटि में उपलब्ध नहीं है?
विल्क २

4

मेरे पास भी वही सवाल है जो आपने पूछा है और कई, कई दिनों तक उस पर (मुझे ध्यान रखने की तुलना में अधिक) एक समाधान की तलाश में बिताया है। निम्न पोस्टग्रेएसक्यूएल टेबल को पोस्टगिस एक्सटेंशन के साथ मान लें,

postgres=> \d cldmatchup.geo_points;
Table "cldmatchup.geo_points"
Column   |         Type         |                               Modifiers                                
-----------+----------------------+------------------------------------------------------------------------
gridid    | bigint               | not null default nextval('cldmatchup.geo_points_gridid_seq'::regclass)
lat       | real                 | 
lon       | real                 | 
the_point | geography(Point,4326) | 

Indexes:
"geo_points_pkey" PRIMARY KEY, btree (gridid)

यह वही है जो मुझे आखिरकार मिल गया है:

import geopandas as gpd
from geoalchemy2 import Geography, Geometry
from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import sessionmaker
from shapely.geometry import Point
from psycopg2.extensions import adapt, register_adapter, AsIs

# From http://initd.org/psycopg/docs/advanced.html#adapting-new-types but 
# modified to accomodate postGIS point type rather than a postgreSQL 
# point type format
def adapt_point(point):
    from psycopg2.extensions import adapt, AsIs
    x = adapt(point.x).getquoted()
    y = adapt(point.y).getquoted()
    return AsIs("'POINT (%s %s)'" % (x, y))

register_adapter(Point, adapt_point)

engine = create_engine('postgresql://<yourUserName>:postgres@localhost:5432/postgres', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
meta = MetaData(engine, schema='cldmatchup')

# Create reference to pre-existing "geo_points" table in schema "cldmatchup"
geoPoints = Table('geo_points', meta, autoload=True, schema='cldmatchup', autoload_with=engine)

df = gpd.GeoDataFrame({'lat':[45.15, 35., 57.], 'lon':[-35, -150, -90.]})

# Create a shapely.geometry point 
the_point = [Point(xy) for xy in zip(df.lon, df.lat)]

# Create a GeoDataFrame specifying 'the_point' as the column with the 
# geometry data
crs = {'init': 'epsg:4326'}
geo_df = gpd.GeoDataFrame(df.copy(), crs=crs, geometry=the_point)

# Rename the geometry column to match the database table's column name.
# From https://media.readthedocs.org/pdf/geopandas/latest/geopandas.pdf,
# Section 1.2.2 p 7
geo_df = geo_df.rename(columns{'geometry':'the_point'}).set_geometry('the_point')

# Write to sql table 'geo_points'
geo_df.to_sql(geoPoints.name, engine, if_exists='append', schema='cldmatchup', index=False)

session.close()

मैं यह नहीं कह सकता कि यदि मेरा डेटाबेस कनेक्शन लॉजिक सबसे अच्छा है क्योंकि मैंने मूल रूप से एक और लिंक से कॉपी किया था और सिर्फ इस बात से खुश था कि मैं सफलतापूर्वक मान्यता प्राप्त ज्यामिति परिभाषा के साथ अपनी मौजूदा तालिका को स्वचालित (या प्रतिबिंबित) करने में सक्षम था। मैं केवल कुछ महीनों के लिए एसक्यूएल स्थानिक कोड के लिए अजगर लिख रहा हूं, इसलिए मुझे पता है कि बहुत कुछ सीखना है।


0

मेरे पास एक समाधान है जिसके लिए केवल psycopg2 और सुडौल (अतिरिक्त जियोपैन्डस ऑफ कोर्स) की आवश्यकता होती है। यह आमतौर पर (Geo)DataFrameवस्तुओं के माध्यम से पुनरावृत्त करने के लिए बुरा अभ्यास है क्योंकि यह धीमा है, लेकिन छोटे लोगों के लिए, या एक-बंद कार्यों के लिए, यह अभी भी काम पूरा कर लेगा।

मूल रूप से यह दूसरे कॉलम में WKB प्रारूप में ज्यामिति को डंप करके काम करता है और फिर GEOMETRYडालने पर इसे टाइप करने के लिए फिर से कास्ट करता है ।

ध्यान दें कि आपको सही कॉलम के साथ समय से पहले तालिका बनानी होगी।

import psycopg2 as pg2
from shapely.wkb import dumps as wkb_dumps
import geopandas as gpd


# Assuming you already have a GeoDataFrame called "gdf"...

# Copy the gdf if you want to keep the original intact
insert_gdf = gdf.copy()

# Make a new field containing the WKB dumped from the geometry column, then turn it into a regular 
insert_gdf["geom_wkb"] = insert_gdf["geometry"].apply(lambda x: wkb_dumps(x))

# Define an insert query which will read the WKB geometry and cast it to GEOMETRY type accordingly
insert_query = """
    INSERT INTO my_table (id, geom)
    VALUES (%(id)s, ST_GeomFromWKB(%(geom_wkb)s));
"""

# Build a list of execution parameters by iterating through the GeoDataFrame
# This is considered bad practice by the pandas community because it is slow.
params_list = [
    {
        "id": i,
        "geom_wkb": row["geom_wkb"]
    } for i, row in insert_gdf.iterrows()
]

# Connect to the database and make a cursor
conn = pg2.connect(host=<your host>, port=<your port>, dbname=<your dbname>, user=<your username>, password=<your password>)
cur = conn.cursor()

# Iterate through the list of execution parameters and apply them to an execution of the insert query
for params in params_list:
    cur.execute(insert_query, params)
conn.commit()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.