Python pour les scientifiques

Une rapide introduction

Jeremy Fix

CentraleSupélec

Analyse de données avec pandas

Introduction

Installation

Avec uv :

~$ uv pip install pandas

Avec pip :

~$ pip install pandas

Beaucoup d’exemples par la suite viennent du guide utilisateur Pandas.

Series et DataFrame

  • une série (pd.Series) est une collection de valeurs indexées :
s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])
s.index # Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
s.loc['a']
s['a']
  • une série peut être indexée, slicée, etc.. comme un tableau numpy avec iloc, et comme un dictionnaire avec [..] ou loc()

  • une DataFrame est une collection de séries de données (comme une base de données)

d = {
    "one": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]),
    "two": pd.Series([1.0, 2.0, 3.0, 4.0], index=["a", "b", "c", "d"]),
    "three": pd.Series([1.0, 2.0 ], index=["b", "d"])
}
df = pd.DataFrame(d)
print(df)
     one  two  three
  a  1.0  1.0    NaN
  b  2.0  2.0    1.0
  c  3.0  3.0    NaN
  d  NaN  4.0    2.0

df.loc['a',['one', 'three']] # pd.Series
  • on accède aux colonnes df.columns, à leurs types df.dtypes, à l’index df.index
  • on peut ajouter (comme un dictionnaire) des colonnes df["four"] = df["one"] + df["two"], supprimer del df["one"]

Créer une dataframe et obtenir des infos

On peut construire une DataFrame à partir de dictionnaires, tableaux numpy, … ou de fichiers :

# Dictionnaire des colonnes
d = {
    "one": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]),
    "two": pd.Series([1.0, 2.0, 3.0, 4.0], index=["a", "b", "c", "d"]),
    "three": pd.Series([1.0, 2.0 ], index=["b", "d"])
}
df = pd.DataFrame(d)

# Liste des lignes
df = pd.DataFrame([{"one": 1, "two": 2}, {"one": 5, "two": 10, "three": 20}])

# Fichier CSV
df = pd.read_csv("fichier.csv", delimiter=";")
  • on obtient des infos avec df.info(), df.describe(), df.head()
  • statistiques descriptives (mean, std, count) df.describe(), (unique, top, freq) df.describe(include='category')

Summarize data cheatsheets pandas

Summarize data cheatsheets pandas

Vérifier et corriger les types

  • Les types des colonnes peuvent être le type générique “object”.
  • si des données sont des temps (datetime), des données catégorielles categories, des données numériques, il faut fixer les types
def read_data(filepath: str):
    df = pd.read_csv(filepath, delimiter=";")
    return df

def fix_datatypes(df):
    cat_columns = ['code_station', 'libelle_station', ...]
    for c in cat_columns:
        df[c] = df[c].astype('category')

    df["date_observation"] = pd.to_datetime(df["date_observation"])

df = read_data("ecoulements.csv")
fix_datatypes(df)

Changing Type cheatsheets pandas

Changing Type cheatsheets pandas

Important fixer les types des séries permet de profiter de toutes les fonctionnalités associées (e.g. catégories, temps)

Calculer avec des tableaux pandas

Calculer des statistiques descriptives

Sur une dataframe, on peut :

  • calculer des moyennes, sommes, médianes : df["Age"].median()
  • agréger avec une liste de fonctions prédéfinies (min, max, mean, …) ou arbitraires df.agg({"Age": ["min", "max", "median", "skew"]})

Les statistiques peuvent être calculées sur des sous-groupes formés par groupby:

titanic = pd.read_csv("data/titanic.csv")



# On peut regrouper les données par catégories et calculer
# des statistiques sur les sous-groupes
titanic = pd.read_csv("titanic.csv") 
grouped = titanic[["Sex", "Pclass", "Age", "Fare"]].groupby(["Sex", "Pclass"])
print(grouped.size())
print(grouped.mean())
   PassengerId  Survived  Pclass  ...     Fare Cabin  Embarked
0            1         0       3  ...   7.2500   NaN         S
1            2         1       1  ...  71.2833   C85         C
2            3         1       3  ...   7.9250   NaN         S

Sex     Pclass
female  1          94
        2          76
        3         144
male    1         122
        2         108
        3         347
dtype: int64
                     Age        Fare
Sex    Pclass                       
female 1       34.611765  106.125798
       2       28.722973   21.970121
       3       21.750000   16.118810
male   1       41.281386   67.226127
       2       30.740707   19.741782
       3       26.507589   12.661633

Voir https://pandas.pydata.org/docs/dev/getting_started/intro_tutorials/06_calculate_statistics.html#min-tut-06-stats

Pivot

Partant d’une représentation empilée (stacked), on peut réarranger les données avec la méthode pivot ou pivot_table (permet d’agréger) :

  • index : la ou les colonnes qui servent d’index
  • columns : les valeurs que ces colonnes prennent deviennent les colonnes
  • values : les valeurs à l’intersection des valeurs d’index et des valeurs de colonnes
df = pd.DataFrame(
    {
        "A": ["one", "one", "two", "three"] * 6,
        "B": ["bidule", "machin", "truc"] * 8,
        "C": ["foo", "foo", "foo", "bar", "bar", "bar"] * 4,
        "D": np.random.randn(24),
        "E": np.random.randn(24),
        "F": [datetime.datetime(2013, i, 1) for i in range(1, 13)]
        + [datetime.datetime(2013, i, 15) for i in range(1, 13)],
    }
)
print(df)

pivoted = pd.pivot_table(df, values="D", index=["A", "B"], columns=["C"])
print(pivoted)

print(pivoted.loc[("one", "bidule"), "bar"])
        A       B    C         D         E          F
0     one  bidule  foo  0.029577  0.050984 2013-01-01
1     one  machin  foo -0.442099 -0.106008 2013-02-01
2     two    truc  foo  1.953053  1.265677 2013-03-01
3   three  bidule  bar -1.299982  0.762093 2013-04-01
4     one  machin  bar  0.652348 -0.323386 2013-05-01
5     one    truc  bar  1.433064 -1.818466 2013-06-01
6     two  bidule  foo  2.291547 -0.087507 2013-07-01
7   three  machin  foo -1.203084 -0.089323 2013-08-01
8     one    truc  foo  1.022026 -1.088463 2013-09-01
9     one  bidule  bar -0.433758  2.892209 2013-10-01
...

C                  bar       foo
A     B                         
one   bidule  0.243642 -0.317265
      machin -0.183342 -0.318656
      truc    0.942341  1.991506
three bidule -0.641189       NaN
      machin       NaN -1.362425
      truc   -1.088678       NaN
two   bidule       NaN  1.272628
      machin -0.686480       NaN
      truc         NaN  1.024224

0.24364165912866229

pivot retourne une erreur en cas de doublons (moins flexible). pivot_table agrège les doublons (e.g. défaut : aggfunc='mean').

Joindre des tables

On peut joindre plusieurs dataframes par des clés, e.g. :

  • une table définit des campagnes de mesures avec leurs dates, l’opérateur, etc…
  • une table contient des observations, associées à un identifiant de campagne de mesures

Ces tableaux peuvent être joints, par exemple pour lister les observations réalisées par un opérateur.

Illustration de pd.merge dans les cheatsheets pandas

Illustration de pd.merge dans les cheatsheets pandas

Tracer des données

Pandas est interfacée avec matplotlib pour le tracé d’histogrammes (hist), nuages de points (scatter), séries (plot, même avec le temps !)

Les fonctions de tracé conduisent à des tracés indépendants pour des données groupées groupby.

Illustration des fonctions de tracés dans les cheatsheets pandas

Illustration des fonctions de tracés dans les cheatsheets pandas

Tracés avec Matplotlib

Introduction

Matplotlib : Numerical Python

  • Librairie python pour le tracé
  • offre une multitude de fonctions de tracés plans (line plot, image, histograms), 3D statiques ou animés

Mission statement

Adapting the requirements laid out by John Hunter Matplotlib should:

  • Support users of the Scientific Python ecosystem;
  • Facilitate interactive data exploration;
  • Produce high-quality raster and vector format outputs suitable for publication;
  • Provide a simple graphical user interface and support embedding in applications;
  • Be understandable and extensible by people familiar with data processing in Python;
  • Make common plots easy, and novel or complex visualizations possible.
import matplotlib
import matplotlib.pyplot as plt

Matplotlib for beginners

Handout for beginners de la documentation de matplotlib disponible sur https://matplotlib.org/cheatsheets/_images/handout-beginner.png

Handout for beginners de la documentation de matplotlib disponible sur https://matplotlib.org/cheatsheets/_images/handout-beginner.png

Matplotlib for intermediate users

Handout for intermediates de la documentation de matplotlib disponible sur https://matplotlib.org/cheatsheets/_images/handout-intermediate.png

Handout for intermediates de la documentation de matplotlib disponible sur https://matplotlib.org/cheatsheets/_images/handout-intermediate.png

Les cheatsheats (1/2)

Les cheatsheats (2/2)

Apprentissage automatique avec scikit-learn

Introduction à l’apprentissage supervisé

Quelques concepts clés pour fixer les idées :

  • On suppose disposer de données \(x_i\) qui peuvent être étiquetées \(y_i\)

  • Apprentissage supervisé :

    Etant donnés des paires \((x_i, y_i) \sim P_{X, Y}\), apprendre une fonction \(f_\theta\) (un prédicteur) qui minimise le risque réel :

\[ R_r(f) = \int_{X \ times Y} \mathcal{L}(y, f_\theta(x)) p_{X, Y}(x,y) dx dy \]

  • Etant données un échantillonnage \((x_i, y_i), i \in [|0, N-1|]\), on peut calculer le risque empirique :

\[ R_e(f) = \sum_{i=0}^{N-1} \mathcal{L}(y_i, f_\theta(x_i)) \]

Question : comment prédire l’étiquette \(y\) associée à des \(x\) étant données des paires d’échantillons \((x_i, y_i)\)

Attention nous ne pourrons pas introduire tout les concepts liés au machine learning

Qu’apporte scikit-learn ? Une vue d’ensemble

Scikit-learn est une librairie python qui offre:

Le tout étant pipelinable et disposant d’une interface commune.

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# Chargement des données
iris = load_iris()
X, y = iris.data, iris.target

# Construction d'un pli d'entrainement et un pli de test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Construction du prédicteur et entrainement
clf = make_pipeline(StandardScaler(), KNeighborsClassifier(3))
clf.fit(X_train, y_train)

# Evaluation du risque sur un pli de test
score = clf.score(X_test, y_test)

# Inférence sur le pli de test
y_test_pred = clf.transform(X_test)

Scikit-learn

Scikit-learn

Exemples de régression et classification

Voir Feature_selection_embedded.html

Bibliographie

Références