如何使用熊猫将行的开始和结束日期转换为月度块?

时间:2019-08-21 05:20:31

标签: python pandas time-series

这是我拥有的数据集

  id      start        end
0  A   1-Jan-19  31-Dec-19
1  A   1-Jan-20  31-Dec-20
2  B  13-Jun-19  19-Nov-19
df = pd.DataFrame({'id': ["A", "A", "B"],
           'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
           'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]})

这是我需要的数据集

   id      start        end
0   A   1-Jan-19  31-Jan-19
1   A   1-Feb-19  28-Feb-19
2   A   1-Mar-19  31-Mar-19
3   A   1-Apr-19  30-Apr-19
4   A   1-May-19  31-May-19
5   A   1-Jun-19  30-Jun-19
6   A   1-Jul-19  31-Jul-19
7   A   1-Aug-19  31-Aug-19
8   A   1-Sep-19  30-Sep-19
9   A   1-Oct-19  31-Oct-19
10  A   1-Nov-19  30-Nov-19
11  A   1-Dec-19  31-Dec-19
12  B  13-Jun-19  30-Jun-19
13  B   1-Jul-19  31-Jul-19
14  B   1-Aug-19  31-Aug-19
15  B   1-Sep-19  30-Sep-19
16  B   1-Oct-19  31-Oct-19
17  B   1-Nov-19  19-Nov-19

数据按ID分组,时间块分布在几个月内。我尝试使用重新采样和填充熊猫方法没有成功。是否可以使用Pandas做到这一点,或者我需要通过对日期系列进行合并并过滤日期重叠的地方来解决该方法?

谢谢

3 个答案:

答案 0 :(得分:0)

这是解决方案。

from dateutil.relativedelta import relativedelta
import pandas as pd
import numpy as np

df1 = pd.DataFrame({'id': ["A", "A", "B"],
           'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
           'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]})

df1["start"] = df1["start"].apply(lambda x: datetime.strptime(x, "%d-%b-%y") )
df1["end"] = df1["end"].apply(lambda x: datetime.strptime(x, "%d-%b-%y") )
df1["rows"] = abs((df1["start"]-df1["end"])/np.timedelta64(1,'M')).astype(int)
df_new = pd.DataFrame([df1.ix[idx] 
                       for idx in df1.index 
                       for i in range(df1.ix[idx]['rows'] +1)])
df_new = df_new.reset_index(drop=True)
groups = df_new.groupby(["start", "end"],as_index = False)
grouped_df = groups.apply(lambda x: x.reset_index(drop = True)).reset_index().drop('level_0',axis = 1)
grouped_df["start"] =grouped_df.apply(lambda row : row["start"]+  relativedelta(months=row["level_1"]), axis =1)
grouped_df.drop(['level_1', 'rows'], axis =1 ,inplace = True)
grouped_df

我假设您跳过了第二个输入行的处理。
如果不是这种情况,请告诉我。

输入:

enter image description here

输出:

[1]: https://i.stack.imgur.com/JKfXz.png

答案 1 :(得分:0)

我认为我的解决方案不是优雅的解决方案。但是,它将返回所需的输出。第一步,我只是导入包并像您一样制作df数据框。

import pandas as pd
import datetime
from dateutil.rrule import rrule, MONTHLY

df = pd.DataFrame(
    {
        'id': ["A", "A", "B"],
        'start': ["1-Jan-19", "1-Jan-20", "13-Jun-19"],
        'end': ["31-Dec-19", "31-Dec-20", "19-Nov-19"]
    }
)

在第二部分中,我遍历df数据帧中的每一行,并尝试为第二个数据帧创建一个项-我将其称为df_2。项目存储在data_items列表中。

data_items = []
for id_, start, end in zip(df['id'], df['start'], df['end']):
    start_dt = datetime.datetime.strptime(start, '%d-%b-%y')
    end_dt = datetime.datetime.strptime(end, '%d-%b-%y')
    start_dates = [dt for dt in rrule(MONTHLY, dtstart=start_dt, until=end_dt.replace(day=start_dt.day))]
    for i, start_date in enumerate(start_dates):
        if i == len(start_dates) - 1:
            end_date = end_dt
        elif start_date.month == 12:
            end_date = start_date.replace(day=31)
        else:
            end_date = start_date.replace(month=start_date.month + 1, day=1) - datetime.timedelta(days=1)
        data_items.append(
            {
                'id': id_,
                'start': start_date if i == 0 else start_date.replace(day=1),
                'end': end_date
            }
        )

您可以检查df_2中的输出是否要实现。

df_2 = pd.DataFrame(data_items)
df_2[['id', 'start', 'end']]

答案 2 :(得分:0)

从定义要应用于每一行的函数开始:

def expDates(row):
    d1 = pd.to_datetime(row.start)
    d2 = pd.to_datetime(row.end)
    stList = [d.strftime('%#d-%b-%y') for d in pd.date_range(d1, d2, freq='MS')]
    if len(stList) == 0:
        stList.append(row.start)
    elif stList[0] != row.start:
        stList.insert(0, row.start)
    endList = [d.strftime('%#d-%b-%y') for d in pd.date_range(d1, d2, freq='M')]
    if len(endList) == 0 or endList[-1] != row.end:
        endList.append(row.end)
    return pd.DataFrame({'id': row.id, 'start': stList, 'end': endList})

然后应用此功能,将结果保存为DataFrames列表:

tbl = df.apply(expDates, axis=1).tolist()

最后一步是连接这些DataFrame:

pd.concat(tbl, ignore_index=True)

在我看来,此解决方案不太“ pythonic”,而更“ pandasonic” 然后所有其他人。