我有一个
DataFrame
存储每日数据,如下所示:
Date Open High Low Close Volume
2010-01-04 38.660000 39.299999 38.509998 39.279999 1293400
2010-01-05 39.389999 39.520000 39.029999 39.430000 1261400
2010-01-06 39.549999 40.700001 39.020000 40.250000 1879800
2010-01-07 40.090000 40.349998 39.910000 40.090000 836400
2010-01-08 40.139999 40.310001 39.720001 40.290001 654600
2010-01-11 40.209999 40.520000 40.040001 40.290001 963600
2010-01-12 40.160000 40.340000 39.279999 39.980000 1012800
2010-01-13 39.930000 40.669998 39.709999 40.560001 1773400
2010-01-14 40.490002 40.970001 40.189999 40.520000 1240600
2010-01-15 40.570000 40.939999 40.099998 40.450001 1244200
我打算做的是将其合并到每周的数据中。分组后:
应该是这样的:
Date Open High Low Close Volume
2010-01-04 38.660000 40.700001 38.509998 40.290001 5925600
2010-01-11 40.209999 40.970001 39.279999 40.450001 6234600
目前,我的代码片段如下,我应该使用哪个函数将基于每日的数据映射到预期的基于每周的数据?非常感谢!
import pandas_datareader.data as web
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2016, 12, 31)
f = web.DataReader("MNST", "yahoo", start, end, session=session)
print f
您可以按如下所示
resample
(每周)、offset
(轮班)和apply
聚合规则[已更新以反映pandas 1.1中的更改]:
logic = {'Open' : 'first',
'High' : 'max',
'Low' : 'min',
'Close' : 'last',
'Volume': 'sum'}
df = pd.read_clipboard(parse_dates=['Date'], index_col=['Date'])
df = df.resample('W').apply(logic)
# changes in Pandas 1.1
from pandas.tseries.frequencies import to_offset
df.index = df.index - to_offset('6D')
获得:
Open High Low Close Volume
Date
2010-01-04 38.660000 40.700001 38.509998 40.290001 5925600
2010-01-11 40.209999 40.970001 39.279999 40.450001 6234600
一般来说,假设您有指定形式的数据框,则需要执行以下步骤:
Date
放入索引resample
索引。 您所面临的是对不同列应用不同函数的情况。 参见。
您可以通过多种方式重新采样。例如您可以取值的平均值或计数等。检查pandas 重新采样。
您还可以应用自定义聚合器(检查相同的链接)。 考虑到这一点,您的案例的代码片段可以如下所示:
f['Date'] = pd.to_datetime(f['Date'])
f.set_index('Date', inplace=True)
f.sort_index(inplace=True)
def take_first(array_like):
return array_like[0]
def take_last(array_like):
return array_like[-1]
output = f.resample('W', # Weekly resample
how={'Open': take_first,
'High': 'max',
'Low': 'min',
'Close': take_last,
'Volume': 'sum'},
loffset=pd.offsets.timedelta(days=-6)) # to put the labels to Monday
output = output[['Open', 'High', 'Low', 'Close', 'Volume']]
此处,
W
表示每周重新采样,默认情况下从周一到周日。为了将标签保持为星期一,使用 loffset
。
有几个预定义的日期说明符。看一下 pandas offsets。您甚至可以定义自定义偏移量(参见)。
回到重采样方法。在这里,对于
Open
和 Close
,您可以指定自定义方法来获取第一个值等,并将函数句柄传递给 how
参数。
这个答案基于这样的假设:数据似乎是每日的,即每天只有 1 个条目。此外,非工作日没有数据。即周六和周日。因此,将本周的最后一个数据点作为周五的数据点就可以了。如果您愿意,可以使用工作周而不是“W”。此外,对于更复杂的数据,您可能需要使用
groupby
对每周数据进行分组,然后处理其中的时间索引。
顺便说一句,解决方案的要点可以在以下位置找到: https://gist.github.com/prithwi/339f87bf9c3c37bb3188
我有完全相同的问题,并在这里找到了一个很好的解决方案。
每周代码发布在下面。
import pandas as pd
import numpy as np
print('*** Program Started ***')
df = pd.read_csv('15-06-2016-TO-14-06-2018HDFCBANKALLN.csv')
# ensuring only equity series is considered
df = df.loc[df['Series'] == 'EQ']
# Converting date to pandas datetime format
df['Date'] = pd.to_datetime(df['Date'])
# Getting week number
df['Week_Number'] = df['Date'].dt.week
# Getting year. Weeknum is common across years to we need to create unique index by using year and weeknum
df['Year'] = df['Date'].dt.year
# Grouping based on required values
df2 = df.groupby(['Year','Week_Number']).agg({'Open Price':'first', 'High Price':'max', 'Low Price':'min', 'Close Price':'last','Total Traded Quantity':'sum'})
# df3 = df.groupby(['Year','Week_Number']).agg({'Open Price':'first', 'High Price':'max', 'Low Price':'min', 'Close Price':'last','Total Traded Quantity':'sum','Average Price':'avg'})
df2.to_csv('Weekly_OHLC.csv')
print('*** Program ended ***')
使用最近的 pandas API 添加到 @Stefan 的答案,因为
loffset
自版本 1.1.0 以来已被弃用,后来被删除。
df = pd.read_clipboard(parse_dates=['Date'], index_col=['Date'])
logic = {'Open' : 'first',
'High' : 'max',
'Low' : 'min',
'Close' : 'last',
'Volume': 'sum'}
dfw = df.resample('W').apply(logic)
# set the index to the beginning of the week
dfw.index = dfw.index - pd.tseries.frequencies.to_offset("6D")
import pandas as pd
from pandas.tseries.frequencies import to_offset
df = pd.read_csv('your_ticker.csv')
logic = {'<Open>' : 'first',
'<High>' : 'max',
'<Low>' : 'min',
'<Close>' : 'last',
'<Volume>': 'sum'}
df['<DTYYYYMMDD>'] = pd.to_datetime(df['<DTYYYYMMDD>'])
df = df.set_index('<DTYYYYMMDD>')
df = df.sort_index()
df = df.resample('W').apply(logic)
df.index = df.index - pd.tseries.frequencies.to_offset("6D")
一开始我根据上述答案使用 df.resample() ,但是当错过一周时它会填充 NaN ,对此不满意,经过一番研究,我使用 groupby() 而不是 resample() 。谢谢你的分享。
我的原始数据是:
c date h l o
260 6014.78 20220321 6053.90 5984.79 6030.43
261 6052.59 20220322 6099.53 5995.22 6012.17
262 6040.86 20220323 6070.85 6008.26 6059.11
263 6003.05 20220324 6031.73 5987.40 6020.00
264 5931.33 20220325 6033.04 5928.72 6033.04
265 5946.98 20220328 5946.98 5830.93 5871.35
266 5900.04 20220329 5958.71 5894.82 5950.89
267 6003.05 20220330 6003.05 5913.08 5913.08
268 6033.04 20220331 6059.11 5978.27 5993.92
269 6126.91 20220401 6134.74 5975.66 6006.96
270 6149.08 20220406 6177.77 6106.05 6126.91
271 6134.74 20220407 6171.25 6091.71 6130.83
272 6151.69 20220408 6160.82 6096.93 6147.78
273 6095.62 20220411 6166.03 6072.15 6164.73
274 6184.28 20220412 6228.62 6049.99 6094.32
275 6119.09 20220413 6180.37 6117.79 6173.85
276 6188.20 20220414 6201.24 6132.13 6150.38
277 6173.85 20220415 6199.93 6137.35 6137.35
278 6124.31 20220418 6173.85 6108.66 6173.85
279 6065.63 20220419 6147.78 6042.16 6124.31
我不在乎日期是不是星期一,所以我没有处理它,代码是:
data['Date'] = pd.to_datetime(data['date'], format="%Y%m%d")
# Refer to: https://www.techtrekking.com/how-to-convert-daily-time-series-data-into-weekly-and-monthly-using-pandas-and-python/
# and here: https://stackoverflow.com/a/60518425/5449346
# and this: https://github.com/pandas-dev/pandas/issues/11217#issuecomment-145253671
logic = {'o' : 'first',
'h' : 'max',
'l' : 'min',
'c' : 'last',
'Date': 'first',
}
data = data.groupby([data['Date'].dt.year, data['Date'].dt.week]).agg(logic)
data.set_index('Date', inplace=True)
结果是,在 2022.01.31 上 resample() 不会产生 NaN:
l o h c
Date
2021-11-29 6284.68 6355.09 6421.59 6382.47
2021-12-06 6365.52 6372.04 6700.62 6593.70
2021-12-13 6445.06 6593.70 6690.19 6450.28
2021-12-20 6415.07 6437.24 6531.12 6463.31
2021-12-27 6463.31 6473.75 6794.50 6649.77
2022-01-04 6625.00 6649.77 7089.18 7055.27
2022-01-10 6804.93 7055.27 7181.75 6808.84
2022-01-17 6769.73 6776.25 7098.30 6919.67
2022-01-24 6692.80 6906.63 7048.76 6754.08
2022-02-07 6737.13 6811.45 7056.58 7023.98
2022-02-14 6815.36 7073.53 7086.57 6911.85
2022-02-21 6634.12 6880.56 6904.03 6668.02
2022-02-28 6452.88 6669.33 6671.93 6493.30
2022-03-07 5953.50 6463.31 6468.53 6228.62
2022-03-14 5817.90 6154.30 6205.15 6027.82
2022-03-21 5928.72 6030.43 6099.53 5931.33
2022-03-28 5830.93 5871.35 6134.74 6126.91
2022-04-06 6091.71 6126.91 6177.77 6151.69
2022-04-11 6049.99 6164.73 6228.62 6173.85
2022-04-18 6042.16 6173.85 6173.85 6065.63
不是直接答案,但假设这些列是日期(表格的转置),没有丢失日期。
'''sum up daily results in df to weekly results in wdf'''
wdf = pd.DataFrame(index = df.index)
for i in range(len(df.columns)):
if (i!=0) & (i%7==0):
wdf['week'+str(i//7)]= df[df.columns[i-7:i]].sum(axis = 1)
上述代码中有一个限制,如果周一有假期,则不会获取该数据,因此我创建了一个函数来克服该限制。希望有帮助。将日期名称命名为“星期一”或您想要的任何名称
def convert_to_weekly(df,day):
#Initialising dataframe to store converted data
converted_data = pd.DataFrame()
converted_data_temp = pd.DataFrame({"Date":[0],"Open":[0],"High":[0],"Low":[0],"Close":[0],"Volume":[0]})
#Converting Date to Datetime and setting that as index
df['Date str'] = df['Date']
df['Date'] = df['Date'].map(lambda a : datetime.datetime.strptime(a, '%d/%m/%Y'))
df.set_index('Date', inplace=True)
df.sort_index(inplace=True)
#Finding first date which is our start Day
start_date = df.index[0]
for i in range(0,6):
start_date = start_date + timedelta(days=i)
day_name = start_date.strftime("%A")
if(day_name == day):
break
#Taking a week back to include middle data
start_date = start_date - timedelta(days=7)
while(start_date < df.index[-1]):
stop_date = start_date + timedelta(days=7)
data_temp = df[start_date:stop_date - timedelta(days=1)]
if(data_temp.size == 0):
start_date = start_date + timedelta(days=7)
continue
data_temp = data_temp.reset_index()
converted_data_temp['Date'] = data_temp['Date str'].iloc[0]
converted_data_temp['Open'] = data_temp['Open'].iloc[0]
converted_data_temp['High'] = data_temp['High'].max()
converted_data_temp['Low'] = data_temp['Low'].min()
converted_data_temp['Close'] = data_temp['Close'].iloc[-1]
try:
converted_data_temp['Volume'] = data_temp['Volume'].sum()
except:
pass
converted_data = pd.concat([converted_data, converted_data_temp])
start_date = start_date + timedelta(days=7)
converted_data = converted_data.reset_index()
converted_data = converted_data.drop(['index'],axis=1)
return converted_data
df_w = Convert_to_weekly(df, "星期一")