Combinaison de tables#
Lorsqu’on travaille avec de nombreuses tables dans une base de données relationnelle, il est souvent judicieux de combiner les tables dans des tables récapitulatives et de les stocker avant tout traitement ultérieur. Pour rappel, nous avons acquis des images pendant les expériences et les mesures correspondantes. Nous voudrions maintenant extraire une table aperçu qui contient les informations les plus importantes des tables image, experiments et measurements.
import pandas as pd
from pandasql import sqldf
Nous commençons à nouveau par charger nos tables depuis le disque.
experiment = pd.read_csv("../../data/experiments.csv")
image = pd.read_csv("../../data/images.csv")
measurement = pd.read_csv("../../data/measurements.csv")
Encore une fois, nous définissons une fonction qui peut interroger la base de données.
query_database = lambda q: sqldf(q, globals())
Jointure interne#
SQL permet également de combiner des tables en utilisant l’instruction JOIN. La plus courante est la INNER JOIN qui permet de combiner deux tables de manière à ce que les lignes soient appariées selon une connexion définie ON sur laquelle les tables sont combinées. La INNER JOIN s’assure que seules les lignes pour lesquelles les deux tables ont des entrées sont affichées. C’est pourquoi l’expérience ID 4 n’apparaît pas dans le tableau suivant. Il n’y avait pas d’images stockées pendant l’expérience 4.
query = """
SELECT *
FROM experiment
INNER JOIN image ON experiment.ID = image.experiment_ID
"""
query_database(query)
| Unnamed: 0 | ID | Comment | Concentration | Unnamed: 0 | ID | Filename | experiment_ID | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 |
| 1 | 0 | 1 | High dose | 50 | 1 | 2 | image1.tif | 1 |
| 2 | 0 | 1 | High dose | 50 | 2 | 3 | image2.tif | 1 |
| 3 | 1 | 2 | Medium dose | 20 | 3 | 4 | image3.tif | 2 |
| 4 | 1 | 2 | Medium dose | 20 | 4 | 5 | image4.tif | 2 |
| 5 | 1 | 2 | Medium dose | 20 | 5 | 6 | image5.tif | 2 |
| 6 | 2 | 3 | Control | 0 | 6 | 7 | image6.tif | 3 |
| 7 | 2 | 3 | Control | 0 | 7 | 8 | image7.tif | 3 |
| 8 | 2 | 3 | Control | 0 | 8 | 9 | image8.tif | 3 |
| 9 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 |
Jointure externe#
Si l’on voulait combiner les tables de manière à ce que l’expérience 4 soit également répertoriée, nous devons utiliser une OUTER JOIN. Dans ce cas, comme la table des expériences est à gauche de notre instruction SQL, nous utilisons le LEFT OUTER JOIN. L’expérience 4 est alors répertoriée dans notre table avec quelques NaNs dans les colonnes des images.
query = """
SELECT *
FROM experiment
LEFT OUTER JOIN image ON experiment.ID = image.experiment_ID
"""
query_database(query)
| Unnamed: 0 | ID | Comment | Concentration | Unnamed: 0 | ID | Filename | experiment_ID | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | High dose | 50 | 0.0 | 1.0 | image0.tif | 1.0 |
| 1 | 0 | 1 | High dose | 50 | 1.0 | 2.0 | image1.tif | 1.0 |
| 2 | 0 | 1 | High dose | 50 | 2.0 | 3.0 | image2.tif | 1.0 |
| 3 | 1 | 2 | Medium dose | 20 | 3.0 | 4.0 | image3.tif | 2.0 |
| 4 | 1 | 2 | Medium dose | 20 | 4.0 | 5.0 | image4.tif | 2.0 |
| 5 | 1 | 2 | Medium dose | 20 | 5.0 | 6.0 | image5.tif | 2.0 |
| 6 | 2 | 3 | Control | 0 | 6.0 | 7.0 | image6.tif | 3.0 |
| 7 | 2 | 3 | Control | 0 | 7.0 | 8.0 | image7.tif | 3.0 |
| 8 | 2 | 3 | Control | 0 | 8.0 | 9.0 | image8.tif | 3.0 |
| 9 | 2 | 3 | Control | 0 | 9.0 | 10.0 | image9.tif | 3.0 |
| 10 | 3 | 4 | Super high dose | 1000 | NaN | NaN | None | NaN |
Combinaison de nombreuses tables#
Les instructions JOIN ci-dessus peuvent également être utilisées en chaîne pour combiner plus de deux tables. Par exemple, nous pourrions être intéressés par le nombre de cellules au fil du temps pour chaque image dans chaque expérience.
query = """
SELECT *
FROM experiment
LEFT OUTER JOIN image ON experiment.ID = image.experiment_ID
INNER JOIN measurement ON image.ID = measurement.image_ID
"""
query_database(query)
| Unnamed: 0 | ID | Comment | Concentration | Unnamed: 0 | ID | Filename | experiment_ID | Unnamed: 0 | image_ID | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 | 0 | 1 | 0 | 96 |
| 1 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 | 1 | 1 | 1 | 47 |
| 2 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 | 2 | 1 | 2 | 32 |
| 3 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 | 3 | 1 | 3 | 24 |
| 4 | 0 | 1 | High dose | 50 | 0 | 1 | image0.tif | 1 | 4 | 1 | 4 | 19 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 95 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 | 95 | 10 | 5 | 142 |
| 96 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 | 96 | 10 | 6 | 148 |
| 97 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 | 97 | 10 | 7 | 144 |
| 98 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 | 98 | 10 | 8 | 141 |
| 99 | 2 | 3 | Control | 0 | 9 | 10 | image9.tif | 3 | 99 | 10 | 9 | 140 |
100 rows × 12 columns
Sélection de colonnes#
Lorsqu’une table devient trop large et comporte des colonnes dont nous n’avons pas vraiment besoin pour notre analyse, il est recommandé de remplacer le * dans l’instruction SELECT par des noms de colonnes.
query = """
SELECT experiment.Comment, image.Filename, measurement.time_after_exposure_in_s, measurement.number_of_cells
FROM experiment
LEFT OUTER JOIN image ON experiment.ID = image.experiment_ID
INNER JOIN measurement ON image.ID = measurement.image_ID
"""
query_database(query)
| Comment | Filename | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|
| 0 | High dose | image0.tif | 0 | 96 |
| 1 | High dose | image0.tif | 1 | 47 |
| 2 | High dose | image0.tif | 2 | 32 |
| 3 | High dose | image0.tif | 3 | 24 |
| 4 | High dose | image0.tif | 4 | 19 |
| ... | ... | ... | ... | ... |
| 95 | Control | image9.tif | 5 | 142 |
| 96 | Control | image9.tif | 6 | 148 |
| 97 | Control | image9.tif | 7 | 144 |
| 98 | Control | image9.tif | 8 | 141 |
| 99 | Control | image9.tif | 9 | 140 |
100 rows × 4 columns
Renommage de colonnes#
En utilisant l’instruction AS, nous pouvons également renommer les colonnes et rendre notre nouvelle table plus facile à lire et à comprendre.
query = """
SELECT experiment.Comment AS experiment_name, image.Filename, measurement.time_after_exposure_in_s, measurement.number_of_cells
FROM experiment
LEFT OUTER JOIN image ON experiment.ID = image.experiment_ID
INNER JOIN measurement ON image.ID = measurement.image_ID
"""
query_database(query)
| experiment_name | Filename | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|
| 0 | High dose | image0.tif | 0 | 96 |
| 1 | High dose | image0.tif | 1 | 47 |
| 2 | High dose | image0.tif | 2 | 32 |
| 3 | High dose | image0.tif | 3 | 24 |
| 4 | High dose | image0.tif | 4 | 19 |
| ... | ... | ... | ... | ... |
| 95 | Control | image9.tif | 5 | 142 |
| 96 | Control | image9.tif | 6 | 148 |
| 97 | Control | image9.tif | 7 | 144 |
| 98 | Control | image9.tif | 8 | 141 |
| 99 | Control | image9.tif | 9 | 140 |
100 rows × 4 columns
Comme cette instruction est assez compliquée et que nous ne devrions pas la copier-coller encore et encore, nous pouvons la stocker dans un DataFrame pandas overview.
query = """
SELECT experiment.Comment AS experiment_name, image.Filename, measurement.time_after_exposure_in_s, measurement.number_of_cells
FROM experiment
LEFT OUTER JOIN image ON experiment.ID = image.experiment_ID
INNER JOIN measurement ON image.ID = measurement.image_ID
"""
overview = query_database(query)
La table overview fait partie de notre base de données. Note : L’aperçu n’a pas encore été sauvegardé sur le disque.
query = """
SELECT *
FROM overview
"""
query_database(query)
| experiment_name | Filename | time_after_exposure_in_s | number_of_cells | |
|---|---|---|---|---|
| 0 | High dose | image0.tif | 0 | 96 |
| 1 | High dose | image0.tif | 1 | 47 |
| 2 | High dose | image0.tif | 2 | 32 |
| 3 | High dose | image0.tif | 3 | 24 |
| 4 | High dose | image0.tif | 4 | 19 |
| ... | ... | ... | ... | ... |
| 95 | Control | image9.tif | 5 | 142 |
| 96 | Control | image9.tif | 6 | 148 |
| 97 | Control | image9.tif | 7 | 144 |
| 98 | Control | image9.tif | 8 | 141 |
| 99 | Control | image9.tif | 9 | 140 |
100 rows × 4 columns
Pour une réutilisation dans les leçons ultérieures, nous sauvegardons le résumé sur le disque.
overview.to_csv("../../data/overview.csv")