2015-03-03 2 views
4

У меня есть сгруппированный DataFrame, который я хочу объединить со словарем функций, которые должны отображаться в определенных столбцах. Для одноуровневых столбцов это просто: groups.agg({'colname': <function>}). Однако я борюсь за то, чтобы это работало с многоуровневыми столбцами, из которых я хочу только ссылаться на один уровень.Агрегатная группа с многоуровневыми столбцами

Вот пример.

позволяет сделать некоторые образцы данных:

import itertools 
import pandas as pd 

lev1 = ['foo', 'bar', 'baz'] 
lev2 = list('abc') 

n = 6 

df = pd.DataFrame({k: np.random.randn(n) for k in itertools.product(lev1,lev2)}, 
        index=pd.DatetimeIndex(start='2015-01-01', periods=n, freq='11D')) 

Это выглядит следующим образом:

   bar    baz    foo    
       a  b  c  a  b  c  a  b  c 
2015-01-01 -1.11 2.12 -1.00 0.18 0.14 1.24 0.73 0.06 3.66 
2015-01-12 -1.43 0.75 0.38 0.04 -0.33 -0.42 1.00 -1.63 -1.35 
2015-01-23 0.01 -1.70 -1.39 0.59 -1.10 -1.17 -1.51 -0.54 -1.11 
2015-02-03 0.93 0.70 -0.12 1.07 -0.97 -0.45 -0.19 0.11 -0.79 
2015-02-14 0.30 0.49 0.60 -0.28 -0.38 1.11 0.15 0.78 -0.58 
2015-02-25 -0.26 0.51 0.82 0.05 -1.45 0.14 0.53 -0.33 -1.35 

и группировка по месяцам с:

groups = df.groupby(pd.TimeGrouper('MS')) 

Определить некоторые функции, основанные на высшем уровне в колонках:

funcs = {'bar': np.sum, 'baz': np.mean, 'foo': np.min} 

Однако выполнение groups.agg(funcs) приводит к KeyError, поскольку оно ожидает ключ для каждого уровня, что имеет смысл.

Это делает работу, например:

groups.agg({('bar', 'a'): np.mean}) 

       bar 
        a 
2015-01-01 -0.845554 
2015-02-01 0.324897 

Но я не хочу, чтобы указать каждый ключ на втором уровне. Так что я искал что-то, который будет работать как:

groups.agg({('bar', slice(None)): np.mean}) 

Но это не работает, конечно, так как slice не hashable, и поэтому не могу поставить в словаре.

Обходной бы:

def multifunc(group): 

    func = funcs[group.name[0]]   
    return func(group) 

groups.agg(multifunc) 

Но это не очень читаемый и не кажется, «Pandonic» мне. Также он не позволяет использовать несколько функций в том же столбце, что и функция agg. Там должен быть лучший/стандартный способ выполнения такой задачи, он не может быть очень необычным.

+0

Я открыл вопрос для обсуждения, если мы хотим, чтобы сделать это проще: https: //github.com/pydata/pandas/issues/9585 Но, я не уверен, какой будет лучший интерфейс. Я полагаю, что '{'bar': np.sum, 'baz': np.mean, 'foo': np.min}' может работать? Не стесняйтесь звонить! – joris

+0

Спасибо, Джорис! Было бы интересно посмотреть на это обсуждение. Как всегда показал Унтубу, всегда есть обходные пути. Но это означает шаг назад от интерфейса Pandas, а простой интерфейс - это значительная часть того, что делает Pandas настолько замечательным, чтобы работать. –

ответ

2

Я не думаю, что для этого есть короткий отрезок. К счастью, это не так уж трудно построить нужную Dict в явном виде:

result = groups.agg(
    {(k1, k2): funcs[k1] for k1, k2 in itertools.product(lev1,lev2)}) 

import itertools 
import numpy as np 
import pandas as pd 

lev1 = ['foo', 'bar', 'baz'] 
lev2 = list('abc') 

n = 6 

df = pd.DataFrame(
    {k: np.random.randn(n) for k in itertools.product(lev1,lev2)}, 
    index=pd.DatetimeIndex(start='2015-01-01', periods=n, freq='11D')) 
groups = df.groupby(pd.TimeGrouper('MS')) 
funcs = {'bar': np.sum, 'baz': np.mean, 'foo': np.min} 
result = groups.agg(
    {(k1, k2): funcs[k1] for k1, k2 in itertools.product(lev1,lev2)}) 
result = result.sortlevel(axis=1) 
print(result) 

дает

    bar       baz      \ 
        a   b   c   a   b   c 
2015-01-01 -2.144890 1.075044 1.038169 -0.460649 -0.309966 -0.211147 
2015-02-01 1.313744 0.247171 1.049129 -0.174827 -0.437982 -0.196427 

       foo      
        a   b   c 
2015-01-01 -1.358973 -1.846916 -0.896234 
2015-02-01 -1.354953 -0.699607 0.288214 
Смежные вопросы