将时间序列重新采样到年初至今

时间:2018-06-12 14:56:49

标签: python pandas scipy

让我们说我正在看US Treasury bill maturity data。它每天测量,但不是每天测量的百分比。

我可以得到四分之一速率的几何平均值:

import pandas as pd
from scipy.stats.mstats import gmean
# ...
tbill_quarterly = raw_tbill.resample('Q').apply(lambda x: gmean(x).item())

如何从这些数据中获得年初至今的季度汇总数据?也就是说,每个季度(2018年:2018-03-31,2018-06-30,2018-09-30,2018-12-31)的数字持有从年初到季度的回报。 / p>

重采样文档(或实际上,StackOverflow answer用作替换不存在的文档)仅提供频率。而我似乎无法在scipy.stats中找到某种年初至今的功能。

2 个答案:

答案 0 :(得分:0)

我讨厌回答我自己的问题,但是解决了这个问题后,我觉得我应该,如果其他人遇到这样的问题。我不保证这是最优雅的解决方案。它可能不是。

我将数据从FRED(回答链接)下载到文件treasury-1year-rates_1980-present.csv中,其中包含1979-12-31点到现在(目前为2018-06-12)的数据。您需要获得1979-12-31的数据点,因为1980-01-01是NA,因为那是联邦假期,是新年。

raw_tbill = pd.read_csv(path.join(base_dir, 'treasury-1year-rates_1980-present.csv'),
                        parse_dates=['DATE'], na_values=['.'])
raw_tbill.columns = [s.lower() for s in raw_tbill.columns.values.tolist()]
print(f'Loaded t-bill 1-year rates data, from 1980 to present, with {len(raw_tbill)} entries')

FRED数据使用.来表示缺失的数据。因此,包含na_values['.']并且我们还希望解析日期列,因此包含parse_dates参数。

我碰巧想把一切都放在小写字母中。它只保留在这里,因为我不想更改以下所有列名称。这真的很痛苦。

首先要避开两种误解,或者先解决问题。

算术意味着错误。算术方法对于处理百分比数据是错误的。你应该使用几何手段。有关详细说明,请参阅this。这会创建逐季度数据。

数据实际上并非每天。无论如何,这些数据实际上并非每天都有。为了解决这个问题,以及国库券仍然在节假日和周末支付的事实,所有这些周末都需要填充前向传播的数据。否则,几何平均值将是错误的,因为几何平均假设之一是数据在时间上均匀间隔(除非你加权它们,这实际上与我在这里做的相同,但我这样做是因为计算权重需要时间思考。这不是。

# fill in days and put in the previous applicable figure
# need to deal with gaps in data
raw_tbill.set_index('date', inplace=True)
raw_tbill.dropna(inplace=True)
tbill_data = raw_tbill.reindex(pd.date_range(raw_tbill.index.min(), raw_tbill.index.max(), freq='D'),
                               method='ffill')

年未完成。完成此操作后,我有多年没有实际填写(例如,显然1979-12-31是空的)。他们需要被删除才无用。

# drop incomplete years
count = tbill_data.set_index([tbill_data.index.year, tbill_data.index.day]).count(level=0)
years = count[count['dgs1'] >= 365].index
tbill_data['tmp_remove'] = tbill_data.apply(lambda r : 0 if r.name.year in years else 1, axis=1)
tbill_data = tbill_data[tbill_data['tmp_remove'] == 0].drop('tmp_remove', axis=1)

从这里开始,如果您关注代码,则索引现在为DatetimeIndex。因此,没有日期列。

获取季度指数并计算。现在,从技术上讲,您不需要执行此步骤。它在我的代码中,因为我必须生成它。但是,在此处理路径中,您必须执行此操作,以获取每个季度的索引。否则,没有宿舍,没有雪茄。

此外,DSG1数据是百分之百,我们不想要那些,如果你正在做任何事情,你可能想要它的比例,即100 pc = 1。

# turn the daily tbill data into quarterly data
# use geometric means
tbill_data['dgs1'] = tbill_data['dgs1'] / 100
tbill_qtrly = tbill_data.resample('Q').apply(lambda x: gmean(x).item())

无论如何我然后定义了一个函数来计算今年的年份,它也使用几何方法。然后,将相关数据子集到日期。我相信今年迄今为止包括报告日期,证明<=是正确的。如果它实际上没有这样做,请发表评论。

def calculate_ytd(row):
    year = row.name.year
    year_data = tbill_data[tbill_data.index.year == year]
    applicable_data = year_data[year_data.index <= row.name]
    return gmean(applicable_data['dgs1'])

tbill_qtrly['dgs1_ytd'] = tbill_qtrly.apply(lambda r : calculate_ytd(r), axis=1)

该功能的应用产生数据。

后脚本。如果所有输入变量都是正数,那么也可以使用季度几何平均值作为计算基础,因为

equation

所有变量 a e 都是正面的。

答案 1 :(得分:0)

使用Pandas DataFrame groupby overlapping intervals of variable length

的帮助
import pandas as pd
import numpy as np
from scipy.stats.mstats import gmean


# Get data & format
df = pd.read_csv("...\DGS1.csv")
def convert(x):
    try:
        return float(x)
    except ValueError:
        return np.nan

# Format data
df['DATE'] = pd.to_datetime(df.DATE)
df['DGS1'] = df.DGS1.map(convert)
df = df.set_index('DATE').dropna()

# Reindex date according to @ifly6 answer
df = df.reindex(pd.date_range(df.index.min(), df.index.max(), freq='D'),method='ffill')
df = df.reset_index().rename(columns={'index': 'date'})

# Determine if the date sits inside the date interval
def year_to_quarter_groups(x):
    return pd.Series([l for l in bins if l[0] <= x <= l[1]])

# Create all the date intervals
# bins = [
#     (pd.datetime(2013, 1, 1), pd.datetime(2013, 3, 31)),  
#     (pd.datetime(2013, 1, 1), pd.datetime(2013, 6, 30)),
#     ...
# ]
dates_from_ = [[i]*4 for i in  pd.date_range('1/1/2013', end='1/1/2019', freq='AS')]
dates_from = [item for sublist in dates_from_ for item in sublist]  # flatten list
dates_to = pd.date_range('1/1/2013', end='1/1/2019', freq='Q')
bins = list(zip(dates_from, dates_to))

# Create a set of intervals that each date belongs to
# A date can belong to up to four intervals/quarters [0, 1, 2, 3]
intervals = df['date'].apply(year_to_quarter_groups).stack().reset_index(1, drop=True)

# Combine the dataframes
new = pd.concat([df, intervals], axis=1).rename(columns={0: 'year_to_quarter'}).drop('date', axis=1)

# Calculate the geometric mean
new.groupby(['year_to_quarter']).DGS1.apply(lambda x: gmean(x))

Out[]:
year_to_quarter
(2013-01-01 00:00:00, 2013-06-30 00:00:00)    0.140469
(2013-01-01 00:00:00, 2013-09-30 00:00:00)    0.125079
(2013-01-01 00:00:00, 2013-12-31 00:00:00)    0.124699
(2014-01-01 00:00:00, 2014-03-31 00:00:00)    0.119801
(2014-01-01 00:00:00, 2014-06-30 00:00:00)    0.110655
(2014-01-01 00:00:00, 2014-09-30 00:00:00)    0.109624
(2014-01-01 00:00:00, 2014-12-31 00:00:00)    0.117386
(2015-01-01 00:00:00, 2015-03-31 00:00:00)    0.222842
(2015-01-01 00:00:00, 2015-06-30 00:00:00)    0.235393
(2015-01-01 00:00:00, 2015-09-30 00:00:00)    0.267067
(2015-01-01 00:00:00, 2015-12-31 00:00:00)    0.301378
(2016-01-01 00:00:00, 2016-03-31 00:00:00)    0.574620
(2016-01-01 00:00:00, 2016-06-30 00:00:00)    0.569675
(2016-01-01 00:00:00, 2016-09-30 00:00:00)    0.564723
(2016-01-01 00:00:00, 2016-12-31 00:00:00)    0.605566
(2017-01-01 00:00:00, 2017-03-31 00:00:00)    0.882396
(2017-01-01 00:00:00, 2017-06-30 00:00:00)    0.994391
(2017-01-01 00:00:00, 2017-09-30 00:00:00)    1.071789
(2017-01-01 00:00:00, 2017-12-31 00:00:00)    1.175368
(2018-01-01 00:00:00, 2018-03-31 00:00:00)    1.935798
(2018-01-01 00:00:00, 2018-06-30 00:00:00)    2.054127
(2018-01-01 00:00:00, 2018-09-30 00:00:00)    2.054127
(2018-01-01 00:00:00, 2018-12-31 00:00:00)    2.054127