Как отфильтровать серию панд с индексом datetime по кварталу и году

У меня есть серия, называемая «счетами», с индексом datetime.

Я хочу разделить его на quarter и year
псевдокодом: series.loc['q2 of 2013']

На данный момент попыток:
s.dt.quarter

AttributeError: может использовать аксессор .dt только со значениями, подобными datetime.

s.index.dt.quarter

AttributeError: объект DatetimeIndex не имеет атрибута dt

Это работает (вдохновлено этим ответом), но Я не могу поверить, что это правильный способ сделать это в Pandas:

d = pd.DataFrame(s)
d['date'] = pd.to_datetime(d.index)
d.loc[(d['date'].dt.quarter == 2) & (d['date'].dt.year == 2013)]['scores']

Я ожидаю, что есть способ сделать это без преобразования в набор данных, принудительного использования индекса в datetime, а затем получения из него Series.

Что мне не хватает, и каков элегантный способ сделать это в серии Pandas?


person sapo_cosmico    schedule 25.07.2016    source источник
comment
это будет работать, если индекс - datetime s.index.quarter.   -  person shivsn    schedule 25.07.2016
comment
Вам нужна функция, которую можно получить в определенный год и квартал?   -  person piRSquared    schedule 25.07.2016
comment
IIUC вам нужен scores.ix[scores.index.quarter==2].   -  person shivsn    schedule 25.07.2016
comment
У @shivsn есть правильный ответ, я в шоке, что не подумал отпустить эту dt штуку.   -  person sapo_cosmico    schedule 25.07.2016


Ответы (3)


import numpy as np
import pandas as pd

index = pd.date_range('2013-01-01', freq='M', periods=12)
s = pd.Series(np.random.rand(12), index=index)
print(s)

# 2013-01-31    0.820672
# 2013-02-28    0.994890
# 2013-03-31    0.928376
# 2013-04-30    0.848532
# 2013-05-31    0.122263
# 2013-06-30    0.305741
# 2013-07-31    0.088432
# 2013-08-31    0.647288
# 2013-09-30    0.640308
# 2013-10-31    0.737139
# 2013-11-30    0.233656
# 2013-12-31    0.245214
# Freq: M, dtype: float64

d = pd.Series(s.index, index=s.index)
quarter = d.dt.quarter.astype(str) + 'Q' + d.dt.year.astype(str)
print(quarter)

# 2013-01-31    1Q2013
# 2013-02-28    1Q2013
# 2013-03-31    1Q2013
# 2013-04-30    2Q2013
# 2013-05-31    2Q2013
# 2013-06-30    2Q2013
# 2013-07-31    3Q2013
# 2013-08-31    3Q2013
# 2013-09-30    3Q2013
# 2013-10-31    4Q2013
# 2013-11-30    4Q2013
# 2013-12-31    4Q2013
# Freq: M, dtype: object

print(s[quarter == '1Q2013'])

# 2013-01-31    0.124398
# 2013-02-28    0.052828
# 2013-03-31    0.126374
# Freq: M, dtype: float64

Если вы не хотите создавать новую серию, содержащую метку для каждого квартала (например, если вы разделяете только один раз), вы даже можете сделать

print(s[(s.index.quarter == 1) & (s.index.year == 2013)])

# 2013-01-31    0.124398
# 2013-02-28    0.052828
# 2013-03-31    0.126374
# Freq: M, dtype: float64
person Alberto Garcia-Raboso    schedule 25.07.2016

Предположим, у вас есть такой фрейм данных:

sa
Out[28]: 
             0
1970-01-31   1
1970-02-28   2
1970-03-31   3
1970-04-30   4
1970-05-31   5
1970-06-30   6
1970-07-31   7
1970-08-31   8
1970-09-30   9
1970-10-31  10
1970-11-30  11
1970-12-31  12

Если индекс - datetime, вы можете получить квартал как sa.index.quarter:

sa.index.quarter
Out[30]: array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])
person shivsn    schedule 25.07.2016

Если вы знаете год и квартал, скажем, Q2 2013, то вы можете сделать это:

s['2013-04':'2013-06']

Оберните это в функцию:

qmap = pd.DataFrame([
        ('01', '03'), ('04', '06'), ('07', '09'), ('10', '12')
    ], list('1234'), list('se')).T

def get_quarter(df, year, quarter):
    s, e = qmap[str(quarter)]
    y = str(year)
    s = y + '-' + s
    e = y + '-' + e
    return df[s:e]

и назовите это:

get_quarter(s, 2013, 2)

предположим, что s:

s = pd.Series(range(32), pd.date_range('2011-01-01', periods=32, freq='Q'))

Тогда я получаю:

2013-03-31    8
Freq: Q-DEC, dtype: int64
person piRSquared    schedule 25.07.2016