Python: группировка по сумме с условием - PullRequest
0 голосов
/ 02 июля 2018

У меня есть датафрейм, подобный следующему:

df = pd.DataFrame({'condition' : ['a','b','b','b','a','a'],
               'name' : ['one', 'one', 'two', 'three', 'three', 'three'],
               'data1' : [7, 3, 48, 13, 27, 12]})
df
  condtion  data1   name
0   a          7    one
1   b          3    one
2   b         48    two
3   b         13    three
4   a         27    three
5   a         12    three

Для каждого имени, которое я хочу суммировать на data1 и использовать информацию condition=a, если у меня есть эта информация, condition=b в противном случае. В конце я хотел бы иметь такой кадр данных:

df1 
    name   total
0   one      7
1   two     48
2   three   39

Ответы [ 3 ]

0 голосов
/ 02 июля 2018

Вы можете groupby name и condition, чтобы найти sum из data1, а затем sort_values по name и condition перед выбором первой записи для каждой группы в группе по name:

df.groupby(['name', 'condition'])['data1'].sum().reset_index(name='total').sort_values(['name','condition']).groupby(['name']).first().reset_index()[['name', 'total']]

Выход:

    name    total
0   one     7
1   three   39
2   two     48
0 голосов
/ 02 июля 2018

Вы можете использовать pd.pivot_table с aggfunc='sum':

df = pd.DataFrame({'condition' : ['a','b','b','b','a','a'],
                   'name' : ['one', 'one', 'two', 'three', 'three', 'three'],
                   'data1' : [7, 3, 48, 13, 27, 12]})

res = df.pivot_table(index='name', columns='condition', values='data1', aggfunc='sum')

condition     a     b
name                 
one         7.0   3.0
three      39.0  13.0
two         NaN  48.0

Затем примените fillna и очистите:

res = res.assign(total=res['a'].fillna(res['b']).astype(int))\
         .reset_index().rename_axis('', 1)\
         .loc[:, ['name', 'total']]

print(res)

    name  total
0    one      7
1  three     39
2    two     48
0 голосов
/ 02 июля 2018

Вы можете агрегировать groupby с агрегацией sum и изменять ее на unstack, в последнем случае заменить NaN для отсутствующих категорий a на fillna

df = df.groupby(['name','condition'], sort=False)['data1'].sum().unstack()
df['total'] = df['a'].fillna(df['b'])
print (df)
condition     a     b  total
name                        
one         7.0   3.0    7.0
two         NaN  48.0   48.0
three      39.0  13.0   39.0

А для новых DataFrame:

df1 = df.reset_index().rename_axis(None, 1)[['name','total']]
print (df1)
    name  total
0    one    7.0
1    two   48.0
2  three   39.0

Другое решение с apply:

def f(x):
    if (x['condition'] == 'a').any():
        return x.loc[x['condition'] == 'a', 'data1'].sum() 
    else:
        return x.loc[x['condition'] == 'b', 'data1'].sum()

df1 = df.groupby('name', sort=False).apply(f).reset_index(name='total')
print (df1)
    name  total
0    one      7
1    two     48
2  three     39

Лучше создать серию для агрегирования отфильтрованного DataFrame, а затем combine_first, но в этом решении пропущены все группы name s без условий a или b:

a = df.loc[df['condition'] == 'a'].groupby('name', sort=False)['data1'].sum()
b = df.loc[df['condition'] == 'b'].groupby('name', sort=False)['data1'].sum()

df = a.combine_first(b).reset_index(name='total')
print (df)
    name  total
0    one    7.0
1  three   39.0
2    two   48.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...