Ajout de tables#
Lors du traitement de plusieurs images, potentiellement en utilisant plusieurs bibliothèques de traitement d’images, une tâche courante consiste à combiner des tables.
Nous commençons avec deux petites tables de mesures qui auraient pu être obtenues à partir de différentes fonctions ou différentes bibliothèques.
import pandas as pd
table1 = pd.DataFrame({
"label": [1, 2, 3],
"circularity": [0.3, 0.5, 0.7],
"elongation": [2.3, 3.4, 1.2],
})
table1
| label | circularity | elongation | |
|---|---|---|---|
| 0 | 1 | 0.3 | 2.3 |
| 1 | 2 | 0.5 | 3.4 |
| 2 | 3 | 0.7 | 1.2 |
table2 = pd.DataFrame({
"label": [3, 2, 1, 4],
"area": [22, 32, 25, 18],
"skewness": [0.5, 0.6, 0.3, 0.3],
})
table2
| label | area | skewness | |
|---|---|---|---|
| 0 | 3 | 22 | 0.5 |
| 1 | 2 | 32 | 0.6 |
| 2 | 1 | 25 | 0.3 |
| 3 | 4 | 18 | 0.3 |
Combinaison des colonnes de tables#
Selon la documentation de pandas, il existe plusieurs façons de combiner des tables. Nous utilisons d’abord un exemple erroné pour mettre en évidence les pièges lors de la combinaison de tables.
Dans l’exemple suivant, les mesures des étiquettes 1 et 3 sont mélangées. De plus, l’une de nos tables ne contenait pas de mesures pour l’étiquette 4.
wrongly_combined_tables = pd.concat([table1, table2], axis=1)
wrongly_combined_tables
| label | circularity | elongation | label | area | skewness | |
|---|---|---|---|---|---|---|
| 0 | 1.0 | 0.3 | 2.3 | 3 | 22 | 0.5 |
| 1 | 2.0 | 0.5 | 3.4 | 2 | 32 | 0.6 |
| 2 | 3.0 | 0.7 | 1.2 | 1 | 25 | 0.3 |
| 3 | NaN | NaN | NaN | 4 | 18 | 0.3 |
Une meilleure façon de combiner les tables est la commande merge. Elle permet de spécifier explicitement sur quelle colonne les tables doivent être combinées. Les scientifiques des données parlent de ‘l’index’ ou de ‘l’identifiant’ des lignes dans les tables.
correctly_combined_tables1 = pd.merge(table1, table2, how='inner', on='label')
correctly_combined_tables1
| label | circularity | elongation | area | skewness | |
|---|---|---|---|---|---|
| 0 | 1 | 0.3 | 2.3 | 25 | 0.3 |
| 1 | 2 | 0.5 | 3.4 | 32 | 0.6 |
| 2 | 3 | 0.7 | 1.2 | 22 | 0.5 |
Vous remarquerez peut-être que dans l’exemple ci-dessus, l’étiquette 4 est manquante. Nous pouvons également l’obtenir dans notre table en effectuant une jointure externe.
correctly_combined_tables2 = pd.merge(table1, table2, how='outer', on='label')
correctly_combined_tables2
| label | circularity | elongation | area | skewness | |
|---|---|---|---|---|---|
| 0 | 1 | 0.3 | 2.3 | 25 | 0.3 |
| 1 | 2 | 0.5 | 3.4 | 32 | 0.6 |
| 2 | 3 | 0.7 | 1.2 | 22 | 0.5 |
| 3 | 4 | NaN | NaN | 18 | 0.3 |
correctly_combined_tables2 = pd.merge(table1, table2, how='right', on='label')
correctly_combined_tables2
| label | circularity | elongation | area | skewness | |
|---|---|---|---|---|---|
| 0 | 3 | 0.7 | 1.2 | 22 | 0.5 |
| 1 | 2 | 0.5 | 3.4 | 32 | 0.6 |
| 2 | 1 | 0.3 | 2.3 | 25 | 0.3 |
| 3 | 4 | NaN | NaN | 18 | 0.3 |
Supposons qu’il y ait un nom de mesure commun provenant de différentes tables. Par exemple, la table3 ci-dessous contient également “elongation”.
table3 = pd.DataFrame({
"label": [3, 2, 1, 4],
"area": [22, 32, 25, 18],
"skewness": [0.5, 0.6, 0.3, 0.3],
"elongation": [2.3, 3.4, 1.2, 1.1]
})
table3
| label | area | skewness | elongation | |
|---|---|---|---|---|
| 0 | 3 | 22 | 0.5 | 2.3 |
| 1 | 2 | 32 | 0.6 | 3.4 |
| 2 | 1 | 25 | 0.3 | 1.2 |
| 3 | 4 | 18 | 0.3 | 1.1 |
L’application de merge conserve toujours les deux mesures dans des colonnes différentes.
correctly_combined_tables3 = pd.merge(table1, table3, how='outer', on='label')
correctly_combined_tables3
| label | circularity | elongation_x | area | skewness | elongation_y | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0.3 | 2.3 | 25 | 0.3 | 1.2 |
| 1 | 2 | 0.5 | 3.4 | 32 | 0.6 | 3.4 |
| 2 | 3 | 0.7 | 1.2 | 22 | 0.5 | 2.3 |
| 3 | 4 | NaN | NaN | 18 | 0.3 | 1.1 |
Nous pouvons changer ‘x’ et ‘y’ en passant d’autres suffixes.
correctly_combined_tables3 = pd.merge(table1, table3, how='outer', on='label', suffixes=('_method1', '_method2'))
correctly_combined_tables3
| label | circularity | elongation_method1 | area | skewness | elongation_method2 | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0.3 | 2.3 | 25 | 0.3 | 1.2 |
| 1 | 2 | 0.5 | 3.4 | 32 | 0.6 | 3.4 |
| 2 | 3 | 0.7 | 1.2 | 22 | 0.5 | 2.3 |
| 3 | 4 | NaN | NaN | 18 | 0.3 | 1.1 |
Combinaison des mesures de plusieurs fichiers image#
Lorsqu’on applique un flux de travail à de nombreuses images, on obtiendrait des tables avec les mêmes noms de colonnes, mais avec un nombre variable de lignes. Pour calculer des statistiques pour des dossiers entiers ou pour effectuer de l’apprentissage automatique, nous devons généralement concaténer ces tables, mais il est important de garder une trace des fichiers sources.
Ouvrons deux tables générées en appliquant le même flux de travail à différents fichiers.
df1 = pd.read_csv('../../data/BBBC007_20P1_POS0007_D_1UL.csv')
df1.head()
| area | intensity_mean | major_axis_length | minor_axis_length | aspect_ratio | |
|---|---|---|---|---|---|
| 0 | 256 | 93.250000 | 19.995017 | 17.021559 | 1.174688 |
| 1 | 90 | 82.488889 | 15.939969 | 7.516326 | 2.120713 |
| 2 | 577 | 90.637782 | 35.324458 | 21.759434 | 1.623409 |
| 3 | 270 | 95.640741 | 20.229431 | 17.669052 | 1.144908 |
| 4 | 153 | 84.908497 | 15.683703 | 12.420475 | 1.262730 |
df2 = pd.read_csv('../../data/BBBC007_20P1_POS0010_D_1UL.csv')
df2.head()
| area | intensity_mean | major_axis_length | minor_axis_length | aspect_ratio | |
|---|---|---|---|---|---|
| 0 | 139 | 96.546763 | 17.504104 | 10.292770 | 1.700621 |
| 1 | 360 | 86.613889 | 35.746808 | 14.983124 | 2.385805 |
| 2 | 43 | 91.488372 | 12.967884 | 4.351573 | 2.980045 |
| 3 | 140 | 73.742857 | 18.940508 | 10.314404 | 1.836316 |
| 4 | 144 | 89.375000 | 13.639308 | 13.458532 | 1.013432 |
Dans ce cas particulier où nous savons que nous avons les mêmes colonnes, nous pourrions les concaténer en une seule grande table.
big_df = pd.concat([df1, df2], axis=0)
big_df
| area | intensity_mean | major_axis_length | minor_axis_length | aspect_ratio | |
|---|---|---|---|---|---|
| 0 | 256 | 93.250000 | 19.995017 | 17.021559 | 1.174688 |
| 1 | 90 | 82.488889 | 15.939969 | 7.516326 | 2.120713 |
| 2 | 577 | 90.637782 | 35.324458 | 21.759434 | 1.623409 |
| 3 | 270 | 95.640741 | 20.229431 | 17.669052 | 1.144908 |
| 4 | 153 | 84.908497 | 15.683703 | 12.420475 | 1.262730 |
| ... | ... | ... | ... | ... | ... |
| 42 | 315 | 91.133333 | 20.927095 | 19.209283 | 1.089426 |
| 43 | 206 | 94.262136 | 23.381879 | 11.669668 | 2.003646 |
| 44 | 45 | 68.377778 | 9.406371 | 6.276445 | 1.498678 |
| 45 | 33 | 76.727273 | 10.724275 | 4.174568 | 2.568955 |
| 46 | 16 | 76.750000 | 7.745967 | 2.783882 | 2.782433 |
111 rows × 5 columns
Le problème est que nous perdons leur identité source. Une solution facile est d’ajouter une nouvelle colonne avec le nom du fichier avant de les concaténer. Cela facilitera leur séparation ultérieure et leur tracé.
Lorsque nous donnons une seule valeur à une nouvelle colonne, elle est attribuée à toutes les lignes.
df1['file_name'] = 'BBBC007_20P1_POS0007_D_1UL'
df2['file_name'] = 'BBBC007_20P1_POS0010_D_1UL'
big_df = pd.concat([df1, df2], axis=0)
big_df
| area | intensity_mean | major_axis_length | minor_axis_length | aspect_ratio | file_name | |
|---|---|---|---|---|---|---|
| 0 | 256 | 93.250000 | 19.995017 | 17.021559 | 1.174688 | BBBC007_20P1_POS0007_D_1UL |
| 1 | 90 | 82.488889 | 15.939969 | 7.516326 | 2.120713 | BBBC007_20P1_POS0007_D_1UL |
| 2 | 577 | 90.637782 | 35.324458 | 21.759434 | 1.623409 | BBBC007_20P1_POS0007_D_1UL |
| 3 | 270 | 95.640741 | 20.229431 | 17.669052 | 1.144908 | BBBC007_20P1_POS0007_D_1UL |
| 4 | 153 | 84.908497 | 15.683703 | 12.420475 | 1.262730 | BBBC007_20P1_POS0007_D_1UL |
| ... | ... | ... | ... | ... | ... | ... |
| 42 | 315 | 91.133333 | 20.927095 | 19.209283 | 1.089426 | BBBC007_20P1_POS0010_D_1UL |
| 43 | 206 | 94.262136 | 23.381879 | 11.669668 | 2.003646 | BBBC007_20P1_POS0010_D_1UL |
| 44 | 45 | 68.377778 | 9.406371 | 6.276445 | 1.498678 | BBBC007_20P1_POS0010_D_1UL |
| 45 | 33 | 76.727273 | 10.724275 | 4.174568 | 2.568955 | BBBC007_20P1_POS0010_D_1UL |
| 46 | 16 | 76.750000 | 7.745967 | 2.783882 | 2.782433 | BBBC007_20P1_POS0010_D_1UL |
111 rows × 6 columns
Maintenant, nous pouvons distinguer en toute sécurité la source de chaque ligne.