如何将另一个数据框的当月最后3个工作日(自定义日历)的数据替换为另一个?
我正在尝试对投资进行一些数据分析(具体交易恒指期货)。本月和下个月(数据框B)有两个用于期货结算的数据框。
数据框A看起来像这样
Date Value
2/1/2019 123
3/1/2019 456
...
29/1/2019 785
30/1/2019 424
31/1/2019 456
1/2/2019 484
...
27/2/2019 465 (last day for available data)
数据框B看起来像这样
Date Value
2/1/2019 654
3/1/2019 424
...
29/1/2019 544
30/1/2019 111
31/1/2019 222
1/2/2019 333
...
27/2/2019 444 (last day for available data)
我想在每个月的最后3个工作日修改数据框A。数据应替换为数据框B中的数据
即
Date Value
2/1/2019 123
3/1/2019 456
...
29/1/2019 544
30/1/2019 111
31/1/2019 222
1/2/2019 484
...
27/2/2019 444 (last day for data available data)
我在网上查找并已经制作了一个自定义日历(如下所示,为简单起见,我删除了大部分假期)。
我也设法修改了上个月的数据。 但是如果今天是最后三个工作日之一,例如今天今天是2019年2月27日,我不知道如何替换数据框B中的数据(值= 444)
import pandas as pd
from pandas.tseries.offsets import CustomBusinessDay
from pandas.tseries.offsets import BMonthEnd
from datetime import date
from pandas.tseries.holiday import AbstractHolidayCalendar, nearest_workday, Holiday
import numpy as np
import quandl
=================Holiday=============================
class hktradingholiday2019(AbstractHolidayCalendar):
rules = [
Holiday('New Years Day', year=2019, month=1, day=1, observance=nearest_workday),
]
hktradeholiday2019 = CustomBusinessDay(calendar=hktradingholiday2019())
hktradeday2019 = pd.date_range(start="1/1/2019",end="31/12/2019", freq=hktradeholiday2019)
=======================================================
dataframeA = quandl.get("CHRIS/HKEX_HSI1")
dataframeB = quandl.get("CHRIS/HKEX_HSI2")
endoflastmonth= dataframeB.index[-1] - pd.tseries.offsets.MonthEnd(1)
df = dataframeB[:endoflastmonth]
df = df.groupby(df.index.month).tail(3)
dataframeA.loc[df.index] = df
有人会建议我如何获取2019年2月27日的数据,替换为数据框B中的值吗?
我的第一个想法是使用if语句检查最后一行是否为3个工作日之一(因此,我做了很多事情)。但是我不知道该怎么做。
答案 0 :(得分:2)
我相信您需要:
class hktradingholiday2019(AbstractHolidayCalendar):
rules = [
Holiday('New Years Day', year=2019, month=1, day=1, observance=nearest_workday),
]
hktradeholiday2019 = CustomBusinessDay(calendar=hktradingholiday2019())
hktradeday2019 = pd.date_range(start="1/1/2019",end="31/12/2019", freq=hktradeholiday2019)
print (hktradeday2019)
#create DatetimeIndex
dfA['Date'] = pd.to_datetime(dfA['Date'], dayfirst=True)
dfB['Date'] = pd.to_datetime(dfB['Date'], dayfirst=True)
dfA = dfA.set_index('Date')
dfB = dfB.set_index('Date')
#print (dfA)
#print (dfB)
#get last 3 days per months for hktradeday2019
s = hktradeday2019.to_series()
lastdays = s.groupby(s.index.month).tail(3)
#print (lastdays)
#replace only last 3 month values if exist
#same indices, so is possible assign by same idx in dfAb and dfB
idx = dfA.index.intersection(lastdays.index)
dfA.loc[idx] = dfB.loc[idx].combine_first(dfA.loc[idx])
print (dfA)
Value
Date
2019-01-02 123
2019-01-03 456
2019-01-29 544
2019-01-30 111
2019-01-31 222
2019-02-01 484
2019-02-27 444
答案 1 :(得分:0)
要将数据从A
复制到B
,可以使用:
A.mask(criterionlist, B)
但是成功的关键是如何定义以上criterionlist
。
要考虑自定义业务日历,必须对其进行定义。 为了演示的目的,我准备了一个与 Jan 30 的日历, 一个假期(此日期在以下示例中的日期中):
class ExBusinessCalendar(AbstractHolidayCalendar):
rules = [
Holiday('New Years Day', month=1, day=1),
Holiday('My Extra Free Day', month=1, day=30),
EasterMonday,
Holiday('Labour Day', month=5, day=1)
]
然后,您必须定义以下辅助变量,与 我们的自定义日历:
offset
- CustomBusinessMonthEnd 的偏移量。cbd
-一个 CustomBusinessDay 偏移量。isBusinessDay
-检查当前日期是否为
“按偏移量”(是否是我们日历中的实际工作日)。我介绍了最后一种功能,可以过滤掉非企业业务 天,如果源数据包括在内。
有关如何定义它们的详细信息,请参见下面的脚本。
具有上述变量和两个DataFrame,条件列表可以 表示为:
A.Date.map(lambda d: offset.rollforward(d) <= d + 2 * cbd
and isBusinessDay(d))
此功能:
offset.rollforward(d)
-的最后一个工作日
本月。d + 2 * cbd
-当前日期+ 2个工作日。d
)必须为
我们日历中的一个工作日。在下面的示例中,它过滤掉了
2019-01-30 的行。因此整个脚本如下所示:
import pandas as pd
from pandas.tseries.holiday import AbstractHolidayCalendar, Holiday, EasterMonday, Easter
# Example business calendar
class ExBusinessCalendar(AbstractHolidayCalendar):
rules = [
Holiday('New Years Day', month=1, day=1),
Holiday('My Extra Free Day', month=1, day=30),
EasterMonday,
Holiday('Labour Day', month=5, day=1)
]
# Source data for A and B
datA = [ ['2/1/2019', 120], ['3/1/2019', 450], ['26/1/2019', 760],
['27/1/2019', 770], ['28/1/2019', 780], ['29/1/2019', 790],
['30/1/2019', 420], ['31/1/2019', 450], ['1/2/2019', 480],
['2/2/2019', 480] ]
datB = [ ['2/1/2019', 122], ['3/1/2019', 453], ['26/1/2019', 764],
['27/1/2019', 775], ['28/1/2019', 786], ['29/1/2019', 797],
['30/1/2019', 428], ['31/1/2019', 451], ['1/2/2019', 482],
['2/2/2019', 483] ]
# Create DataFrames
A = pd.DataFrame(data=datA, columns=['Date', 'Value'])
A.Date = pd.to_datetime(A.Date, dayfirst=True)
B = pd.DataFrame(data=datB, columns=['Date', 'Value'])
B.Date = pd.to_datetime(B.Date, dayfirst=True)
# Auxiliary variables
offset = pd.offsets.CustomBusinessMonthEnd(calendar=ExBusinessCalendar())
cbd = pd.offsets.CustomBusinessDay(calendar=ExBusinessCalendar())
isBusinessDay = pd.offsets.CustomBusinessDay(calendar=ExBusinessCalendar()).onOffset
# Compute the result
A.mask(A.Date.map(lambda d: offset.rollforward(d) <= d + 2 * cbd
and isBusinessDay(d)), B)
结果是:
Date Value
0 2019-01-02 120
1 2019-01-03 450
2 2019-01-26 760
3 2019-01-27 770
4 2019-01-28 786
5 2019-01-29 797
6 2019-01-30 420
7 2019-01-31 451
8 2019-02-01 480
9 2019-02-02 480
如您所见,从B
复制的值是 2019-01-28 , 2019-01-29
和 2019-01-31 (在我的示例数据中,结尾处没有 0 )。
2019-01-30 的值未复制,如在我的自定义业务日历中一样 这不是工作日。
要使用以上结果修改A
,请将最后一条指令更改为:
A = A.mask(A.Date.map( ...