#python #pandas
#python #pandas
Вопрос:
Имея следующий DF:
id init_time event_time value
0 0 2020-10-21 00:21:25 2020-10-21 00:21:30 1
1 0 2020-10-21 00:21:25 2020-10-21 00:21:35 3
2 0 2020-10-21 00:21:25 2020-10-21 00:23:25 7
3 1 2020-10-21 15:21:25 2020-10-21 15:21:30 3
4 1 2020-10-21 15:21:25 2020-10-21 15:22:25 6
5 1 2020-10-21 15:21:25 2020-10-21 16:21:25 9
6 1 2020-10-21 15:21:25 2020-10-21 18:21:25 10
7 1 2020-10-21 15:21:25 2020-10-21 18:30:25 10
8 2 2020-10-21 08:11:20 2020-10-21 08:21:25 1
9 2 2020-10-21 08:11:20 2020-10-21 09:11:20 2
10 2 2020-10-21 08:11:20 2020-10-21 09:21:25 3
11 2 2020-10-21 08:11:20 2020-10-21 10:12:12 4
12 2 2020-10-21 08:11:20 2020-10-21 10:30:00 5
13 2 2020-10-21 08:11:20 2020-10-21 11:50:48 6
14 2 2020-10-21 08:11:20 2020-10-21 11:59:15 7
Я хотел бы сгруппировать id
, затем на основе init_time вставлять строку каждые X интервалов и повторять Y раз. Обратите внимание, что init_time
это одинаково для всех строк и event_time
является временем создания строки.
Например, если X
is 1h
и Y
is 5
раз, результат DF будет:
id init_time event_time value
0 0 2020-10-21 00:21:25 2020-10-21 00:21:25 -- ⎫
1 0 2020-10-21 00:21:25 2020-10-21 00:21:30 1 ⎪
2 0 2020-10-21 00:21:25 2020-10-21 00:21:35 3 ⎬ 1H interval (00:21:25 - 01:21:25)
3 0 2020-10-21 00:21:25 2020-10-21 00:23:25 7 ⎪
4 0 2020-10-21 00:21:25 2020-10-21 01:21:25 -- ⎭
5 0 2020-10-21 00:21:25 2020-10-21 02:21:25 --
6 0 2020-10-21 00:21:25 2020-10-21 03:21:25 --
7 0 2020-10-21 00:21:25 2020-10-21 04:21:25 --
8 1 2020-10-21 15:21:25 2020-10-21 15:21:25 -- ⎫
9 1 2020-10-21 15:21:25 2020-10-21 15:21:30 3 ⎪
10 1 2020-10-21 15:21:25 2020-10-21 15:22:25 6 ⎬ 1H interval (15:21:25 - 16:21:25)
11 1 2020-10-21 15:21:25 2020-10-21 16:21:25 -- ⎭
12 1 2020-10-21 15:21:25 2020-10-21 16:21:25 9
13 1 2020-10-21 15:21:25 2020-10-21 17:21:25 --
14 1 2020-10-21 15:21:25 2020-10-21 18:21:25 --
15 1 2020-10-21 15:21:25 2020-10-21 18:21:25 10
16 1 2020-10-21 15:21:25 2020-10-21 18:30:25 10
17 1 2020-10-21 15:21:25 2020-10-21 19:21:25 --
18 2 2020-10-21 08:11:20 2020-10-21 08:11:20 -- ⎫
19 2 2020-10-21 08:11:20 2020-10-21 08:21:25 1 ⎬ 1H interval (08:11:20 - 09:11:20)
20 2 2020-10-21 08:11:20 2020-10-21 09:11:20 -- ⎭
21 2 2020-10-21 08:11:20 2020-10-21 09:11:20 2
22 2 2020-10-21 08:11:20 2020-10-21 09:21:25 3
23 2 2020-10-21 08:11:20 2020-10-21 10:11:20 --
24 2 2020-10-21 08:11:20 2020-10-21 10:12:12 4
25 2 2020-10-21 08:11:20 2020-10-21 10:30:00 5
26 2 2020-10-21 08:11:20 2020-10-21 11:11:20 --
27 2 2020-10-21 08:11:20 2020-10-21 11:50:48 6
28 2 2020-10-21 08:11:20 2020-10-21 11:59:15 7
29 2 2020-10-21 08:11:20 2020-10-21 12:11:20 --
Любая помощь будет оценена по достоинству 🙂
Обновление: вот что я сделал до сих пор:
df2 = pd.DataFrame()
groups = df.groupby('id')['init_time'].first()
for g in groups:
tmp = pd.DataFrame(index=pd.date_range(g, periods=5, freq="H"))
tmp['value'] = -1
df2 = df2.append(tmp,ignore_index=False)
df2 = df2.reset_index(drop=False)
df2['event_time'] = df2.pop('index')
Код создает недостающие строки:
value event_time
0 -1 2020-10-21 00:21:25
1 -1 2020-10-21 01:21:25
2 -1 2020-10-21 02:21:25
3 -1 2020-10-21 03:21:25
4 -1 2020-10-21 04:21:25
5 -1 2020-10-21 15:21:25
6 -1 2020-10-21 16:21:25
7 -1 2020-10-21 17:21:25
8 -1 2020-10-21 18:21:25
9 -1 2020-10-21 19:21:25
10 -1 2020-10-21 08:11:20
11 -1 2020-10-21 09:11:20
12 -1 2020-10-21 10:11:20
13 -1 2020-10-21 11:11:20
14 -1 2020-10-21 12:11:20
Теперь мне нужно выяснить, как объединить DFS, или, может быть, найти лучшую альтернативу
Update2: я хочу оптимизировать решение, предложенное @Serge Ballesta, чтобы увеличить время выполнения.
Комментарии:
1. Вы хотите сделать это в режиме реального времени или после сбора данных?
2. После сбора данных
Ответ №1:
Я не мог найти умный способ. Поэтому я только предлагаю:
- получить строку данных для каждого
id
init_time
столбца (предполагается, что она уникальна для идентификатора) - добавьте новый
event_time
столбец, построенный из adate_range
, и объедините все - объедините ее с исходным фреймом данных, отсортируйте и создайте новый индекс
Код может быть (при условии, что фрейм данных есть df
, а xxx_time
столбцы имеют datetime64[ns]
dtypes):
# extract init_time per id
df1 = df[['id', 'init_time']].drop_duplicates()
# build the new event_time data
df2 = pd.concat(pd.DataFrame({'id': [s[1]['id']] * 5,
'init_time': [s[1]['init_time']] * 5,
'event_time': pd.date_range(s[1]['init_time'],
periods=5,
freq='1H')})
for s in df1.iterrows())
# concat with the initial dataframe
final = pd.concat((df, df2)).sort_values(['id', 'event_time']).reset_index(
drop=True)
С вашими примерами данных это дает:
id init_time event_time value
0 0 2020-10-21 00:21:25 2020-10-21 00:21:25 NaN
1 0 2020-10-21 00:21:25 2020-10-21 00:21:30 1.0
2 0 2020-10-21 00:21:25 2020-10-21 00:21:35 3.0
3 0 2020-10-21 00:21:25 2020-10-21 00:23:25 7.0
4 0 2020-10-21 00:21:25 2020-10-21 01:21:25 NaN
5 0 2020-10-21 00:21:25 2020-10-21 02:21:25 NaN
6 0 2020-10-21 00:21:25 2020-10-21 03:21:25 NaN
7 0 2020-10-21 00:21:25 2020-10-21 04:21:25 NaN
8 1 2020-10-21 15:21:25 2020-10-21 15:21:25 NaN
9 1 2020-10-21 15:21:25 2020-10-21 15:21:30 3.0
10 1 2020-10-21 15:21:25 2020-10-21 15:22:25 6.0
11 1 2020-10-21 15:21:25 2020-10-21 16:21:25 9.0
12 1 2020-10-21 15:21:25 2020-10-21 16:21:25 NaN
13 1 2020-10-21 15:21:25 2020-10-21 17:21:25 NaN
14 1 2020-10-21 15:21:25 2020-10-21 18:21:25 10.0
15 1 2020-10-21 15:21:25 2020-10-21 18:21:25 NaN
16 1 2020-10-21 15:21:25 2020-10-21 18:30:25 10.0
17 1 2020-10-21 15:21:25 2020-10-21 19:21:25 NaN
18 2 2020-10-21 08:11:20 2020-10-21 08:11:20 NaN
19 2 2020-10-21 08:11:20 2020-10-21 08:21:25 1.0
20 2 2020-10-21 08:11:20 2020-10-21 09:11:20 2.0
21 2 2020-10-21 08:11:20 2020-10-21 09:11:20 NaN
22 2 2020-10-21 08:11:20 2020-10-21 09:21:25 3.0
23 2 2020-10-21 08:11:20 2020-10-21 10:11:20 NaN
24 2 2020-10-21 08:11:20 2020-10-21 10:12:12 4.0
25 2 2020-10-21 08:11:20 2020-10-21 10:30:00 5.0
26 2 2020-10-21 08:11:20 2020-10-21 11:11:20 NaN
27 2 2020-10-21 08:11:20 2020-10-21 11:50:48 6.0
28 2 2020-10-21 08:11:20 2020-10-21 11:59:15 7.0
29 2 2020-10-21 08:11:20 2020-10-21 12:11:20 NaN
Комментарии:
1. Спасибо за ответ, ваш код работает, однако время выполнения очень велико для моего реального набора данных. Как мы можем это улучшить?
2. @ShlomiSchwartz: Неудивительно, что причина, по которой я начал свой ответ, заключалась в том, что я не мог найти умный способ .
iterrows
известно, что это приводит к простым в реализации решениям, но с низкой производительностью при увеличении размера.groupby
иapply
также можно попробовать, но они немного сложнее в настройке, и выигрыш должен быть сопоставлен. С этим образцом данных выигрыша нет…3. У меня нет времени писать ответ прямо сейчас, но я думаю, что если вместо разработки временных интервалов вдоль строк вы превратите их в
periods
столбцы, а затемmelt
в фрейм данных, вы можете использовать операции с массивами и избежать iterrows. Например. после создания выdf1
добавляете5
новые столбцы, в которыхвы добавляете 1 часinit_time
, затем превращаете такие столбцы в новые строки, используя что-то вродеmelt
, тогда вам просто нужно немного почистить, но должно быть быстрее.4. @gionni: я был удивлен этим, но с образцами данных,
melt
похоже, медленнее, чемiterrows
(не тестировалось с большим количеством строк …)