У меня есть следующий фрейм данных:
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
Я хочу расширить (изменить) начальную дату и конечную дату до дневного временного ряда. Но что важно, так это то, что мы сохраняем разрыв между датами. Итак, если вы посмотрите на 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
Так в чем же проблема?
У меня есть рабочее решение, но оно довольно медленное. У меня уходит ~ 90 - 110 секунд для кадра данных из 66 тыс. Строк, который в итоге будет преобразован в 10,5 млн. Строк.
Вот рабочее решение:
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
Векторизация решение, но не работает
Поэтому я попробовал векторизованный метод (ожидаем применения в групповом режиме), но он не работает, поскольку он заполнит промежутки между датами.
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]