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, но просто не могу заставить ничего работать.
Спасибо за любую помощь.
Ответы
Ответ 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)