Gestion des valeurs NaN#

Lors de l’analyse de données tabulaires, il arrive parfois que des cellules du tableau ne contiennent pas de données. En Python, cela signifie généralement que la valeur est Not a Number (NaN). Nous ne pouvons pas supposer que ces valeurs sont 0 ou -1 ou toute autre valeur car cela fausserait les statistiques descriptives, par exemple. Nous devons traiter ces entrées NaN différemment et ce notebook va présenter comment faire.

Pour avoir un premier aperçu du rôle des NaN, nous chargeons à nouveau un tableau d’exemple et le trions.

import numpy as np
import pandas as pd 

Nous trions le tableau par le paramètre area pour comprendre où les NaN jouent un rôle. Nous trions le tableau en utilisant sort_values.

data = pd.read_csv('../../data/Results.csv', index_col=0, delimiter=';')
data.sort_values(by = "Area", ascending=False)
Area Mean StdDev Min Max X Y XM YM Major Minor Angle %Area Type
190 2755.0 859.928 235.458 539.0 3880.0 108.710 302.158 110.999 300.247 144.475 24.280 39.318 100 C
81 2295.0 765.239 96.545 558.0 1431.0 375.003 134.888 374.982 135.359 65.769 44.429 127.247 100 B
209 1821.0 847.761 122.074 600.0 1510.0 287.795 321.115 288.074 321.824 55.879 41.492 112.124 100 A
252 1528.0 763.777 83.183 572.0 1172.0 191.969 385.944 192.487 385.697 63.150 30.808 34.424 100 B
265 1252.0 793.371 117.139 579.0 1668.0 262.071 394.497 262.268 394.326 60.154 26.500 50.147 100 A
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
113 1.0 587.000 0.000 587.0 587.0 399.500 117.500 399.500 117.500 1.128 1.128 0.000 100 A
310 1.0 866.000 0.000 866.0 866.0 343.500 408.500 343.500 408.500 1.128 1.128 0.000 100 A
219 1.0 763.000 0.000 763.0 763.0 411.500 296.500 411.500 296.500 1.128 1.128 0.000 100 A
3 NaN NaN NaN 608.0 964.0 NaN NaN NaN 7.665 7.359 NaN 101.121 100 A
5 NaN NaN 69.438 566.0 792.0 348.500 7.500 NaN 7.508 NaN 3.088 NaN 100 A

391 rows × 14 columns

Nous pourrions également utiliser cette fonction pour trier selon un axe (lignes/colonnes).

Comme vous pouvez le voir, il y a des lignes en bas contenant des NaNs. Elles sont au bas du tableau car pandas ne peut pas les trier.

Une vérification rapide pour savoir s’il y a des NaNs quelque part dans un tableau est un contrôle de qualité important pour une bonne pratique scientifique :

data.isnull().values.any()
True

Maintenant nous savons que nous avons des NaNs dans notre tableau. Nous pouvons également obtenir des informations plus détaillées sur les colonnes où se trouvent ces valeurs NaN.

data.isnull().sum()
Area      2
Mean      5
StdDev    3
Min       3
Max       3
X         2
Y         3
XM        3
YM        5
Major     8
Minor     3
Angle     1
%Area     0
Type      0
dtype: int64

Pour avoir un aperçu de la possibilité de traiter davantage ce tableau, nous pourrions vouloir connaître le pourcentage de NaNs pour chaque colonne :

data.isnull().mean().sort_values(ascending=False) *100
Major     2.046036
Mean      1.278772
YM        1.278772
StdDev    0.767263
Min       0.767263
Max       0.767263
Y         0.767263
XM        0.767263
Minor     0.767263
Area      0.511509
X         0.511509
Angle     0.255754
%Area     0.000000
Type      0.000000
dtype: float64

Suppression des lignes contenant des NaNs#

Selon le type d’analyse de données à effectuer, il peut être judicieux d’ignorer simplement les colonnes qui contiennent des valeurs NaN. Alternativement, il est possible de supprimer les lignes qui contiennent des NaNs.

Cela dépend de votre projet et de ce qui est important ou non pour l’analyse. Ce n’est pas une réponse facile.

data_no_nan = data.dropna(how="any")
data_no_nan 
Area Mean StdDev Min Max X Y XM YM Major Minor Angle %Area Type
1 18.0 730.389 103.354 592.0 948.0 435.000 4.722 434.962 4.697 5.987 3.828 168.425 100 A
2 126.0 718.333 90.367 556.0 1046.0 388.087 8.683 388.183 8.687 16.559 9.688 175.471 100 A
4 68.0 686.985 61.169 571.0 880.0 126.147 8.809 126.192 8.811 15.136 5.720 168.133 100 A
6 669.0 697.164 72.863 539.0 957.0 471.696 26.253 471.694 26.197 36.656 23.237 124.340 100 A
7 5.0 658.600 49.161 607.0 710.0 28.300 8.100 28.284 8.103 3.144 2.025 161.565 100 A
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
383 94.0 746.617 85.198 550.0 1021.0 194.032 498.223 194.014 498.239 17.295 6.920 52.720 100 B
387 152.0 801.599 111.328 582.0 1263.0 348.487 497.632 348.451 497.675 17.773 10.889 11.829 100 A
389 60.0 758.033 77.309 601.0 947.0 259.000 499.300 258.990 499.289 9.476 8.062 90.000 100 A
390 12.0 714.833 67.294 551.0 785.0 240.167 498.167 240.179 498.148 4.606 3.317 168.690 100 A
391 23.0 695.043 67.356 611.0 846.0 49.891 503.022 49.882 502.979 6.454 4.537 73.243 100 A

374 rows × 14 columns

En bas de ce tableau, vous pouvez voir qu’il contient encore 374 des 391 colonnes d’origine. Si vous supprimez des lignes, vous devriez documenter dans votre future publication scientifique combien de jeux de données sur combien ont été analysés.

Nous pouvons maintenant vérifier à nouveau si des NaNs sont présents.

data_no_nan.isnull().values.any()
False

Déterminer les lignes qui contiennent des NaNs#

Dans certains cas d’utilisation, il peut être utile d’avoir une liste des indices de lignes où il y a des valeurs NaN.

data = {
    'A': [0, 1, 22, 21, 12, 23],
    'B': [2, 3, np.nan,  2,  12, 22],
    'C': [2, 3, 44,  2,  np.nan, 52],
}

table = pd.DataFrame(data)
table
A B C
0 0 2.0 2.0
1 1 3.0 3.0
2 22 NaN 44.0
3 21 2.0 2.0
4 12 12.0 NaN
5 23 22.0 52.0
np.max(table.isnull().values, axis=1)
array([False, False,  True, False,  True, False])

Suppression des colonnes contenant des NaNs#

Comme mentionné précédemment, il est parfois judicieux de supprimer des colonnes. Par exemple, si une colonne est remplie de valeurs NaN. Pour illustrer cela, nous allons créer une telle colonne :

data['difficult_measurement'] = np.nan
nan_table = pd.DataFrame(data)
nan_table
A B C difficult_measurement
0 0 2.0 2.0 NaN
1 1 3.0 3.0 NaN
2 22 NaN 44.0 NaN
3 21 2.0 2.0 NaN
4 12 12.0 NaN NaN
5 23 22.0 52.0 NaN

Nous pouvons maintenant drop la colonne comme ceci :

table_dropped = nan_table.drop('difficult_measurement', axis=1)

Et avoir la colonne à nouveau supprimée de notre tableau

table_dropped
A B C
0 0 2.0 2.0
1 1 3.0 3.0
2 22 NaN 44.0
3 21 2.0 2.0
4 12 12.0 NaN
5 23 22.0 52.0