2
votes

Vérifier l'unicité des séries dans les pandas d'objets Groupby

J'ai du mal à savoir comment obtenir transform () pour renvoyer le résultat souhaité. Je voudrais vérifier si dans chaque groupe si "manqué" est unique dans un groupe donné.

Tenez compte de ce qui suit:

a = ['correct', 'incorrect']
m = ['missed']
df['only_missed'] = df.groupby('key')['type'].transform(lambda x: 'no' if all(x.isin(a)) else ('yes' if all(x.isin(m)) else 'pass'))
df
   key  type    only_missed
0   1   correct     no
1   1   incorrect   no
2   2   missed      pass
3   2   incorrect   pass
4   3   missed      yes
5   3   missed      yes
6   2   correct     pass
7   4   pass        pass

J'essaie d'obtenir l'original dataframe pour ressembler à ceci. Où only_missed est oui si manqué est le seul type du groupe.

    key type    only_missed
0   1   correct     no
1   1   incorrect   no
2   2   missed      no
3   2   incorrect   no
4   3   missed      yes
5   3   missed      yes
6   2   correct     no
7   4   pass        pass

J'ai essayé ceci mais le résultat est inattendu:

df = pd.DataFrame({'key': [1, 1, 2, 2, 3, 3, 2, 4], 'type': ['correct', 'incorrect', 'missed', 'incorrect', 'missed', 'missed', 'correct', 'pass']})
df

  key   type
0   1   correct
1   1   incorrect
2   2   missed
3   2   incorrect
4   3   missed
5   3   missed
6   2   correct
7   4   pass

Celui-ci m'a vraiment déconcerté car j'ai parcouru plusieurs itérations ici pour essayer de comprendre ce qui se passe. p>

L'aide est grandement appréciée.


1 commentaires

Je suppose que je suis confus. Quel est votre résultat attendu? Le dataframe avec 1 "pass" ou le dataframe avec 4 "pass"?


3 Réponses :


0
votes

Essayez :

   key       type only_misses
0    1    correct          No
1    1  incorrect          No
2    2     missed          No
3    2  incorrect          No
4    3     missed         Yes
5    3     missed         Yes
6    2    correct          No
7    4       pass        pass

Output:

df['only_misses'] = df.groupby('key')['type']\
                      .transform(lambda x: (x.nunique() == 1) & (x.iloc[0] == 'missed'))\
                      .replace({False:'No',True:'Yes'})\
                      .mask(df.type == 'pass','pass')
df

Et, vous pouvez masquer le 'pass':

0      No
1      No
2      No
3      No
4     Yes
5     Yes
6      No
7    pass
Name: type, dtype: object

Résultat:

df.groupby('key')['type']\
  .transform(lambda x: (x.nunique() == 1) & (x.iloc[0] == 'missed'))\
  .replace({False:'No',True:'Yes'})\
  .mask(df.type == 'pass','pass')

Et, remplacez True / False par oui / non:

0    False
1    False
2    False
3    False
4     True
5     True
6    False
7     pass
Name: type, dtype: object

Sortie:

df.groupby('key')['type']\
  .transform(lambda x: (x.nunique() == 1) & (x.iloc[0] == 'missed'))\
  .mask(df.type == 'pass','pass')

Attribuer à la colonne dataframe:

0    False
1    False
2    False
3    False
4     True
5     True
6    False
7    False
Name: type, dtype: bool

Sortie:

df.groupby('key')['type'].transform(lambda x: (x.nunique() == 1) & (x.iloc[0] == 'missed'))


0 commentaires

0
votes
df.groupby('key')['type'].transform(
    lambda x: 'yes'
              if (x == 'missed').all() else 
              ('pass' if (x == 'pass').all() else 'no')
)                                        

1 commentaires

Cela a fait l'affaire. J'étais à l'envers sur la logique et je n'ai pas utilisé correctement a.all () . Idem pour ce que @RamGhadiyaram a dit - je ne sais pas pourquoi ce n'était pas directement évident pour moi. Merci!



0
votes

Une façon est d'utiliser des booléens et de les additionner pour créer un catégoriel:

In [21]: p = pd.Series((df.type == 'pass').values, df.key).groupby(level=0).transform('all')

In [22]: pd.Categorical.from_codes(m + 2 * p, ['no', 'yes', 'pass'])
Out[22]:
[no, no, no, no, yes, yes, no, pass]
Categories (3, object): [no, yes, pass]

In [23]: df['only_missed'] = pd.Categorical.from_codes(m + 2 * p, ['no', 'yes', 'pass'])

In [24]: df
Out[24]:
   key       type only_missed
0    1    correct          no
1    1  incorrect          no
2    2     missed          no
3    2  incorrect          no
4    3     missed         yes
5    3     missed         yes
6    2    correct          no
7    4       pass        pass

Cela semble un petit piratage avec le .values ​​ code> (pour éviter la réindexation) mais devrait être assez efficace ...


En regardant à nouveau, c'était la sortie "incorrecte", mais je vais le laisser là car c'est essentiellement le même. Afin d'obtenir le bon, vous devriez regarder tous les "pass":

In [11]: a = pd.Series(df.type.str.match('correct|incorrect').values, df.key).groupby(level=0).transform('all')

In [12]: m = pd.Series((df.type == 'missed').values, df.key).groupby(level=0).transform('all')

In [13]: pd.Categorical.from_codes(a + 2 * m, ['pass', 'no', 'yes'])
Out[13]:
[no, no, pass, pass, yes, yes, pass, pass]
Categories (3, object): [pass, no, yes]

In [14]: df["only_missed"] = pd.Categorical.from_codes(a + 2 * m, ['pass', 'no', 'yes'])

In [15]: df
Out[15]:
   key       type only_missed
0    1    correct          no
1    1  incorrect          no
2    2     missed        pass
3    2  incorrect        pass
4    3     missed         yes
5    3     missed         yes
6    2    correct        pass
7    4       pass        pass


0 commentaires