Le module pandas
de python est destiné à traiter des tables (DataFrames).
On est donc assez proche de la conception tabulaire des bases de données relationnelles. On essaie d’explorer un peu cette relation.
On verra en DS2 des modèles de bases de données NoSQL, parmi lesquels Spark, qui reprend un peu les idées que nous allons voir.
Il importe cependant de comprendre la différence essentielle entre un ensemble de DataFrames pandas et une BDD gérée par SGBD. Le SGBD est là pour assurer des contraintes d’intégrité, et proposer un protocole client-serveur pour interroger les données. Pandas est un outil local, qui charge en mémoire les tables, et permet ainsi des traitements rapides et adaptés à vos besoins locaux, mais limités par les contraintes matérielles (RAM) de votre machine.
On peut voir pandas comme un outils d’ETL (extract-transform-load). Dans le chapitre suivant, on parle de façon plus détaillée d’autres outils d’ETL.
Connexion à PostgreSQL à partir de pandas
On se donne un fichier password.py
de la forme
monlogin = '...'
monpwd = '...'
mabase = '...'
monserveur = 'data.stud'
On peut alors accéder à la base de donnée PostgreSQL, de la façon suivante :
import pandas as pd
from sqlalchemy import create_engine
import psycopg2
from password import *
data_connexion = f"postgresql+psycopg2://{mabase}:{monpwd}@{monserveur}/{mabase}"
engine = create_engine(data_connexion,pool_recycle=3600)
conn = engine.connect()
# Lecture d'une table et importation dans un DataFrame
df = pd.read_sql("select * from comptes", conn)
# Création d'une table à partir d'un DataFrame
data= [(6,257),(7,26987),(52,-25)]
df = pd.DataFrame(data,columns=("id","montant"))
df.to_sql('new',conn)
conn.close()
Faire du SQL en pandas
On va utiliser la documentation de pandas
Travailler avec une table
Pour comparer, on va partir d’un fichier csv https://math.univ-angers.fr/~ducrot/bddr/churn_modelling.csv qui correspond à une table dont le schéma serait le suivant :
CREATE TABLE churn (
RowNumber INT NOT NULL,
CustomerId INT NOT NULL,
Surname VARCHAR(20) NULL,
CreditScore INT NULL,
Geography VARCHAR(20) NULL,
Gender VARCHAR(20) NULL,
Age INT NULL,
Tenure INT NULL,
Balance DECIMAL(10,2) NULL,
NumOfProducts INT NULL,
HasCrCard INT NULL,
IsActiveMember INT NULL,
EstimatedSalary DECIMAL(10,2) NULL,
Exited INT NULL,
PRIMARY KEY(RowNumber)
);
On peut,
-
soit le charger dans un sgbd, et faire des requêtes SQL,
-
soit le charger dans un DataFrame pandas, et en extraire des informations avec pandas
Ici, on vous demande de la charger dans un DataFrame, et de faire les requêtes pandas équivalentes à
-- Les 5 premières lignes
SELECT * FROM churn LIMIT 5;
-- Sélectionner des colonnes
SELECT CustomerId, Geography FROM churn;
-- Sélectionner suivant un critère
SELECT CustomerId, Geography FROM churn
WHERE Geography = 'France'
LIMIT 5;
-- les valeurs distinctes
SELECT DISTINCT Geography FROM churn;
-- compter les valeurs distinctes
SELECT COUNT(DISTINCT Geography) FROM churn;
-- Groupement et fonction d'agrégation
SELECT Geography, COUNT(Geography) AS 'count'
FROM churn
GROUP BY Geography;
-- Même chose, mais ordonnée
SELECT Geography, AVG(Age) AS 'Average Age'
FROM churn
GROUP BY Geography
ORDER BY Age;
Les jointures
On utilise ici les fonctions merge
, join
et èconcat` de pandas.
On se donne deux fichiers csv :
https://math.univ-angers.fr/~ducrot/bddr/climate_temp.csv et https://math.univ-angers.fr/~ducrot/bddr/climate_precip.csv qui recensent des relevés météo (températures et précipitations) dans différentes stations météo tous les jours pendant un an.
-
charger ces fichiers dans deux DataFrames pandas
-
choisir à votre guise une station et créer un DataFrame
precip_one_station
recensant uniquement les enregistrement de précipitations de cette station. -
Faire une jointure de cette table avec la table des températures. Quelle est sa taille ?
-
Regarder ce que font les différentes commandes (en particulier les tailles des différents DataFrames obtenus) ?
inner_merged_total = pd.merge(climate_temp, climate_precip, on=["STATION", "DATE"])
outer_merged = pd.merge(precip_one_station, climate_temp, how="outer", on=["STATION", "DATE"])
left_merged = pd.merge(climate_temp, precip_one_station, how="left", on=["STATION", "DATE"])
right_merged = pd.merge(precip_one_station, climate_temp, how="right", on=["STATION", "DATE"])
precip_one_station.join(climate_temp, lsuffix="_left", rsuffix="_right")
climate_temp.join(precip_one_station, lsuffix="_left")
inner_joined_bare_total = climate_temp.join(climate_precip, lsuffix="_left", rsuffix="_right")
pd.concat([precip_one_station, precip_one_station])
pd.concat([precip_one_station, precip_one_station], ignore_index=True)