Pandas 将季度转换为每日,同时牢记不同的代码
Pandas convert quarterly to daily while keeping distinct tickers in mind
我正在处理财务数据,其中一些是按季度格式化的,另一些是按天格式化的。我的模型每天都需要所有这些,因此我需要每天重复相同的季度值。我一直在使用这个 并尝试使代码适应我的数据。
这是我的数据框头:
date ticker value
0 31/03/1980 ECB/RA6 1.0
1 30/06/1980 ECB/RA6 4.0
2 30/09/1980 ECB/RA6 2.0
3 30/12/1980 ECB/RA6 3.0
4 31/03/1981 ECB/RA6 2.0
这是我想要的输出:
date ticker value
0 01/01/1980 ECB/RA6 1.0
1 02/01/1980 ECB/RA6 1.0
2 03/01/1980 ECB/RA6 1.0
3 04/01/1980 ECB/RA6 1.0
4 05/01/1980 ECB/RA6 1.0
. . . .
. . . .
. . . .
91 01/04/1980 ECB/RA6 4.0
还有我的代码:
df['date'] = pd.to_datetime(df['date'], format='%d/%m/%Y')
df = df.pivot(index='date', columns='ticker')
start_date = df.index.min() - pd.DateOffset(day=1)
end_date = df.index.max() + pd.DateOffset(day=31)
dates = pd.date_range(start_date, end_date, freq='d')
dates.name = 'date'
df = df.reindex(dates, method='ffill')
df = df.stack('ticker')
df = df.sortlevel(level=1)
df = df.reset_index()
我现在明白问题出在哪里了,但我相信这应该不是问题。 我 运行 来自@Pierre D 的以下代码(删除后重复):
df = df.set_index('date') # assuming 'date' is a proper Timestamp
df.index = df.index.to_period('Q') # turn index into PeriodIndex('Q')
df = df.set_index('ticker', append=True).squeeze()
df2 = df[df.duplicated( keep = False)]
我得到 df2 的以下输出:
value value2
date ticker
1997Q2 AAPL 46850 NaN
1997Q3 AAPL 46850 NaN
2003Q1 MSFT 10137 19/12/2003
2003Q2 MSFT 10137 19/12/2003
如您所见,索引不同,但在这些实例中 value 和 value2 是相等的。我相信这应该不是问题,但是当我现在 运行:
df.unstack()
我收到以下错误:“ValueError:索引包含重复条目,无法重塑”
先谢谢大家了!
更新
问题已修改,表明 'value'
旁边还有其他列,从一些评论中我收集到“扩大范围”可能是一个问题(注意:我们通常会处理类似的时间序列,其中有数千个列没有任何问题)。
所以,这是另一种看法。它执行相同的初始步骤,将所谓的 'date'
转变为它真正的样子:每季度 Period
。但随后它应用了一种在多索引 (time, key)
中按 key
组重新采样 time
的方法。这个问题有几个 Whosebug 答案,例如 .
全部加起来(举例):
# setup for example
txt = """ date ticker value value2
0 31/03/1980 ECB/RA6 1.0 NA
1 30/06/1980 another 4.0 NA
2 30/09/1980 ECB/RA6 2.0 19/12/2003
3 30/12/1980 ECB/RA6 3.0 19/12/2003
4 31/03/1981 ECB/RA6 2.0 19/12/2003
"""
df = pd.read_csv(io.StringIO(re.sub(r' +', '\t', txt)),
sep='\t', index_col=[0],
parse_dates=['date', 'value2'])
# set date as index and convert to quarterly periods
df = df.set_index('date')
df.index = df.index.to_period('Q')
# and now the new resample method (here monthly,
# but change to 'D' for daily)
df = df.groupby('ticker').resample('M').ffill()
如果您愿意,您可以 .reset_index()
,或者保持原样。这是没有重置索引的结果:
>>> df
ticker value value2
ticker date
ECB/RA6 1980-03 ECB/RA6 1.0 NaT
1980-04 ECB/RA6 1.0 NaT
1980-05 ECB/RA6 1.0 NaT
1980-06 ECB/RA6 1.0 NaT
1980-07 ECB/RA6 1.0 NaT
1980-08 ECB/RA6 1.0 NaT
1980-09 ECB/RA6 2.0 2003-12-19
1980-10 ECB/RA6 2.0 2003-12-19
1980-11 ECB/RA6 2.0 2003-12-19
1980-12 ECB/RA6 3.0 2003-12-19
1981-01 ECB/RA6 3.0 2003-12-19
1981-02 ECB/RA6 3.0 2003-12-19
1981-03 ECB/RA6 2.0 2003-12-19
another 1980-06 another 4.0 NaT
原回答
我会这样做:首先,将您的 date
设置为索引并将其转换为 PeriodIndex
,然后通过将每个股票行情成一列。然后重新取样:
df = df.set_index('date') # assuming 'date' is a proper Timestamp
df.index = df.index.to_period('Q') # turn index into PeriodIndex('Q')
df = df.set_index('ticker', append=True).squeeze().unstack() # make wide: 1 col per ticker
df.resample('D').ffill() # resample to daily, repeating the values
结果:
value
ticker ECB/RA6
date
1980-01-01 1.0
1980-01-02 1.0
1980-01-03 1.0
1980-01-04 1.0
1980-01-05 1.0
... ...
1981-03-27 2.0
1981-03-28 2.0
1981-03-29 2.0
1981-03-30 2.0
1981-03-31 2.0
如果改为按月重新采样,可能更容易检查结果:
df.resample('M').ffill() # resample to daily, repeating the values
# out:
ticker ECB/RA6
date
1980-01 1.0
1980-02 1.0
1980-03 1.0
1980-04 4.0
1980-05 4.0
1980-06 4.0
1980-07 2.0
1980-08 2.0
1980-09 2.0
1980-10 3.0
1980-11 3.0
1980-12 3.0
1981-01 2.0
1981-02 2.0
1981-03 2.0
顺便说一句,观察缺失数据会发生什么是很有用的:
# with input df as:
date ticker value
0 1980-03-31 ECB/RA6 1.0
1 1980-06-30 another 4.0
2 1980-09-30 ECB/RA6 2.0
# output:
ticker ECB/RA6 another
date
1980-01 1.0 NaN
1980-02 1.0 NaN
1980-03 1.0 NaN
1980-04 NaN 4.0
1980-05 NaN 4.0
1980-06 NaN 4.0
1980-07 2.0 NaN
1980-08 2.0 NaN
1980-09 2.0 NaN
最后说明:当然,如果你想得到又高又瘦的结果,你可以再次叠加结果table(如果你愿意,甚至可以重置索引):
print(df.resample('M').ffill().stack().reset_index())
# out:
date ticker 0
0 1980-01 ECB/RA6 1.0
1 1980-02 ECB/RA6 1.0
2 1980-03 ECB/RA6 1.0
3 1980-04 another 4.0
4 1980-05 another 4.0
5 1980-06 another 4.0
6 1980-07 ECB/RA6 2.0
7 1980-08 ECB/RA6 2.0
8 1980-09 ECB/RA6 2.0
我正在处理财务数据,其中一些是按季度格式化的,另一些是按天格式化的。我的模型每天都需要所有这些,因此我需要每天重复相同的季度值。我一直在使用这个
这是我的数据框头:
date ticker value
0 31/03/1980 ECB/RA6 1.0
1 30/06/1980 ECB/RA6 4.0
2 30/09/1980 ECB/RA6 2.0
3 30/12/1980 ECB/RA6 3.0
4 31/03/1981 ECB/RA6 2.0
这是我想要的输出:
date ticker value
0 01/01/1980 ECB/RA6 1.0
1 02/01/1980 ECB/RA6 1.0
2 03/01/1980 ECB/RA6 1.0
3 04/01/1980 ECB/RA6 1.0
4 05/01/1980 ECB/RA6 1.0
. . . .
. . . .
. . . .
91 01/04/1980 ECB/RA6 4.0
还有我的代码:
df['date'] = pd.to_datetime(df['date'], format='%d/%m/%Y')
df = df.pivot(index='date', columns='ticker')
start_date = df.index.min() - pd.DateOffset(day=1)
end_date = df.index.max() + pd.DateOffset(day=31)
dates = pd.date_range(start_date, end_date, freq='d')
dates.name = 'date'
df = df.reindex(dates, method='ffill')
df = df.stack('ticker')
df = df.sortlevel(level=1)
df = df.reset_index()
我现在明白问题出在哪里了,但我相信这应该不是问题。 我 运行 来自@Pierre D 的以下代码(删除后重复):
df = df.set_index('date') # assuming 'date' is a proper Timestamp
df.index = df.index.to_period('Q') # turn index into PeriodIndex('Q')
df = df.set_index('ticker', append=True).squeeze()
df2 = df[df.duplicated( keep = False)]
我得到 df2 的以下输出:
value value2
date ticker
1997Q2 AAPL 46850 NaN
1997Q3 AAPL 46850 NaN
2003Q1 MSFT 10137 19/12/2003
2003Q2 MSFT 10137 19/12/2003
如您所见,索引不同,但在这些实例中 value 和 value2 是相等的。我相信这应该不是问题,但是当我现在 运行:
df.unstack()
我收到以下错误:“ValueError:索引包含重复条目,无法重塑”
先谢谢大家了!
更新
问题已修改,表明 'value'
旁边还有其他列,从一些评论中我收集到“扩大范围”可能是一个问题(注意:我们通常会处理类似的时间序列,其中有数千个列没有任何问题)。
所以,这是另一种看法。它执行相同的初始步骤,将所谓的 'date'
转变为它真正的样子:每季度 Period
。但随后它应用了一种在多索引 (time, key)
中按 key
组重新采样 time
的方法。这个问题有几个 Whosebug 答案,例如
全部加起来(举例):
# setup for example
txt = """ date ticker value value2
0 31/03/1980 ECB/RA6 1.0 NA
1 30/06/1980 another 4.0 NA
2 30/09/1980 ECB/RA6 2.0 19/12/2003
3 30/12/1980 ECB/RA6 3.0 19/12/2003
4 31/03/1981 ECB/RA6 2.0 19/12/2003
"""
df = pd.read_csv(io.StringIO(re.sub(r' +', '\t', txt)),
sep='\t', index_col=[0],
parse_dates=['date', 'value2'])
# set date as index and convert to quarterly periods
df = df.set_index('date')
df.index = df.index.to_period('Q')
# and now the new resample method (here monthly,
# but change to 'D' for daily)
df = df.groupby('ticker').resample('M').ffill()
如果您愿意,您可以 .reset_index()
,或者保持原样。这是没有重置索引的结果:
>>> df
ticker value value2
ticker date
ECB/RA6 1980-03 ECB/RA6 1.0 NaT
1980-04 ECB/RA6 1.0 NaT
1980-05 ECB/RA6 1.0 NaT
1980-06 ECB/RA6 1.0 NaT
1980-07 ECB/RA6 1.0 NaT
1980-08 ECB/RA6 1.0 NaT
1980-09 ECB/RA6 2.0 2003-12-19
1980-10 ECB/RA6 2.0 2003-12-19
1980-11 ECB/RA6 2.0 2003-12-19
1980-12 ECB/RA6 3.0 2003-12-19
1981-01 ECB/RA6 3.0 2003-12-19
1981-02 ECB/RA6 3.0 2003-12-19
1981-03 ECB/RA6 2.0 2003-12-19
another 1980-06 another 4.0 NaT
原回答
我会这样做:首先,将您的 date
设置为索引并将其转换为 PeriodIndex
,然后通过将每个股票行情成一列。然后重新取样:
df = df.set_index('date') # assuming 'date' is a proper Timestamp
df.index = df.index.to_period('Q') # turn index into PeriodIndex('Q')
df = df.set_index('ticker', append=True).squeeze().unstack() # make wide: 1 col per ticker
df.resample('D').ffill() # resample to daily, repeating the values
结果:
value
ticker ECB/RA6
date
1980-01-01 1.0
1980-01-02 1.0
1980-01-03 1.0
1980-01-04 1.0
1980-01-05 1.0
... ...
1981-03-27 2.0
1981-03-28 2.0
1981-03-29 2.0
1981-03-30 2.0
1981-03-31 2.0
如果改为按月重新采样,可能更容易检查结果:
df.resample('M').ffill() # resample to daily, repeating the values
# out:
ticker ECB/RA6
date
1980-01 1.0
1980-02 1.0
1980-03 1.0
1980-04 4.0
1980-05 4.0
1980-06 4.0
1980-07 2.0
1980-08 2.0
1980-09 2.0
1980-10 3.0
1980-11 3.0
1980-12 3.0
1981-01 2.0
1981-02 2.0
1981-03 2.0
顺便说一句,观察缺失数据会发生什么是很有用的:
# with input df as:
date ticker value
0 1980-03-31 ECB/RA6 1.0
1 1980-06-30 another 4.0
2 1980-09-30 ECB/RA6 2.0
# output:
ticker ECB/RA6 another
date
1980-01 1.0 NaN
1980-02 1.0 NaN
1980-03 1.0 NaN
1980-04 NaN 4.0
1980-05 NaN 4.0
1980-06 NaN 4.0
1980-07 2.0 NaN
1980-08 2.0 NaN
1980-09 2.0 NaN
最后说明:当然,如果你想得到又高又瘦的结果,你可以再次叠加结果table(如果你愿意,甚至可以重置索引):
print(df.resample('M').ffill().stack().reset_index())
# out:
date ticker 0
0 1980-01 ECB/RA6 1.0
1 1980-02 ECB/RA6 1.0
2 1980-03 ECB/RA6 1.0
3 1980-04 another 4.0
4 1980-05 another 4.0
5 1980-06 another 4.0
6 1980-07 ECB/RA6 2.0
7 1980-08 ECB/RA6 2.0
8 1980-09 ECB/RA6 2.0