web-dev-qa-db-fra.com

Grouper la classe et compter les valeurs manquantes dans les fonctionnalités

J'ai un problème et je ne trouve aucune solution sur le web ou dans la documentation, même si je pense que c'est très banal.

Que veux-je faire?

J'ai une trame de données comme celle-ci

CLASS FEATURE1 FEATURE2 FEATURE3
  X      A       NaN      NaN
  X     NaN       A       NaN
  B      A        A        A

Je veux regrouper par le libellé ( CLASSE ) et afficher le nombre de valeurs NaN qui sont comptées dans chaque fonctionnalité pour que cela ressemble à ceci. Le but de ceci est d'avoir une idée générale de la façon dont les valeurs manquantes sont réparties entre les différentes classes.

CLASS FEATURE1 FEATURE2 FEATURE3
  X      1        1        2
  B      0        0        0

Je sais comment recevoir la quantité de non nulle - Valeurs - df.groupby['CLASS'].count()

Existe-t-il quelque chose de similaire pour les valeurs NaN -?

J'ai essayé de soustraire le count () de la taille () mais il a renvoyé une sortie non formatée remplie avec la valeur NaN

17
FlixRo

Calculez un masque avec isna, puis groupez et trouvez la somme:

df.drop('CLASS', 1).isna().groupby(df.CLASS, sort=False).sum().reset_index()

  CLASS  FEATURE1  FEATURE2  FEATURE3
0     X       1.0       1.0       2.0
1     B       0.0       0.0       0.0

Une autre option consiste à soustraire le size du count en utilisant rsub le long du 0e axe pour la soustraction alignée sur l'indice:

df.groupby('CLASS').count().rsub(df.groupby('CLASS').size(), axis=0)

Ou,

g = df.groupby('CLASS')
g.count().rsub(g.size(), axis=0)
       FEATURE1  FEATURE2  FEATURE3
CLASS                              
B             0         0         0
X             1         1         2

Il y a pas mal de bonnes réponses, alors voici quelques timeits pour votre lecture:

df_ = df
df = pd.concat([df_] * 10000)

%timeit df.drop('CLASS', 1).isna().groupby(df.CLASS, sort=False).sum()
%timeit df.set_index('CLASS').isna().sum(level=0)    
%%timeit
g = df.groupby('CLASS')
g.count().rsub(g.size(), axis=0)

11.8 ms ± 108 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.47 ms ± 379 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
6.54 ms ± 81.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Les performances réelles dépendent de vos données et de votre configuration, votre kilométrage peut donc varier.

16
cs95

Vous pouvez utiliser set_index et sum:

df.set_index('CLASS').isna().sum(level=0)

Sortie:

       FEATURE1  FEATURE2  FEATURE3
CLASS                              
X           1.0       1.0       2.0
B           0.0       0.0       0.0
13
Scott Boston

Utilisation de la différence entre count et size

g=df.groupby('CLASS')

-g.count().sub(g.size(),0)

          FEATURE1  FEATURE2  FEATURE3
CLASS                              
B             0         0         0
X             1         1         2

Et nous pouvons transformer cette question en une question plus générique, comment compter le nombre de NaN dans la trame de données avec la boucle for

pd.DataFrame({x: y.isna().sum()for x , y in g }).T.drop('CLASS',1)
Out[468]: 
   FEATURE1  FEATURE2  FEATURE3
B         0         0         0
X         1         1         2
7
WeNYoBen