web-dev-qa-db-fra.com

Somme conditionnelle des pandas en python avec Groupby

En utilisant des exemples de données:

df = pd.DataFrame({'key1' : ['a','a','b','b','a'],
               'key2' : ['one', 'two', 'one', 'two', 'one'],
               'data1' : np.random.randn(5),
               'data2' : np. random.randn(5)})

df

    data1        data2     key1  key2
0    0.361601    0.375297    a   one
1    0.069889    0.809772    a   two
2    1.468194    0.272929    b   one
3   -1.138458    0.865060    b   two
4   -0.268210    1.250340    a   one

J'essaie de comprendre comment grouper les données par clé1 et additionner uniquement les valeurs de données1 où clé2 est égal à «un».

Voici ce que j'ai essayé

def f(d,a,b):
    d.ix[d[a] == b, 'data1'].sum()

df.groupby(['key1']).apply(f, a = 'key2', b = 'one').reset_index()

Mais cela me donne un cadre de données avec des valeurs 'Aucune' 

index   key1    0
0       a       None
1       b       None

Des idées ici? Je cherche l'équivalent en Pandas du code SQL suivant:

SELECT Key1, SUM(CASE WHEN Key2 = 'one' then data1 else 0 end)
FROM df
GROUP BY key1

Pour votre information - j'ai vu des sommes conditionnelles pour des pandas agrégés mais je ne pouvais pas transformer la réponse fournie pour travailler avec des sommes plutôt que des comptes.

Merci d'avance

15
AllenQ

Première groupe par la colonne clé1:

In [11]: g = df.groupby('key1')

puis, pour chaque groupe, prenez le sous-fichier DataFrame où key2 est égal à «un» et additionnez la colonne data1:

In [12]: g.apply(lambda x: x[x['key2'] == 'one']['data1'].sum())
Out[12]:
key1
a       0.093391
b       1.468194
dtype: float64

Pour expliquer ce qui se passe, regardons le groupe 'a':

In [21]: a = g.get_group('a')

In [22]: a
Out[22]:
      data1     data2 key1 key2
0  0.361601  0.375297    a  one
1  0.069889  0.809772    a  two
4 -0.268210  1.250340    a  one

In [23]: a[a['key2'] == 'one']
Out[23]:
      data1     data2 key1 key2
0  0.361601  0.375297    a  one
4 -0.268210  1.250340    a  one

In [24]: a[a['key2'] == 'one']['data1']
Out[24]:
0    0.361601
4   -0.268210
Name: data1, dtype: float64

In [25]: a[a['key2'] == 'one']['data1'].sum()
Out[25]: 0.093391000000000002

Cela peut être légèrement plus facile/plus clair en limitant le cadre de données à ceux avec key2 égal à un:

In [31]: df1 = df[df['key2'] == 'one']

In [32]: df1
Out[32]:
      data1     data2 key1 key2
0  0.361601  0.375297    a  one
2  1.468194  0.272929    b  one
4 -0.268210  1.250340    a  one

In [33]: df1.groupby('key1')['data1'].sum()
Out[33]:
key1
a       0.093391
b       1.468194
Name: data1, dtype: float64
25
Andy Hayden

Je pense qu'aujourd'hui avec les pandas 0,23, vous pouvez le faire:

import numpy as np

 df.assign(result = np.where(df['key2']=='one',df.data1,0))\
   .groupby('key1').agg({'result':sum})

L'avantage de ceci est que vous pouvez l'appliquer à plus d'une colonne du même dataframe

df.assign(
 result1 = np.where(df['key2']=='one',df.data1,0),
 result2 = np.where(df['key2']=='two',df.data1,0)
  ).groupby('key1').agg({'result1':sum, 'result2':sum})
1
Diego

Vous pouvez filtrer votre base de données avant vous effectuez votre opération groupby. Si cela réduit votre index de série du fait que toutes les valeurs sont hors de portée, vous pouvez utiliser reindex avec fillna:

res = df.loc[df['key2'].eq('one')]\
        .groupby('key1')['data1'].sum()\
        .reindex(df['key1'].unique()).fillna(0)

print(res)

key1
a    3.631610
b    0.978738
c    0.000000
Name: data1, dtype: float64

Installer

J'ai ajouté une ligne supplémentaire à des fins de démonstration.

np.random.seed(0)

df = pd.DataFrame({'key1': ['a','a','b','b','a','c'],
                   'key2': ['one', 'two', 'one', 'two', 'one', 'two'],
                   'data1': np.random.randn(6),
                   'data2': np.random.randn(6)})
0
jpp