如何用Python(Pandas)有效地创建“日历”?

db2dz4w8  于 2023-03-11  发布在  Python
关注(0)|答案(1)|浏览(137)

我需要为不同债券的息票创建一个“日历”。想法如下:息票债券有三种类型。2第一种每年付息票,第二种每季度付息票,第三种每月付息票。3我有下表

表1

| 债券|类型|发布日期|到期日|
| - ------|- ------|- ------|- ------|
| 粘合A|每季|2022年1月1日|2032年1月1日|
| 粘合B|每月|2020年6月6日|二〇二五年六月六日|
在此表中,每行都是唯一的,每个焊接只出现一次,因此表中没有重复项。
最后我希望得到这样的表

表二

| 债券|类型|发布日期|到期日|息票日期|
| - ------|- ------|- ------|- ------|- ------|
| 粘合A|每季|2022年1月1日|2032年1月1日|2022年4月1日|
| 粘合A|每季|2022年1月1日|2032年1月1日|2022年7月1日|
| 粘合A|每季|2022年1月1日|2032年1月1日|二○二二年十月一日|
| 粘合A|每季|2022年1月1日|2032年1月1日|2023年1月1日|
显然,这个表格应该更长,但我希望预期结果的概念是明确的。
在这里我应该指出,我不需要日期与天的精度,我需要有正确的年份和月份,这就是为什么你会看到,我做了所有的优惠券日期与第一天的一个月。
我尝试使用pandom.Timedelta来完成这个任务,但是“M”(月)和“Y”(年)值被删除了,所以我不得不在没有它们的情况下处理。

我尝试完成以下任务:

我的进口

import numpy as np
import pandas as pd
import datetime

因此,表1是我的 Dataframe ,我根据键类型将其分为三个较小的帧。所有日期均为datetime 64 [ns]格式

annual_df   = df[df.Type == 'Annually'].reset_index(drop = True)
quarter_ df = df[df.Type == 'Quarterly'].reset_index(drop = True)
month_df    = df[df.Type == 'Monthly'].reset_index(drop = True)

这是我的代码为年息票债券我倒回去,因为在到期日coupond是肯定支付

temp = pd.DataFrame(columns={'Bond', 'Type', 'Release date', 'Maturity date', 'Coupon date'})
for i in annual_df.index:
    stop_date = annual_df['Release date'][i]
    _date     = annual_df['Maturity date'][i] # the date that will be passed into 'Coupon date' column
    c = 0 # a constant
    print(i, 'out of',  annual_df.index.max()) # to track the iteration
    while _date > stop_date:
        arr = {'Bond':annual_df.Bond[i], 'Type':annual_df.Type[i], 'Release date':stop_date,
               'Maturity date':annual_df['Maturity date'][i], 'Coupon date': _date}
        temp = temp.append(arr, ignore_index = True)
        c += 1
        _date = datetime.datetime(annual_df['Maturity date'][i].year - c, ['Maturity date'][i].month, 1)

annual_df = temp

所以,这段代码在我的数据集上运行了大约一个小时,这个数据集包含25000个不同的债券,这是相当多的,但是没有下面的季度支付券代码运行的时间长

temp = pd.DataFrame(columns={'Bond', 'Type', 'Release date', 'Maturity date', 'Coupon date'})
for i in quarter_df.index:
    stop_date = quarter_df['Release date'][i]
    _date     = quarter_df['Maturity date'][i] # the date that will be passed into 'Coupon date' column
    c = 0 # a constant
    print(i, 'out of',  quarter_df.index.max()) # to track the iteration
    if quarter_df['Maturity date'][i].month < 4:
        while _date > stop_date:
            arr1 = {'Bond':annual_df.Bond[i], 'Type':annual_df.Type[i], 'Release date':stop_date,
               'Maturity date':annual_df['Maturity date'][i], 'Coupon date': _date}

            _date = datetime.datetime(annual_df['Maturity date'][i].year - c, 
                                     ['Maturity date'][i].month + 3,1)
            arr2 = {'Bond':annual_df.Bond[i], 'Type':annual_df.Type[i], 'Release date':stop_date,
               'Maturity date':annual_df['Maturity date'][i], 'Coupon date': _date}

            _date = datetime.datetime(annual_df['Maturity date'][i].year - c, 
                                     ['Maturity date'][i].month + 6,1)
            arr3 = {'Bond':annual_df.Bond[i], 'Type':annual_df.Type[i], 'Release date':stop_date,
               'Maturity date':annual_df['Maturity date'][i], 'Coupon date': _date}

            _date = datetime.datetime(annual_df['Maturity date'][i].year - c, 
                                     ['Maturity date'][i].month + 9,1)
            arr4 = {'Bond':annual_df.Bond[i], 'Type':annual_df.Type[i], 'Release date':stop_date,
               'Maturity date':annual_df['Maturity date'][i], 'Coupon date': _date}

            c += 1
            _date = datetime.datetime(annual_df['Maturity date'][i].year - c, 
                                     ['Maturity date'][i].month,1)
            temp = temp.append(arr1, ignore_index=True)
            temp = temp.append(arr2, ignore_index=True)
            temp = temp.append(arr3, ignore_index=True)
            temp = temp.append(arr4, ignore_index=True)

    elif quarter_df['Maturity date'][i].month > 3 and quarter_df['Maturity date'][i].month < 7:
            #the same if but just with different _date month values, literaly Ctrl+C, Ctrl+V
    elif quarter_df['Maturity date'][i].month > 6 and quarter_df['Maturity date'][i].month < 10:
            #again, the same
    else:
            #same

所以,根据我的计算,这部分每次迭代大约需要2秒,我有一个34000行的数据集,这个代码总共工作了18.3小时。
你知道如何优化这段代码吗?你知道有没有其他方法可以做同样的事情,但是更短更快?

bejyjqdl

bejyjqdl1#

您可以为每行生成一系列息票日期,然后将其展开:

def coupon_dates(row: pd.Series):
    n = {"Monthly": 1, "Quarterly": 3, "Annually": 12}[row["Type"]]

    # Generate a series of coupon dates from Release date to Maturity date
    return pd.date_range(
        row["Release date"],
        row["Maturity date"],
        freq=pd.DateOffset(months=n),
        inclusive="right",
    )

df["Coupon date"] = df.apply(coupon_dates, axis=1)
df = df.explode("Coupon date")

相关问题