2016-03-09 4 views
5

Предположим, имеющий следующий DataFrame:Группа по год/месяц/день в панд

rng = pd.date_range('1/1/2011', periods=72, freq='H') 
np.random.seed(10) 
n = 10 
df = pd.DataFrame(
    { 
     "datetime": np.random.choice(rng,n), 
     "cat": np.random.choice(['a','b','b'], n), 
     "val": np.random.randint(0,5, size=n) 
     } 
    ) 

Если я теперь groupby:

gb = df.groupby(['cat','datetime']).sum() 

Я получаю итоги для каждого cat за каждый час:

cat datetime   val 
a 2011-01-01 00:00:00 1 
    2011-01-01 09:00:00 3 
    2011-01-02 16:00:00 1 
    2011-01-03 16:00:00 1 
b 2011-01-01 08:00:00 4 
    2011-01-01 15:00:00 3 
    2011-01-01 16:00:00 3 
    2011-01-02 04:00:00 4 
    2011-01-02 05:00:00 1 
    2011-01-02 12:00:00 4 

Однако, я хотел бы иметь что-то вроде:

cat datetime val 
a 2011-01-01 4 
    2011-01-02 1 
    2011-01-03 1 
b 2011-01-01 10 
    2011-01-02 9 

я мог бы получить желаемый результат, добавив еще один столбец date:

df['date'] = df.datetime.apply(pd.datetime.date) 

, а затем сделать подобную groupby: df.groupby(['cat','date']).sum(). Но меня интересует, есть ли еще питонический способ сделать это? Кроме того, я мог бы взглянуть на месяц или год. Итак, каков был бы правильный путь?

+0

Вы собираетесь просто фильтровать или хотите суммировать/пересчитать? возможно, лучше разделить дату на компоненты дня года и установить ее в индекс, чтобы вы могли называть 'sum (level = [1,2])' например. Или, чтобы установить индекс в столбец даты, 'resample', а затем groupby на 'cat' и выполнить скопления – EdChum

+0

Мне кажется, что решение, которое я предложил, является отправной точкой того, что вы имеете в виду, но я не понять, как это сделать. – Dror

ответ

1

Вы можете попробовать set_index, а затем groupby по cat и date:

import pandas as pd 
import numpy as np 

rng = pd.date_range('1/1/2011', periods=72, freq='H') 
np.random.seed(10) 
n = 10 
df = pd.DataFrame(
    { 
     "datetime": np.random.choice(rng,n), 
     "cat": np.random.choice(['a','b','b'], n), 
     "val": np.random.randint(0,5, size=n) 
     } 
    ) 
print df 
    cat   datetime val 
0 a 2011-01-01 09:00:00 3 
1 b 2011-01-01 15:00:00 3 
2 a 2011-01-03 16:00:00 1 
3 b 2011-01-02 04:00:00 4 
4 b 2011-01-02 05:00:00 1 
5 b 2011-01-01 08:00:00 4 
6 a 2011-01-01 00:00:00 1 
7 a 2011-01-02 16:00:00 1 
8 b 2011-01-02 12:00:00 4 
9 b 2011-01-01 16:00:00 3 
df = df.set_index('datetime') 
gb = df.groupby(['cat', lambda x: x.date]).sum() 
print gb 
       val 
cat     
a 2011-01-01 4 
    2011-01-02 1 
    2011-01-03 1 
b 2011-01-01 10 
    2011-01-02 9 
+1

Благодарю вас за трюк лямбда x: x.date. Я снова узнал от вас что-то новое. +1 – MaxU

+0

Спасибо. Приятный день. – jezrael

0

С вашей промежуточной структуры, которую можно использовать .unstack отделить категории, сделать .resample, а затем .stack снова для возврата к первоначальной форме:

In [126]: gb = df.groupby(['cat', 'datetime']).sum() 

In [127]: gb.unstack(0) 
Out[127]: 
        val 
cat     a b 
datetime 
2011-01-01 00:00:00 1.0 NaN 
2011-01-01 08:00:00 NaN 4.0 
2011-01-01 09:00:00 3.0 NaN 
2011-01-01 15:00:00 NaN 3.0 
2011-01-01 16:00:00 NaN 3.0 
2011-01-02 04:00:00 NaN 4.0 
2011-01-02 05:00:00 NaN 1.0 
2011-01-02 12:00:00 NaN 4.0 
2011-01-02 16:00:00 1.0 NaN 
2011-01-03 16:00:00 1.0 NaN 

In [128]: gb.unstack(0).resample("D").sum().stack() 
Out[128]: 
       val 
datetime cat 
2011-01-01 a  4.0 
      b 10.0 
2011-01-02 a  1.0 
      b  9.0 
2011-01-03 a  1.0 

EDIT: Для других частот повторной дискретизации (месяц, год и т. Д.) Есть хороший список опций на pandas resample documentation