Подтвердить что ты не робот

Pandas группа за месяц и год

У меня есть следующий фреймворк:

Date        abc    xyz
01-Jun-13   100    200
03-Jun-13   -20    50
15-Aug-13   40     -5
20-Jan-14   25     15
21-Feb-14   60     80

Мне нужно сгруппировать данные по годам и месяцам. т.е.: Группа к январю 2013, февраль 2013, март 2013 и т.д.... Я буду использовать вновь сгруппированные данные, чтобы создать график, показывающий abc vs xyz в год/месяц.

Я пробовал различные комбинации groupby и sum, но просто не могу заставить ничего работать.

Спасибо за любую помощь.

4b9b3361

Ответ 1

Вы можете использовать либо resample, либо TimeGrouper (который используется для повторного использования под капотом).

Сначала сделайте столбец datetime фактическим числом времени (нажмите его pd.to_datetime). Это проще, если бы DatetimeIndex:

In [11]: df1
Out[11]:
            abc  xyz
Date
2013-06-01  100  200
2013-06-03  -20   50
2013-08-15   40   -5
2014-01-20   25   15
2014-02-21   60   80

In [12]: g = df1.groupby(pd.TimeGrouper("M"))  # DataFrameGroupBy (grouped by Month)

In [13]: g.sum()
Out[13]:
            abc  xyz
Date
2013-06-30   80  250
2013-07-31  NaN  NaN
2013-08-31   40   -5
2013-09-30  NaN  NaN
2013-10-31  NaN  NaN
2013-11-30  NaN  NaN
2013-12-31  NaN  NaN
2014-01-31   25   15
2014-02-28   60   80

In [14]: df1.resample("M", how='sum')  # the same
Out[14]:
            abc  xyz
Date
2013-06-30   40  125
2013-07-31  NaN  NaN
2013-08-31   40   -5
2013-09-30  NaN  NaN
2013-10-31  NaN  NaN
2013-11-30  NaN  NaN
2013-12-31  NaN  NaN
2014-01-31   25   15
2014-02-28   60   80

Я думал, что следующее будет работать, но это не так (из-за as_index не соблюдается? Я не уверен.), я включаю это ради интересов.

Если это столбец (он должен быть столбцом datetime64, как я сказал, нажмите его с помощью to_datetime), вы можете использовать PeriodIndex:

In [21]: df
Out[21]:
        Date  abc  xyz
0 2013-06-01  100  200
1 2013-06-03  -20   50
2 2013-08-15   40   -5
3 2014-01-20   25   15
4 2014-02-21   60   80

In [22]: pd.DatetimeIndex(df.Date).to_period("M")  # old way
Out[22]:
<class 'pandas.tseries.period.PeriodIndex'>
[2013-06, ..., 2014-02]
Length: 5, Freq: M

In [23]: per = df.Date.dt.to_period("M")  # new way to get the same

In [24]: g = df.groupby(per)

In [25]: g.sum()  # dang not quite what we want (doesn't fill in the gaps)
Out[25]:
         abc  xyz
2013-06   80  250
2013-08   40   -5
2014-01   25   15
2014-02   60   80

Чтобы получить желаемый результат, мы должны переиндексировать...

Ответ 2

Почему бы не сохранить его простым?!

GB=DF.groupby([(DF.index.year),(DF.index.month)]).sum()

print(GB)
        abc  xyz
2013 6   80  250
     8   40   -5
2014 1   25   15
     2   60   80

а затем вы можете нарисовать, как просили использовать,

GB.plot('abc','xyz',kind='scatter')

Ответ 3

Существуют разные способы сделать это.

  • Я создал фрейм данных, чтобы продемонстрировать различные методы фильтрации ваших данных.
df = pd.DataFrame({'Date':['01-Jun-13','03-Jun-13', '15-Aug-13', '20-Jan-14', '21-Feb-14'],

'abc': [100, -20,40,25,60], 'xyz': [200,50, -5,15,80]})

  • Я разделил месяцы/год/день и раздельный месяц-год, как вы объяснили.
def getMonth(s):
  return s.split("-")[1]

def getDay(s):
  return s.split("-")[0]

def getYear(s):
  return s.split("-")[2]

def getYearMonth(s):
  return s.split("-")[1]+"-"+s.split("-")[2]
  • Я создал новые столбцы: year, month, day и 'yearMonth'. В вашем случае вам нужен один из них. Вы можете группировать два столбца 'year','month' или использовать один столбец yearMonth
df['year']= df['Date'].apply(lambda x: getYear(x))
df['month']= df['Date'].apply(lambda x: getMonth(x))
df['day']= df['Date'].apply(lambda x: getDay(x))
df['YearMonth']= df['Date'].apply(lambda x: getYearMonth(x))

Выход:

        Date  abc  xyz year month day YearMonth
0  01-Jun-13  100  200   13   Jun  01    Jun-13
1  03-Jun-13  -20   50   13   Jun  03    Jun-13
2  15-Aug-13   40   -5   13   Aug  15    Aug-13
3  20-Jan-14   25   15   14   Jan  20    Jan-14
4  21-Feb-14   60   80   14   Feb  21    Feb-14
  • Вы можете просматривать различные группы в элементах groupby (..).

В этом случае мы группируем по двум столбцам:

for key,g in df.groupby(['year','month']):
    print key,g

Выход:

('13', 'Jun')         Date  abc  xyz year month day YearMonth
0  01-Jun-13  100  200   13   Jun  01    Jun-13
1  03-Jun-13  -20   50   13   Jun  03    Jun-13
('13', 'Aug')         Date  abc  xyz year month day YearMonth
2  15-Aug-13   40   -5   13   Aug  15    Aug-13
('14', 'Jan')         Date  abc  xyz year month day YearMonth
3  20-Jan-14   25   15   14   Jan  20    Jan-14
('14', 'Feb')         Date  abc  xyz year month day YearMonth

В этом случае мы группируем по одному столбцу:

for key,g in df.groupby(['YearMonth']):
    print key,g

Выход:

Jun-13         Date  abc  xyz year month day YearMonth
0  01-Jun-13  100  200   13   Jun  01    Jun-13
1  03-Jun-13  -20   50   13   Jun  03    Jun-13
Aug-13         Date  abc  xyz year month day YearMonth
2  15-Aug-13   40   -5   13   Aug  15    Aug-13
Jan-14         Date  abc  xyz year month day YearMonth
3  20-Jan-14   25   15   14   Jan  20    Jan-14
Feb-14         Date  abc  xyz year month day YearMonth
4  21-Feb-14   60   80   14   Feb  21    Feb-14
  • Если вы хотите получить доступ к определенному элементу, вы можете использовать get_group

print df.groupby(['YearMonth']). get_group ('Jun-13')

Выход:

        Date  abc  xyz year month day YearMonth
0  01-Jun-13  100  200   13   Jun  01    Jun-13
1  03-Jun-13  -20   50   13   Jun  03    Jun-13
  • Аналогично get_group. Этот хак поможет фильтровать значения и получать сгруппированные значения.

Это также даст тот же результат.

print df[df['YearMonth']=='Jun-13'] 

Вывод:

        Date  abc  xyz year month day YearMonth
0  01-Jun-13  100  200   13   Jun  01    Jun-13
1  03-Jun-13  -20   50   13   Jun  03    Jun-13

Вы можете выбрать список значений abc или xyz во время Jun-13

print df[df['YearMonth']=='Jun-13'].abc.values
print df[df['YearMonth']=='Jun-13'].xyz.values

Выход:

[100 -20]  #abc values
[200  50]  #xyz values

Вы можете использовать это, чтобы просмотреть даты, которые вы классифицировали как "год-месяц", и применять кретирию на нем для получения связанных данных.

for x in set(df.YearMonth): 
    print df[df['YearMonth']==x].abc.values
    print df[df['YearMonth']==x].xyz.values

Я также рекомендую также проверить этот .

Ответ 4

Вы также можете сделать это, создав строковый столбец с годом и месяц следующим образом:

df['date'] = df.index
df['year-month'] = df['date'].apply(lambda x: str(x.year) + ' ' + str(x.month))
grouped = df.groupby('year-month')

Однако это не сохраняет порядок, когда вы перебираете группы, например.

for name, group in grouped:
    print(name)

Дает:

2007 11
2007 12
2008 1
2008 10
2008 11
2008 12
2008 2
2008 3
2008 4
2008 5
2008 6
2008 7
2008 8
2008 9
2009 1
2009 10

Итак, если вы хотите сохранить заказ, вы должны сделать так, как предложила @Q-man выше:

grouped = df.groupby([df.index.year, df.index.month])

Это сохранит порядок в приведенном выше цикле:

(2007, 11)
(2007, 12)
(2008, 1)
(2008, 2)
(2008, 3)
(2008, 4)
(2008, 5)
(2008, 6)
(2008, 7)
(2008, 8)
(2008, 9)
(2008, 10)