Заполните один столбец последнего элемента в группе значением другого столбца

1

У меня есть набор данных для каждого случая. Я пытаюсь заполнить последнее unassigned из каждого случая дату case_closed.

case_nb   attorney      cas_closed_date assigned    last_event
1         A             2015-07-02      2015-07-02  2015-07-02
2         B             2015-09-10      2015-09-10  2015-09-10
3         C             2016-03-24      2016-03-24  2016-03-24
4         D             2018-06-07      2013-10-21  2014-02-06
4         C             2018-06-07      2013-09-13  2013-09-13
4         F             2018-06-07      2018-03-31  2018-04-05

(Для тиражирования:

df = pd.DataFrame({'assigned': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10', 2: '2016-03-24', 3: '2013-10-21', 4: '2013-09-13', 5: '2018-03-31'},
                    'attorney': {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'C', 5: 'F'},
                    'cas_closed_date': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10', 2: '2016-03-24', 3: '2018-06-07', 4: '2018-06-07', 5: '2018-06-07'},
                    'case_nb': {0: 1, 1: 2, 2: 3, 3: 4, 4: 4, 5: 4},
                    'last_event': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10', 2: '2016-03-24', 3: '2014-02-06', 4: '2013-09-13', 5: '2018-04-05'}}

)

В моем наборе данных содержится номер дела, назначенный адвокат, дата закрытия дела, дата назначения адвоката и последнее событие, на котором появился адвокат. В приведенном выше примере я бы хотел, чтобы последняя строка была

4         F             2018-06-07      2018-03-31  2018-06-07

Я видел несколько способов заполнения НС на основе данных в одном столбце, таких как этот вопрос. Но эти способы используют transform, которое я не могу использовать для использования нескольких столбцов.

То, к чему я до сих пор работаю, apply, но не transform:

def fixdate(gp):
    last_unasgn = gp.iloc[-1]['last_event']
    if gp.iloc[-1]['cas_closed_date'] > last_unasgn:
        return gp.iloc[-1]['cas_closed_date']
    else:
       return last_unasgn

asmt.groupby('evt_file_number').apply(lambda x: fixdate(x))
> 4  2018-06-07

Есть ли способ использовать transform? Если нет, то какой лучший способ использовать эти агрегированные данные для заполнения моего исходного набора данных?

Теги:
pandas
pandas-groupby

3 ответа

1
Лучший ответ

В случае, когда тот же case_nb никогда не назначается в тот же день двум различным адвокатам, вы можете попробовать это решение.

import numpy as np
import pandas as pd

df = pd.DataFrame({'assigned': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10',
                                2: '2016-03-24', 3: '2013-10-21', 4: '2013-09-13',
                                5: '2018-03-31'},
                    'attorney': {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'C', 5: 'F'},
                    'cas_closed_date': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10',
                                        2: '2016-03-24', 3: '2018-06-07', 4: '2018-06-07',
                                        5: '2018-06-07'},
                    'case_nb': {0: 1, 1: 2, 2: 3, 3: 4, 4: 4, 5: 4},
                    'last_event': {0: pd.Timestamp('2015-07-02'), 1: '2015-09-10',
                                   2: '2016-03-24', 3: '2014-02-06', 4: '2013-09-13',
                                   5: '2018-04-05'}})

out = df.groupby("case_nb")["assigned"].max().reset_index()
out["last"] = True
df = pd.merge(df, out, how="left", on= ["case_nb", "assigned"])
df["last_event"] = np.where(df["last"] == True, df["cas_closed_date"], df["last_event"])
del df["last"], out

Возможно есть более элегантное решение, но по крайней мере это векторное (см np.where) и не использовать apply. pandas performaces.

EDIT В случае, если вы хотите использовать transform есть этот вариант, который кажется мне самым быстрым решением.

df["last_assigned"] = df.groupby("case_nb")["assigned"].transform("max")
df["last_event"] = np.where(df["assigned"]==df["last_assigned"], 
                            df["cas_closed_date"],
                            df["last_event"])
del df["last_assigned"]
  • 0
    С %%timeit%%, your решение np.where` заняло 1.45 ms ± 37.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) , а мое решение loc заняло 2.14 ms ± 72.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) . Так что я бы сказал, что np.where - явный победитель.
  • 0
    @RCA Пробовали ли вы на реальном случае df ?
1

Операция .transform передает все столбцы для каждой группы в качестве одномерной серии для функции, а операция .apply передает все столбцы для каждой группы в качестве DataFrame для функции. Таким образом, .transform работает на одной серии (или столбце) за раз, а .apply работает для всего DataFrame (или всех столбцов). Надеюсь это поможет.

  • 0
    Спасибо! Я смутно знал, что именно он делает, но ваш ответ помог мне продумать, как создать флаг.
0

В итоге я сделал комбинацию transform и просто индексирования.

df = df.sort_values(['case_nb', 'last_event'])
df['last_unassigned'] = df.groupby('case_nb')['last_event'].transform('last')
df.loc[(df['last_event'] == df['last_unassigned'])
        & (df['last_unassigned'] != df['cas_closed_date']), 'last_event'] = df['cas_closed_date']
  • 0
    Вы не хотите протестировать это решение против моего последнего с вашим df, чтобы увидеть, какое из них быстрее в реальном случае? Тогда я думаю, что это условие df['last_unassigned'] != df['cas_closed_date'] является избыточным. Я имею в виду, что если эти значения совпадают, это не повредит обновлению df["last_event"] с самим собой.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню