2 votes

En Python, comment regrouper + muter + ifelse comme en R?

Je utilise normalement R. Si j'ai des données comme :

Produit Indice Valeur
   a      1       0.5
   a      1       0.4
   c      1       1.4
   c      2       0.75
   e      2       0.6
   f      3       0.9

Si mon code R est :

a <- data %>%
  group_by(Produit) %>%
  mutate(Drapeau=ifelse(all(Indice==1),'droit','faux'))

Cela signifie, je regroupe d'abord les données par Produit. Ensuite, pour chaque groupe, je lui donne un nouveau champ appelé Drapeau. Si l'Indice dans ce groupe est tout 1, alors le Drapeau est droit, sinon il est faux. En même temps, tous les enregistrements sont conservés. Ainsi, le résultat devrait ressembler à :

Produit Indice Valeur Drapeau
   a       1      0.5   droit
   a       1      0.4   droit
   c       1      1.4   faux
   c       2      0.75  faux
   e       2      0.6   faux
   f       3      0.9   faux

Ma question est : comment faire les mêmes opérations en python ? J'ai essayé, np.where, groupby, transform et d'autres fonctions. Je les ai probablement combinées de la mauvaise manière.

Est-ce que quelqu'un pourrait m'aider ici ?

5voto

datapug Points 364

Utiliser transform est une option.

import pandas as pd

df = pd.DataFrame({'Produit': ['a', 'a', 'c', 'c', 'e', 'f'],
               'Index': [1, 1, 1, 2, 2, 3], 
              'Valeur': [0.5, 0.4, 1.4, 0.75, 0.6, 0.9]})
df['Marqueur'] = df.groupby('Produit')['Index'].transform(lambda x: 'correct' if sum(x)/len(x) == 1 else 'faux')
df

En passant, si les valeurs de Marqueur sont simplement 'correct' et 'faux', les remplacer par des valeurs 0,1 pourrait être plus efficace.

2voto

user3483203 Points 28606

Vous pouvez utiliser unique() et groupby() pour vous assurer que tous les produits ont un index de 1, puis les mapper vers votre nouvelle colonne :

In [51]: df['Flag'] = df['Product'].map(df.groupby('Product')['Index'].unique().apply(lambda row: 'right' if all(row==[1]) else 'wrong'))

In [52]: df
Out[52]:
  Product  Index  Value   Flag
0       a      1   0.50  right
1       a      1   0.40  right
2       c      1   1.40  wrong
3       c      2   0.75  wrong
4       e      2   0.60  wrong
5       f      3   0.90  wrong

1voto

jezrael Points 290608

Utilisez GroupBy.transform avec mean, comparez avec 1 et numpy.where pour les valeurs selon la condition :

df['Flag'] = np.where(df.groupby('Product')['Index'].transform('mean')== 1, 'correct', 'Faux')
print (df)
  Product  Index  Value   Flag
0       a      1   0.50  correct
1       a      1   0.40  correct
2       c      1   1.40  Faux
3       c      2   0.75  Faux
4       e      2   0.60  Faux
5       f      3   0.90  Faux

Détails :

print (df.groupby('Product')['Index'].transform('mean'))
0    1.0
1    1.0
2    1.5
3    1.5
4    2.0
5    3.0
Name: Index, dtype: float64

Une autre solution :

Comparez d'abord avec 1 avec eq puis utilisez GroupBy.transform avec all pour vérifier si tous les True par groupe et numpy.where pour les valeurs selon la condition :

df['Flag'] = np.where(df['Index'].eq(1).groupby(df['Product']).transform('all'), 
                      'correct', 'Faux')
print (df)
  Product  Index  Value   Flag
0       a      1   0.50  correct
1       a      1   0.40  correct
2       c      1   1.40  Faux
3       c      2   0.75  Faux
4       e      2   0.60  Faux
5       f      3   0.90  Faux

Détails :

print (df['Index'].eq(1).groupby(df['Product']).transform('all'))
0     True
1     True
2    False
3    False
4    False
5    False
Name: Index, dtype: bool

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X