Более быстрый способ поиска значений в Python

#python-3.x #pandas #performance #logging

Вопрос:

Я анализирую журналы, и у меня есть идентификатор пользователя, время покупки и сумма покупки в первой таблице, а также временной интервал посещения и идентификатор во второй.

Первая таблица содержит около 90 тысяч строк, во второй-около 1 миллиона. Мне нужно найти доходы во второй таблице, если:

  1. Совпадающие идентификаторы
  2. Покупка происходит в течение временного интервала сеанса из таблицы 1

Я написал этот код:

 for i in range(len(data_purchases)):
    rowIndex = data_visits[(data_visits['uid'] == data_purchases['uid'].iloc[i]) amp;                             
    (data_visits['start_ts_dt'] < data_purchases['buy_ts'].iloc[i]) amp; 
    (data_visits['end_ts_dt'] > data_purchases['buy_ts'].iloc[i])].index
    data_visits.loc[rowIndex, 'Revenue'] = data_purchases['revenue'].iloc[i]
 

Но это действительно медленно. Есть ли какой-нибудь способ ускорить этот процесс?

Ответ №1:

Вы можете выполнить слияние слева по uid столбцу

 data_visits.merge(data_purchases, on='uid', how='left')
 

Отфильтруйте строки, соответствующие вашему условию интервала, и извлеките revenue столбец

 .query('start_ts_dt < buy_ts < end_ts_dt')['revenue']
 

Переименуйте его, чтобы он соответствовал столбцу, который вы хотите обновить.

 .rename('Revenue')
 

И, наконец, передайте его update() методу фрейма данных, который вы хотите изменить.

 data_visits.update((
    data_visits
        .merge(data_purchases, on='uid', how='left')
        .query('start_ts_dt < buy_ts < end_ts_dt')['revenue']
        .rename('Revenue')
))
 

Пример:

 >>> data_visits
   uid  start_ts_dt  end_ts_dt  Revenue
0    0           10         20       30
1    1          900       1001        9
2    2           10         20       10
3    3          100       1010      200
>>> data_purchases
   uid  buy_ts      revenue
0    1    1000  NEW REVENUE
1    2    1001           50
>>> data_visits.update((
...     data_visits
...         .merge(data_purchases, on='uid', how='left')
...         .query('start_ts_dt < buy_ts < end_ts_dt')['revenue']
...         .rename('Revenue')
... ))
>>> data_visits
   uid  start_ts_dt  end_ts_dt      Revenue
0    0           10         20           30
1    1          900       1001  NEW REVENUE
2    2           10         20           10
3    3          100       1010          200
 

Комментарии:

1. Спасибо за ваш ответ! Но этот метод удаляет все значения из data_visits, которые не входят в data_purchases, однако мне также нужна информация о сеансах, в которых не было покупок

2. Я добавил пример — data_visits сохраняет все исходные строки.