#python #pandas #dataframe #lambda
Вопрос:
У меня есть большой фрейм данных с именованными объектами, которые можно сгруппировать по идентификатору события. Каждая группа состоит из одного или нескольких событий. Механизм обнаружения событий часто запускает новую группу до завершения текущей серии, что приводит к большому количеству коротких событий, в которых действительно должно быть меньшее количество более длинных событий.
Я могу определить группы, которые принадлежат друг другу по временному интервалу между событиями — если последнее событие в одной группе происходит в течение N секунд после первого события в следующей группе, то группы должны быть объединены.
В псевдокоде я хочу:
for all rows in dataframe:
if row['time_interval'] is less than N
and if row['ID'] is not equal to next_row['ID']
then where row['ID'] is the first row's value set it to the second row's value
Мои данные выглядят так:
TimeUTC | Имя | ID | time_interval_seconds |
---|---|---|---|
2021-06-01 08:58:47 00:00 | 0M63HB200SY101 | 9c3807ce-bf21-4cd8-b4ac-f2da440340dc | |
2021-06-01 09:00:11 00:00 | 0M63HB200SY101 | 16e9ea6c-2722-4881-bd35-5867e83be19b | 4 |
2021-06-01 09:00:21 00:00 | 0M63HB200SY101 | 16e9ea6c-2722-4881-bd35-5867e83be19b | 10 |
2021-06-01 09:00:24 00:00 | 0M63HB200SY101 | 16e9ea6c-2722-4881-bd35-5867e83be19b | 3 |
2021-06-01 09:04:25 00:00 | 0M63HB200SY101 | 204fb08c-7271-4399-b111-81488f5f26ec | 152 |
2021-06-01 09:04:35 00:00 | 0M63HB200SY101 | 204fb08c-7271-4399-b111-81488f5f26ec | 10 |
2021-06-01 09:05:23 00:00 | 0M63HB200SY101 | 204fb08c-7271-4399-b111-81488f5f26ec | 48 |
2021-06-01 09:06:30 00:00 | 0M63HB200SY101 | 4bfedd19-b081-467a-8441-bebaef05520c | 6 |
2021-06-01 09:07:04 00:00 | 0M63HB200SY101 | 4bfedd19-b081-467a-8441-bebaef05520c | 34 |
Так как значение time_interval во второй строке равно
Даже если идентификатор изменится между строками 4 и 5, мы не будем обновлять идентификатор, так как значение time_interval равно > N.
Однако все идентификаторы во втором блоке будут изменены на идентификаторы из третьего блока.
Такое ощущение, что я могу обнаружить изменение с помощью этой лямбда-функции:
if r2.time_interval_seconds < 5:
if r1['ID'] != r2['ID']:
return(r2['ID'])
df['newID'] = df[df.apply(lambda x: row_compare(x, x's iloc 1)
Но а) я не могу понять, как передать обе строки (.shift()?) и б) получить доступ к исходному кадру данных для его обновления.
Если бы для данной строки я мог передать исходный кадр данных в лямбда-функцию, то я мог бы присоединиться к двум группам внутри функции.
У меня есть миллионы этих строк, и перебирать их на самом деле не вариант, хотя это было бы прямолинейно.
Ответ №1:
Способ сделать это без применения, но все же с векторизованным вычислением:
Я предполагаю, что df
сортируется по TimeUTC
. Вы создаете новый столбец newID
, содержащий только значение для начала каждой группы. Группа начинается, когда time_interval_seconds >= N
df['newID'] = np.where(
time_interval_seconds >= N,
df['ID'], np.nan
)
Вы инициализируете первое значение столбца :
df['newID'].iloc[0] = df['ID'].iloc[0]
А затем вы пересылаете его, чтобы заполнить колонку
df['newId'] = df['newId'].ffill()
Комментарии:
1. Это немного неясно в вашем описании, здесь я пересылаю заполнение столбца, в вашем примере вы говорите, что хотите обновить первую строку значением второй строки, чтобы вы могли адаптировать логику и также заполнить данные обратно.
2. Я вижу, как это работает, и думаю, что это должно сработать. Я пойду, покатаюсь на нем. Спасибо.