Добавить строку, когда условия из нескольких столбцов совпадают в python?

Я пытаюсь добавить строку в фрейм данных. Условие заключается в том, что когда пользователь снова возвращается (через 300 секунд) в приложение, мне нужно добавить строку. Ниже мой код. Он отлично работает, но требует много времени на выполнение, так как реальный фрейм данных содержит 10 миллионов строк.

for i in range(1,len(df)):
    if df['user_id'][i]==df['user_id'][i-1] and (df['start_time'][i]-df['start_time'][i-1]).seconds>300:
        df.loc[len(df)]=[df['user_id'][i],df['start_time'][i],'psuedo_App_start_2']

Вход:

user_id   start_time        event
100       03/04/19 6:11     psuedo_App_start
100       03/04/19 6:11     notification_receive
100       03/04/19 8:56     notification_dismiss
10        03/04/19 22:05    psuedo_App_start
10        03/04/19 22:05    subcategory_click
10        03/04/19 22:06    subcategory_click

вывод должен выглядеть так:

user_id   start_time        event
100       03/04/19 6:11     psuedo_App_start
100       03/04/19 6:11     notification_receive
100       03/04/19 8:56     psuedo_App_start_2
100       03/04/19 8:56     notification_dismiss
10        03/04/19 22:05    psuedo_App_start
10        03/04/19 22:05    subcategory_click
10        03/04/19 22:06    subcategory_click

Как видно из вывода, добавлена ​​строка для user_id = 100, так как он вернулся в 8,56, то есть через 300 секунд.

У вас есть контроль над тем, как эти события вставляются в фрейм данных?

rdas 07.04.2019 11:35

нет, другие события генерируются автоматически

nk23 07.04.2019 11:42

Почему бы вам не сделать это: 1) вспомнить, какая была последняя временная метка, которую вы видели во время полного сканирования фрейма данных, 2) при следующем сканировании получить только строки с более высокой временной меткой (т.е. новые строки)

rdas 07.04.2019 11:44

Не могу проверить это прямо сейчас, но вы можете groupby['user_id','start_time'], затем используйте df.timedelta, чтобы проверить, больше ли start_time для каждого идентификатора 300, и вставить новую строку, если выполняется условие (с последними start_time и user_id, извлеченными из df)

CAPSLOCK 07.04.2019 11:59
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
4
550
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Обычно в таких случаях нужно преобразовать явные циклы в векторизованные операции. Попробуйте что-то вроде этого:

i = (df.user_id.values[1:] == df.user_id.values[:-1]) & ((df.start_time.values[1:] - df.start_time.values[:-1])/np.timedelta64(1, 's') > 300)
newRows = tt[np.append(False, i)].copy()
newRows.event = 'psuedo_App_start_2'
df.append(newRows)
Ответ принят как подходящий

Сначала фильтруем по 2 условиям — сравниваем user_id по DataFrameGroupBy.shifted значения по группам, а также разницу по группам по DataFrameGroupBy.diff, затем переназначаем столбец evet по DataFrame.assign, последний concat вместе и сортируем по DataFrame.sort_values:

#MM/DD/YY HH:MM
#df['start_time'] = pd.to_datetime(df['start_time'])
#DD/MM/YY HH:MM
#df['start_time'] = pd.to_datetime(df['start_time'], dayfirst=True)

m1 = df['user_id'].eq(df.groupby('user_id')['user_id'].shift())
m2 = df.groupby('user_id')['start_time'].diff().dt.total_seconds() > 300

df1 = df[m1 & m2].assign(event='psuedo_App_start_2')

df1 = (pd.concat([df, df1], ignore_index=True)
         .sort_values(['user_id','start_time'], ascending=[False, True]))
print (df1)
   user_id          start_time                 event
0      100 2019-03-04 06:11:00      psuedo_App_start
1      100 2019-03-04 06:11:00  notification_receive
2      100 2019-03-04 08:56:00  notification_dismiss
6      100 2019-03-04 08:56:00    psuedo_App_start_2
3       10 2019-03-04 22:05:00      psuedo_App_start
4       10 2019-03-04 22:05:00     subcategory_click
5       10 2019-03-04 22:06:00     subcategory_click

Вы можете помочь мне понять, что хранится в m1 и m2?

nk23 04.05.2019 13:57

@ nk23 Существуют логические маски, сначала сравниваемые с помощью eq для ==, затем сравниваемые с >

jezrael 04.05.2019 14:55

Другие вопросы по теме