给定日期,找到季度结束日期,使用pandas

12

假设我们有一个像这样的表格:

table = [[datetime.datetime(2015, 1, 1), 1, 0.5],
         [datetime.datetime(2015, 1, 27), 1, 0.5],
         [datetime.datetime(2015, 1, 31), 1, 0.5],
         [datetime.datetime(2015, 2, 1), 1, 2],
         [datetime.datetime(2015, 2, 3), 1, 2],
         [datetime.datetime(2015, 2, 15), 1, 2],
         [datetime.datetime(2015, 2, 28), 1, 2],
         [datetime.datetime(2015, 3, 1), 1, 3],
         [datetime.datetime(2015, 3, 17), 1, 3],
         [datetime.datetime(2015, 3, 31), 1, 3]]

df = pd.DataFrame(table, columns=['Date', 'Id', 'Value'])

如何根据Date列中的日期获取实际季度的特定结束日期?例如,我想添加Q_date列到df,使得

        Date  Id  Value  Qdate
0 2015-01-01   1    0.5  2015-03-31
1 2015-01-27   1    0.5  2015-03-31
2 2015-01-31   1    0.5  2015-03-31
3 2015-02-01   1    2.0  2015-03-31
4 2015-02-03   1    2.0  2015-03-31
5 2015-02-15   1    2.0  2015-03-31
6 2015-02-28   1    2.0  2015-03-31
7 2015-03-01   1    3.0  2015-03-31
8 2015-03-17   1    3.0  2015-03-31
9 2015-03-31   1    3.0  2015-03-31

为简单起见,我只考虑了第一季度 - 因为我知道现在是什么日期。

4个回答

18

更简单的方法是将日期转换为季度,然后再转回日期,例如:

df['Qdate'] = df['Date'].dt.to_period("Q").dt.end_time

注意还有.start_time用于表示第一季度的开始时间。


是的,更干净和更健壮的答案。 - dlm

18
您可以使用pd.tseries.offsets.QuarterEnd()来实现您在这里的目标。
import pandas as pd
import datetime

# your data
# ================================
table = [[datetime.datetime(2015, 1, 1), 1, 0.5],
         [datetime.datetime(2015, 1, 27), 1, 0.5],
         [datetime.datetime(2015, 1, 31), 1, 0.5],
         [datetime.datetime(2015, 2, 1), 1, 2],
         [datetime.datetime(2015, 2, 3), 1, 2],
         [datetime.datetime(2015, 2, 15), 1, 2],
         [datetime.datetime(2015, 2, 28), 1, 2],
         [datetime.datetime(2015, 3, 1), 1, 3],
         [datetime.datetime(2015, 3, 17), 1, 3],
         [datetime.datetime(2015, 3, 31), 1, 3]]

df = pd.DataFrame(table, columns=['Date', 'Id', 'Value'])

# processing
# ================================
# in case of 2015.03.31, simple QuarterEnd will roll forward to next quarter, so use DateOffset here to make it robust to this
df['Qdate'] = [date - pd.tseries.offsets.DateOffset(days=1) + pd.tseries.offsets.QuarterEnd() for date in  df.Date]

print(df)


        Date  Id  Value      Qdate
0 2015-01-01   1    0.5 2015-03-31
1 2015-01-27   1    0.5 2015-03-31
2 2015-01-31   1    0.5 2015-03-31
3 2015-02-01   1    2.0 2015-03-31
4 2015-02-03   1    2.0 2015-03-31
5 2015-02-15   1    2.0 2015-03-31
6 2015-02-28   1    2.0 2015-03-31
7 2015-03-01   1    3.0 2015-03-31
8 2015-03-17   1    3.0 2015-03-31
9 2015-03-31   1    3.0 2015-03-31

哇,非常感谢(再次)!您的解决方案总是非常棒和优雅。我将在七分钟内标记它为已解决... - Tingiskhan
1
@Tingiskhan 非常欢迎。很高兴能帮助到你。 :-) - Jianxun Li
3
为了使这个答案更加优雅,您可以使用:date + pd.tseries.offsets.QuarterEnd(n=0) - Luis
太棒了!你刚刚救了我的命。 - Steph

4
使用searchsorted是另一个选择:
import datetime
import pandas as pd

table = [[datetime.datetime(2015, 1, 1), 1, 0.5],
         [datetime.datetime(2015, 1, 27), 1, 0.5],
         [datetime.datetime(2015, 1, 31), 1, 0.5],
         [datetime.datetime(2015, 2, 1), 1, 2],
         [datetime.datetime(2015, 2, 3), 1, 2],
         [datetime.datetime(2015, 2, 15), 1, 2],
         [datetime.datetime(2015, 2, 28), 1, 2],
         [datetime.datetime(2015, 3, 1), 1, 3],
         [datetime.datetime(2015, 3, 17), 1, 3],
         [datetime.datetime(2015, 3, 31), 1, 3],
         [datetime.datetime(2015, 4, 1), 1, 3],
]

df = pd.DataFrame(table, columns=['Date', 'Id', 'Value'])
quarters = pd.date_range(
    df['Date'].min(), 
    df['Date'].max()+pd.tseries.offsets.QuarterEnd(), freq='Q')
df['Qdate'] = quarters[quarters.searchsorted(df['Date'].values)]
print(df)

产量
         Date  Id  Value      Qdate
0  2015-01-01   1    0.5 2015-03-31
1  2015-01-27   1    0.5 2015-03-31
2  2015-01-31   1    0.5 2015-03-31
3  2015-02-01   1    2.0 2015-03-31
4  2015-02-03   1    2.0 2015-03-31
5  2015-02-15   1    2.0 2015-03-31
6  2015-02-28   1    2.0 2015-03-31
7  2015-03-01   1    3.0 2015-03-31
8  2015-03-17   1    3.0 2015-03-31
9  2015-03-31   1    3.0 2015-03-31
10 2015-04-01   1    3.0 2015-06-30

通过避免逐行计算,像上面这样使用searchsorted 可以使中等大小的 DataFrames 的速度提高几个数量级。

这实际上是我自己考虑过的事情 - 即生成一个 date_range 列表并找到季度。非常感谢! - Tingiskhan
这比针对大型数据框的接受方法快得多。 - Neelotpal Shukla

2

非常棒的@Jianxun!这里有另一种方法:

import calendar

def f(x):
    q = ((x[0].month-1)//3 + 1)*3
    last = calendar.monthrange(x[0].year,q)[1]
    return datetime.date(x[0].year, q, last)

df['QDate'] = df.apply(f,axis=1)


In [24]: df
Out[24]:
        Date  Id  Value       QDate
0 2015-01-01   1    0.5  2015-03-31
1 2015-01-27   1    0.5  2015-03-31
2 2015-01-31   1    0.5  2015-03-31
3 2015-02-01   1    2.0  2015-03-31
4 2015-02-03   1    2.0  2015-03-31
5 2015-02-15   1    2.0  2015-03-31
6 2015-02-28   1    2.0  2015-03-31
7 2015-03-01   1    3.0  2015-03-31
8 2015-03-17   1    3.0  2015-03-31
9 2015-03-31   1    3.0  2015-03-31

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接