Risposte:
A partire da pandas 0.14 (rilasciato a fine maggio 2014), è supportato postgresql. Il sql
modulo ora utilizza sqlalchemy
per supportare diversi tipi di database. È possibile passare un motore sqlalchemy per un database postgresql (vedere la documentazione ). Per esempio:
from sqlalchemy import create_engine
engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
df.to_sql('table_name', engine)
Hai ragione che nei panda fino alla versione 0.13.1 postgresql non era supportato. Se è necessario utilizzare una versione precedente di panda, ecco una versione con patch di pandas.io.sql
: https://gist.github.com/jorisvandenbossche/10841234 .
L'ho scritto tempo fa, quindi non posso garantire completamente che funzioni sempre, ma la base dovrebbe essere lì). Se metti quel file nella tua directory di lavoro e lo importi, dovresti essere in grado di fare (dov'è con
una connessione postgresql):
import sql # the patched version (file is named sql.py)
sql.write_frame(df, 'table_name', con, flavor='postgresql')
Sqlalchemy engine
, posso usare una Postgres
connessione esistente creata usando psycopg2.connect()
?
Opzione più veloce:
Il codice seguente copierà il tuo Pandas DF nel DB postgres molto più velocemente del metodo df.to_sql e non avrai bisogno di alcun file csv intermedio per memorizzare il df.
Crea un motore basato sulle specifiche del tuo DB.
Crea una tabella nel tuo DB postgres che abbia lo stesso numero di colonne del Dataframe (df).
I dati in DF verranno inseriti nella tua tabella postgres.
from sqlalchemy import create_engine
import psycopg2
import io
se si desidera sostituire la tabella, possiamo sostituirla con il normale metodo to_sql utilizzando le intestazioni dal nostro df e quindi caricare l'intero df che richiede molto tempo nel DB.
engine = create_engine('postgresql+psycopg2://username:password@host:port/database')
df.head(0).to_sql('table_name', engine, if_exists='replace',index=False) #truncates the table
conn = engine.raw_connection()
cur = conn.cursor()
output = io.StringIO()
df.to_csv(output, sep='\t', header=False, index=False)
output.seek(0)
contents = output.getvalue()
cur.copy_from(output, 'table_name', null="") # null values become ''
conn.commit()
contents
? Dovrebbe essere questo quello in cui è scritto copy_from()
?
contents
variabile, tutto il resto dovrebbe funzionare bene
output.seek(0)
?
Panda 0.24.0+ soluzione
In Pandas 0.24.0 è stata introdotta una nuova funzionalità specificamente progettata per scritture veloci su Postgres. Puoi saperne di più qui: https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-sql-method
import csv
from io import StringIO
from sqlalchemy import create_engine
def psql_insert_copy(table, conn, keys, data_iter):
# gets a DBAPI connection that can provide a cursor
dbapi_conn = conn.connection
with dbapi_conn.cursor() as cur:
s_buf = StringIO()
writer = csv.writer(s_buf)
writer.writerows(data_iter)
s_buf.seek(0)
columns = ', '.join('"{}"'.format(k) for k in keys)
if table.schema:
table_name = '{}.{}'.format(table.schema, table.name)
else:
table_name = table.name
sql = 'COPY {} ({}) FROM STDIN WITH CSV'.format(
table_name, columns)
cur.copy_expert(sql=sql, file=s_buf)
engine = create_engine('postgresql://myusername:mypassword@myhost:5432/mydatabase')
df.to_sql('table_name', engine, method=psql_insert_copy)
method='multi'
un'opzione è abbastanza veloce. Ma sì, questo COPY
metodo è il modo più veloce in questo momento.
with
sta scrivendo in un buffer di memoria. L'ultima parte di with
utilizza un'istruzione SQL e sfrutta la velocità di copy_expert per caricare in blocco i dati. Qual è la parte centrale che inizia con il columns =
fare?
keys
argomenti nella psql_insert_copy
funzione per favore? Come ottiene le chiavi e le chiavi sono solo i nomi delle colonne?
Table 'XYZ' already exists
. Per quanto ho capito, non dovrebbe creare una tabella, vero?
df.to_sql('table_name', engine, if_exists='replace', method=psql_insert_copy)
- questo crea una tabella nel tuo database.
Ecco come l'ho fatto.
Potrebbe essere più veloce perché utilizza execute_batch
:
# df is the dataframe
if len(df) > 0:
df_columns = list(df)
# create (col1,col2,...)
columns = ",".join(df_columns)
# create VALUES('%s', '%s",...) one '%s' per column
values = "VALUES({})".format(",".join(["%s" for _ in df_columns]))
#create INSERT INTO table (columns) VALUES('%s',...)
insert_stmt = "INSERT INTO {} ({}) {}".format(table,columns,values)
cur = conn.cursor()
psycopg2.extras.execute_batch(cur, insert_stmt, df.values)
conn.commit()
cur.close()
Per Python 2.7 e Panda 0.24.2 e utilizzando Psycopg2
Modulo di connessione Psycopg2
def dbConnect (db_parm, username_parm, host_parm, pw_parm):
# Parse in connection information
credentials = {'host': host_parm, 'database': db_parm, 'user': username_parm, 'password': pw_parm}
conn = psycopg2.connect(**credentials)
conn.autocommit = True # auto-commit each entry to the database
conn.cursor_factory = RealDictCursor
cur = conn.cursor()
print ("Connected Successfully to DB: " + str(db_parm) + "@" + str(host_parm))
return conn, cur
Connettiti al database
conn, cur = dbConnect(databaseName, dbUser, dbHost, dbPwd)
Supponendo che dataframe sia già presente come df
output = io.BytesIO() # For Python3 use StringIO
df.to_csv(output, sep='\t', header=True, index=False)
output.seek(0) # Required for rewinding the String object
copy_query = "COPY mem_info FROM STDOUT csv DELIMITER '\t' NULL '' ESCAPE '\\' HEADER " # Replace your table name in place of mem_info
cur.copy_expert(copy_query, output)
conn.commit()