Ускорить логическое объединение строк в пандах (в зависимости от условий) - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть фрейм данных с миллионами заказов на продажу. Каждый ряд представляет один элемент корзины. Мне нужно объединить заказы, которые разделены, несмотря на то, что заказы были сделаны в тот же день. Точнее, все заказы от одного и того же клиента в тот же день, которые также были отправлены в один и тот же день, должны быть привязаны к одному и тому же идентификатору заказа (независимо от того, какой из них был рассмотрен).

Столбцы: 'customer_id', 'order_id', ..., 'order_date', 'ship_date'

Мое наивное решение работает, но ужасно медленно:

for _, customer_groups in df.groupby(by='customer_id'):
        for _, same_day_orders in customer_groups.groupby(by=['order_date', 'ship_date']):
            # Only merge if multiple orders per day.
            if same_day_orders.shape[0] > 1:
                # Now step through the line items two at a time.
                row_iterator = same_day_orders.iterrows()
                _, last_row = next(row_iterator)
                for it in row_iterator:
                    idx, current_row = it
                    # Check if the next line order has the same 'ship_date' and a different 'order_id'...
                    same_shipping_date = (last_row.ship_date == current_row.ship_date)
                    different_order_id = (last_row.order_id is not current_row.order_id)
                    # ... if so, merge the rows by assigning the second line item the same 'order_id' as its predecessor.
                    if (same_shipping_date and different_order_id):
                        df.loc[idx, 'order_id'] = last_row.order_id
                    last_row = current_row

Пример:

index   customer_id  order_id   order_date  ship_date
1234    C0176        S0159      2018-03-24  2018-04-23
1235    C0176        S0163      2018-03-24  2018-04-23
1236    C0176        S0163      2018-03-24  2018-04-23
1237    C0176        S0171      2018-03-24  2018-05-01

index   customer_id  order_id   order_date  ship_date   
1234    C0176        S0159      2018-03-24  2018-04-23
1235    C0176        S0159      2018-03-24  2018-04-23
1236    C0176        S0159      2018-03-24  2018-04-23
1237    C0176        S0171      2018-03-24  2018-05-01

Как я могу решить эту проблему умнее, то есть быстрее (сохранение читабельности было бы тоже неплохо)?

1 Ответ

0 голосов
/ 09 ноября 2018

Это отличная работа для transform, которая выполняет преобразование для сгруппированных рядов, но гарантирует, что индекс результата совпадает с индексом ввода (а не объединяет группы в один результат, как то, что делает agg). Вы можете использовать его так:

# Get groups of equal customer_id, order_date, and ship_date:
groups = df.groupby(['customer_id', 'order_date', 'ship_date'])

# Get the last order_id value, but ensure its index matches df:
collapsed_orders = groups['order_id'].transform(lambda x: x.iloc[-1])

# Overwrite the original order_id with this new value:
df['order_id'] = collapsed_orders

Или, как однострочный:

df['order_id'] = df.groupby(['customer_id', 'order_date', 'ship_date'])['order_id'].transform(lambda x: x.iloc[-1])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...