У меня есть большой набор данных, где каждая строка представляет значение определенного типа (например, датчик) за временной интервал (между началом и концом). Это выглядит так:
start end type value
2015-01-01 2015-01-05 1 3
2015-01-06 2015-01-08 1 2
2015-01-05 2015-01-08 3 3
2015-01-13 2015-01-16 2 1
Я хочу превратить его в ежедневный индексированный по времени кадр следующим образом:
day type value
2015-01-01 1 3
2015-01-02 1 3
2015-01-03 1 3
2015-01-04 1 3
2015-01-05 1 3
2015-01-06 1 2
2015-01-07 1 2
2015-01-08 1 2
2015-01-05 3 3
2015-01-16 3 3
2015-01-07 3 3
2015-01-08 3 3
2015-01-13 2 1
2015-01-14 2 1
2015-01-15 2 1
2015-01-16 2 1
(Обратите внимание, что мы не можем делать никаких предположений относительно интервала: они должны быть непрерывными и не перекрываться, но мы не можем этого гарантировать)
На основе этих ответов Stack Overflow [1] (передискретизация DataFrame по диапазонам дат) [2] (pandas: агрегат на основе начала /конечная дата), похоже, существует два метода: один вокруг itertuples, другой вокруг Mel (2 выше использовал stack/unstack, но он похож на Mel). Сравним их по производительности.
# Creating a big enough dataframe
date_range = pd.date_range(start=dt.datetime(2015,1,1), end=dt.datetime(2019,12,31), freq='4D')
to_concat = []
for val in range(1,50):
frame_tmp = pd.DataFrame()
frame_tmp['start'] = date_range
frame_tmp['end'] = frame_tmp['start']+ dt.timedelta(3)
frame_tmp['type'] = val
frame_tmp['value'] = np.random.randint(1, 6, frame_tmp.shape[0])
to_concat.append(frame_tmp)
df = pd.concat(to_concat, ignore_index=True)
# Method 1
def method_1(df):
df1 = (pd.concat([pd.Series(r.Index,
pd.date_range(r.start,
r.end,
freq='D'))
for r in df.itertuples()])) \
.reset_index()
df1.columns = ['start_2', 'idx']
df2 = df1.set_index('idx').join(df).reset_index(drop=True)
return df2.set_index('start_2')
df_method_1=df.groupby(['type']).apply(method_1)
# Method 2
df_tmp= df.reset_index()
df1 = (df_tmp.melt(df_tmp.columns.difference(['start','end']),
['start', 'end'],
value_name='current_time')
)
df_method_2 = df1.set_index('current_time').groupby('index', group_keys=False)\
.resample('D').ffill()
С %%timeit
в Jupyter метод 1 занимает ~ 8 с, а метод 2 - ~ 25 с для кадра данных, определенного в качестве примера. Это слишком медленно, так как реальный набор данных, с которым я имею дело, намного больше этого. В этом кадре данных метод 1 занимает ~ 20 минут.
У вас есть идеи, как сделать это быстрее?
date_range
вframe_tmp['start'] = date_range
? - person Ben.T   schedule 07.06.2018df_tmp
? Кроме того, поскольку вы говорите «мы не можем делать никаких предположений относительно интервала», я предполагаю, что вы хотите расширить указанные показания (даже если они перекрываются или имеют пробелы), а не искать каждый день года среди доступных показаний. Это правильно? - person Matthias Fripp   schedule 07.06.2018