python-pandas et bases de données comme mysql


97

La documentation de Pandas contient de nombreux exemples de bonnes pratiques pour travailler avec des données stockées dans différents formats.

Cependant, je n'arrive pas à trouver de bons exemples pour travailler avec des bases de données comme MySQL par exemple.

Quelqu'un peut-il me diriger vers des liens ou donner des extraits de code sur la façon de convertir efficacement les résultats de la requête en utilisant mysql-python en cadres de données dans Pandas?




Jetez également un œil à Blaze .
osa

Si vous êtes prêt à dépenser de l'argent, je crois que le livre de Wes McKinney ("Python for Data Analysis") contient quelques exemples utiles.
MTrenfield

Réponses:


102

Comme le dit Wes, read_sql d'io / sql le fera, une fois que vous aurez obtenu une connexion à la base de données en utilisant une bibliothèque compatible DBI. Nous pouvons examiner deux courts exemples utilisant les bibliothèques MySQLdbet cx_Oraclepour se connecter à Oracle et MySQL et interroger leurs dictionnaires de données. Voici l'exemple pour cx_Oracle:

import pandas as pd
import cx_Oracle

ora_conn = cx_Oracle.connect('your_connection_string')
df_ora = pd.read_sql('select * from user_objects', con=ora_conn)    
print 'loaded dataframe from Oracle. # Records: ', len(df_ora)
ora_conn.close()

Et voici l'exemple équivalent pour MySQLdb:

import MySQLdb
mysql_cn= MySQLdb.connect(host='myhost', 
                port=3306,user='myusername', passwd='mypassword', 
                db='information_schema')
df_mysql = pd.read_sql('select * from VIEWS;', con=mysql_cn)    
print 'loaded dataframe from MySQL. records:', len(df_mysql)
mysql_cn.close()

57

Pour les lecteurs récents de cette question: les pandas ont l'avertissement suivant dans leur documentation pour la version 14.0 :

Avertissement: certaines fonctions ou alias de fonction existants sont obsolètes et seront supprimés dans les versions futures. Cela inclut: tquery, uquery, read_frame, frame_query, write_frame.

Et:

Avertissement: La prise en charge de la saveur 'mysql' lors de l'utilisation d'objets de connexion DBAPI est obsolète. MySQL sera en outre pris en charge avec les moteurs SQLAlchemy (GH6900).

Cela rend la plupart des réponses obsolètes. Vous devez utiliser sqlalchemy:

from sqlalchemy import create_engine
import pandas as pd
engine = create_engine('dialect://user:pass@host:port/schema', echo=False)
f = pd.read_sql_query('SELECT * FROM mytable', engine, index_col = 'ID')

le chargement d'une table de 133 lignes et 7 colonnes prend environ 30 secondes. Pouvez-vous nous expliquer pourquoi?
idoda

@idoda [en général, ce n'est pas le sujet de la question et il vaut mieux poser une nouvelle question pour avoir plus d'opinions]. Êtes-vous sûr que ce n'est pas une question de délai de demande? L'envoi de la requête et la récupération des résultats sont-ils simplement beaucoup plus rapides?
Korem le

@Korem J'ai pensé à en ouvrir un nouveau, mais je voulais d'abord m'assurer que ce ne soit pas trivial. Lorsque j'utilise un client mySql (Sequel pro) et que j'interroge la base de données, les réutilisations apparaissent beaucoup plus rapidement. Lorsque vous dites «simplement envoyer et récupérer», est-ce cela que vous voulez dire? (en utilisant un client)
idoda

@idoda je veux dire comparer le temps qu'il faut pour s'exécuter engine.execute("select * FROM mytable")avec le temps qu'il faut pour s'exécuterpd.read_sql_query('SELECT * FROM mytable', engine)
Korem

Peut-on passer une requête sqlalchemy (session.query comme dans ma réponse ci-dessous) directement à une méthode pandas? Ce serait un ripper!
dmvianna

23

Pour mémoire, voici un exemple utilisant une base de données sqlite:

import pandas as pd
import sqlite3

with sqlite3.connect("whatever.sqlite") as con:
    sql = "SELECT * FROM table_name"
    df = pd.read_sql_query(sql, con)
    print df.shape

1
Vous pouvez spécifier la colonne à utiliser comme index en spécifiant index_col='timestamp'dans frame_query.
Escargot mécanique

19

Je préfère créer des requêtes avec SQLAlchemy , puis en créer un DataFrame. SQLAlchemy facilite la combinaison de conditions SQL de manière Python si vous avez l'intention de mélanger et de faire correspondre les choses encore et encore.

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Table
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from pandas import DataFrame
import datetime

# We are connecting to an existing service
engine = create_engine('dialect://user:pwd@host:port/db', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

# And we want to query an existing table
tablename = Table('tablename', 
    Base.metadata, 
    autoload=True, 
    autoload_with=engine, 
    schema='ownername')

# These are the "Where" parameters, but I could as easily 
# create joins and limit results
us = tablename.c.country_code.in_(['US','MX'])
dc = tablename.c.locn_name.like('%DC%')
dt = tablename.c.arr_date >= datetime.date.today() # Give me convenience or...

q = session.query(tablename).\
            filter(us & dc & dt) # That's where the magic happens!!!

def querydb(query):
    """
    Function to execute query and return DataFrame.
    """
    df = DataFrame(query.all());
    df.columns = [x['name'] for x in query.column_descriptions]
    return df

querydb(q)

Vous devez également spécifier le pilote s'il n'est pas le même que celui par défaut de SQLAlchemy :dialect+driver://user:pwd@host:port/db
Nuno André

11

Exemple MySQL:

import MySQLdb as db
from pandas import DataFrame
from pandas.io.sql import frame_query

database = db.connect('localhost','username','password','database')
data     = frame_query("SELECT * FROM data", database)

7
frame_queryest désormais obsolète. Maintenant, utilisez à la pd.read_sql(query, db)place.
Robert Smith

8

La même syntaxe fonctionne pour le serveur Ms SQL utilisant également podbc.

import pyodbc
import pandas.io.sql as psql

cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=servername;DATABASE=mydb;UID=username;PWD=password') 
cursor = cnxn.cursor()
sql = ("""select * from mytable""")

df = psql.frame_query(sql, cnxn)
cnxn.close()

5

Et voici comment vous vous connectez à PostgreSQL en utilisant le pilote psycopg2 (installez avec «apt-get install python-psycopg2» si vous êtes sur un OS dérivé de Debian Linux).

import pandas.io.sql as psql
import psycopg2

conn = psycopg2.connect("dbname='datawarehouse' user='user1' host='localhost' password='uberdba'")

q = """select month_idx, sum(payment) from bi_some_table"""

df3 = psql.frame_query(q, conn)


4

pandas.io.sql.frame_queryest obsolète. Utilisez pandas.read_sqlplutôt.


1

importer le module

import pandas as pd
import oursql

relier

conn=oursql.connect(host="localhost",user="me",passwd="mypassword",db="classicmodels")
sql="Select customerName, city,country from customers order by customerName,country,city"
df_mysql = pd.read_sql(sql,conn)
print df_mysql

Cela fonctionne très bien et en utilisant pandas.io.sql frame_works (avec l'avertissement de dépréciation). La base de données utilisée est l'exemple de base de données du didacticiel mysql.


0

Cela devrait très bien fonctionner.

import MySQLdb as mdb
import pandas as pd
con = mdb.connect(‘127.0.0.1’, root’, password’, database_name’);
with con:
 cur = con.cursor()
 cur.execute(“select random_number_one, random_number_two, random_number_three from randomness.a_random_table”)
 rows = cur.fetchall()
 df = pd.DataFrame( [[ij for ij in i] for i in rows] )
 df.rename(columns={0: Random Number One’, 1: Random Number Two’, 2: Random Number Three’}, inplace=True);
 print(df.head(20))

0

Cela m'a aidé à me connecter à AWS MYSQL (RDS) à partir de la fonction lambda basée sur python 3.x et à charger dans un pandas DataFrame

import json
import boto3
import pymysql
import pandas as pd
user = 'username'
password = 'XXXXXXX'
client = boto3.client('rds')
def lambda_handler(event, context):
    conn = pymysql.connect(host='xxx.xxxxus-west-2.rds.amazonaws.com', port=3306, user=user, passwd=password, db='database name', connect_timeout=5)
    df= pd.read_sql('select * from TableName limit 10',con=conn)
    print(df)
    # TODO implement
    #return {
    #    'statusCode': 200,
    #    'df': df
    #}

0

Pour les utilisateurs de Postgres

import psycopg2
import pandas as pd

conn = psycopg2.connect("database='datawarehouse' user='user1' host='localhost' password='uberdba'")

customers = 'select * from customers'

customers_df = pd.read_sql(customers,conn)

customers_df

1
Pourriez-vous souligner la différence avec la réponse de @Will et pourquoi votre solution devrait être choisie?
Sebastian
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.