我有一个文件,每十分钟就有一个盘中价格。 [0:41]一天的时间。每个日期重复42次。下面的多指数应该将重复的日期“折叠”为一次。
有62,035行x 3列:[date, time, price]
。
我想写一个函数来获得十分钟价格的差异,将差异限制在每个唯一的日期。
换句话说,09:30是每天的第一次,16:20是最后一次:我不能重叠16:20 - 09:30之间价格天数之间的差异。对于数据框中的每个唯一日期,差异应从09:40 - 09:30开始,以16:20 - 16:10结束。
这是我的尝试。任何建议都将不胜感激。
def diffSeries(rounded,data):
'''This function accepts a column called rounded from 'data'
The 2nd input 'data' is a dataframe
'''
df=rounded.shift(1)
idf=data.set_index(['date', 'time'])
data['diff']=['000']
for i in range(0,length(rounded)):
for day in idf.index.levels[0]:
for time in idf.index.levels[1]:
if idf.index.levels[1]!=1620:
data['diff']=rounded[i]-df[i]
else:
day+=1
time+=2
data[['date','time','price','II','diff']].to_csv('final.csv')
return data['diff']
然后我打电话给:
data=read_csv('file.csv')
rounded=roundSeries(data['price'],5)
diffSeries(rounded,data)
在追溯上 - 我得到Assertion Error
。
答案 0 :(得分:1)
您可以使用groupby然后申请实现您的目标:
diffs = data.groupby(lambda idx: idx[0]).apply(lambda row: row - row.shift(1))
有关完整示例,假设您创建了11月14日至11月16日的测试数据集:
import pandas as pd
from numpy.random import randn
from datetime import time
# Create date range with 10 minute intervals, and filter out irrelevant times
times = pd.bdate_range(start=pd.datetime(2012,11,14,0,0,0),end=pd.datetime(2012,11,17,0,0,0), freq='10T')
filtered_times = [x for x in times if x.time() >= time(9,30) and x.time() <= time(16,20)]
prices = randn(len(filtered_times))
# Create MultiIndex and data frame matching the format of your CSV
arrays = [[x.date() for x in filtered_times]
,[x.time() for x in filtered_times]]
tuples = zip(*arrays)
m_index = pd.MultiIndex.from_tuples(tuples, names=['date', 'time'])
data = pd.DataFrame({'prices': prices}, index=m_index)
你应该得到一个像这样的DataFrame:
prices
date time
2012-11-14 09:30:00 0.696054
09:40:00 -1.263852
09:50:00 0.196662
10:00:00 -0.942375
10:10:00 1.915207
如上所述,您可以通过按第一个索引分组然后减去每行的前一行来获得差异:
diffs = data.groupby(lambda idx: idx[0]).apply(lambda row: row - row.shift(1))
这给你一些类似的东西:
prices
date time
2012-11-14 09:30:00 NaN
09:40:00 -1.959906
09:50:00 1.460514
10:00:00 -1.139036
10:10:00 2.857582
由于您按日期分组,因此该功能不适用于16:20 - 09:30。
您可能需要考虑使用TimeSeries而不是DataFrame,因为它可以为您提供这种数据的更大灵活性。假设您已经从CSV文件加载了DataFrame,您可以轻松地将其转换为TimeSeries并执行类似的功能以获得差异:
dt_index = pd.DatetimeIndex([datetime.combine(i[0],i[1]) for i in data.index])
# or dt_index = pd.DatetimeIndex([datetime.combine(i.date,i.time) for i in data.index])
# if you don't have an multi-level index on data yet
ts = pd.Series(data.prices.values, dt_index)
diffs = ts.groupby(lambda idx: idx.date()).apply(lambda row: row - row.shift(1))
但是,您现在可以访问内置时间序列功能,例如重新采样。有关pandas中时间序列的更多信息,请参阅here。
答案 1 :(得分:0)
@MattiJohn的结构给出了一个长度为86,772的过滤列表 - 当超过1/3 / 2007-8 / 30/2012运行42次(间隔10分钟)时。观察数据清理问题。
这里来自csv的价格数据是长度:62,034。 因此,只需从.csv导入,如下所示:
filtered_times = [x for x in times if x.time() >= time(9,30) and x.time() <= time(16,20)]
DF=pd.read_csv('MR10min.csv')
prices = DF.price
# I.E. rather than the generic: prices = randn(len(filtered_times)) above.
实际数据达不到“应该”的长度这一事实意味着存在数据清理问题。我们通常没有充分的时间,因为bdate_time会产生(市场半天等假期)。
您的解决方案很优雅。但我不确定如何克服实际数据与先验规定数据帧之间的不匹配。
您的第二个TimesSeries建议似乎仍然需要构建类似于第一个的日期时间索引。例如,如果我使用以下两行来获取感兴趣的实际数据:
DF=pd.read_csv('MR10min.csv')
data=pd.DF.set_index(['date','time'])
dt_index = pd.DatetimeIndex([datetime.combine(i[0],i[1]) for i in data.index])
它将生成一个:
TypeError: combine() argument 1 must be datetime.date, not str
如何根据实际可用数据完全通知bdate_time数组?
感谢(@MattiJohn)和有兴趣继续讨论的人。