Python 加快对每个组的结束日期和开始日期进行重新采样,但保持日期之间的间隔

Python 加快对每个组的结束日期和开始日期进行重新采样,但保持日期之间的间隔,python,pandas,dataframe,time-series,Python,Pandas,Dataframe,Time Series,我有以下数据帧: df = pd.DataFrame({'startdate': ['2013-03-04', '2012-01-02', '2012-08-06', '2013-02-04', '2013-05-07'], 'enddate': ['2013-03-07', '2012-01-06', '2012-08-10', '2013-02-11', '2013-05-09'], 'regnr': [111, 1

我有以下数据帧:

df = pd.DataFrame({'startdate': ['2013-03-04', '2012-01-02', '2012-08-06', '2013-02-04', '2013-05-07'],
                   'enddate': ['2013-03-07', '2012-01-06', '2012-08-10', '2013-02-11', '2013-05-09'],
                   'regnr': [111, 111, 111, 222, 222],
                   'contracttype': ['ABU', 'ABU', 'ULDB', 'ULDB', 'ABU']})

df['startdate'], df['enddate'] = pd.to_datetime(df['startdate']), pd.to_datetime(df['enddate'])

print(df)

   startdate    enddate  regnr contracttype
0 2013-03-04 2013-03-07    111          ABU
1 2012-01-02 2012-01-06    111          ABU
2 2012-08-06 2012-08-10    111         ULDB
3 2013-02-04 2013-02-11    222         ULDB
4 2013-05-07 2013-05-09    222          ABU
我想要的是将startdate和enddate扩展(重新采样)为每日时间序列。但重要的是,我们要保持日期之间的间隔。因此,如果你看一下
regnr=111
,我们会在索引2中看到
enddate=2012-11-04
,而下一个
startdate=2013-03-04
在索引0上。所以这两个日期之间有差距


因此,预期产出是:

         date  regnr contracttype
0  2013-03-04    111          ABU
1  2013-03-05    111          ABU
2  2013-03-06    111          ABU
3  2013-03-07    111          ABU
4  2012-01-02    111          ABU
5  2012-01-03    111          ABU
6  2012-01-04    111          ABU
7  2012-01-05    111          ABU
8  2012-01-06    111          ABU
9  2012-08-06    111         ULDB
10 2012-08-07    111         ULDB
11 2012-08-08    111         ULDB
12 2012-08-09    111         ULDB
13 2012-08-10    111         ULDB
14 2013-02-04    222         ULDB
15 2013-02-05    222         ULDB
16 2013-02-06    222         ULDB
17 2013-02-07    222         ULDB
18 2013-02-08    222         ULDB
19 2013-02-09    222         ULDB
20 2013-02-10    222         ULDB
21 2013-02-11    222         ULDB
22 2013-05-07    222          ABU
23 2013-05-08    222          ABU
24 2013-05-09    222          ABU

那么问题出在哪里?

我有一个可行的解决方案,但有点慢。对于66k行的数据帧,我需要约90-110秒的时间,最终将重新采样到1050万行

以下是可行的解决方案:

def resample_data(df):
    """
    :param df: dataframe where datetime has to be resampled to daily
    :return: resampled dataframe
    """
    tables = []

    for _, d in df.groupby('regnr'):
        for __, data in d.iterrows():
            dates = pd.date_range(data['startdate'], data['enddate'])
            dfn = pd.DataFrame({'regnr': data['regnr'],
                                'contracttype': data['contracttype']}, index=dates)
            tables.append(dfn)

    df = pd.concat(tables).rename_axis('date').reset_index()

    return df

矢量化解决方案,但不起作用

因此,我尝试了一种矢量化方法(除了在groupby中应用),但这不起作用,因为它将填补日期之间的空白

dfn = df.melt(id_vars=['regnr', 'contracttype'], 
              value_name='date', 
              var_name='start_end').drop('start_end', axis=1)

dfn = (
    dfn.groupby('regnr').apply(lambda x: x.set_index('date').resample('D').first().ffill())
    .reset_index(level=0, drop=True)
    .reset_index()
)

print(dfn)

          date  regnr contracttype
0   2012-01-02  111.0          ABU
1   2012-01-03  111.0          ABU
2   2012-01-04  111.0          ABU
3   2012-01-05  111.0          ABU
4   2012-01-06  111.0          ABU
..         ...    ...          ...
521 2013-05-05  222.0         ULDB
522 2013-05-06  222.0         ULDB
523 2013-05-07  222.0          ABU
524 2013-05-08  222.0          ABU
525 2013-05-09  222.0          ABU

[526 rows x 3 columns]

我不确定它是否满足要求,但我认为下面的代码可以处理它。但是,我还没有检查执行速度

tables = pd.DataFrame(index=[], columns=['Date','regnr','contracttype'])
for i in range(len(df)):
    days = pd.DataFrame({'Date':list(pd.date_range(df.startdate[i], df.enddate[i])),
            'regnr':[df.regnr[i]]*len(pd.date_range(df.startdate[i],df.enddate[i])),
            'contracttype':[df.contracttype[i]]*len(pd.date_range(df.startdate[i], df.enddate[i]))})
tables = pd.concat([tables, days], ignore_index=True)

    Date    regnr   contracttype
0   2013-03-04  111 ABU
1   2013-03-05  111 ABU
2   2013-03-06  111 ABU
3   2013-03-07  111 ABU
4   2012-01-02  111 ABU
5   2012-01-03  111 ABU
6   2012-01-04  111 ABU
7   2012-01-05  111 ABU
8   2012-01-06  111 ABU
9   2012-08-06  111 ULDB
10  2012-08-07  111 ULDB
11  2012-08-08  111 ULDB
12  2012-08-09  111 ULDB
13  2012-08-10  111 ULDB
14  2013-02-04  222 ULDB
15  2013-02-05  222 ULDB
16  2013-02-06  222 ULDB
17  2013-02-07  222 ULDB
18  2013-02-08  222 ULDB
19  2013-02-09  222 ULDB
20  2013-02-10  222 ULDB
21  2013-02-11  222 ULDB
22  2013-05-07  222 ABU
23  2013-05-08  222 ABU
24  2013-05-09  222 A

df1=pd.concat([pd.DataFrame({'date':pd.date_range(row.startdate,row.enddate,freq='D'),'regnr':row.regnr,'contracttype':row.contracttype},列=['date','regnr','contracttype']),对于df.itertuples()中的行,忽略索引=True)
这里的一点优化是,我使用的
itertuples()
iterrows()
更快,因为它不进行任何类型检查。我粘贴了结果。如果你能指出我错在哪里,我将不胜感激。