Разделите интервал месяцев относительно значения из другого столбца. - PullRequest
3 голосов
/ 05 февраля 2020

Проблема: у меня есть данные о состоянии записи клиентов за периоды времени. Для каждого клиента (группы) я хотел бы разделить временной интервал на «Старт» и «Фини sh» в зависимости от статуса, который они имеют в этот период.

Например, у меня есть этот кадр данных:

df = pd.DataFrame({'Group': ['group1', 'group1', 'group1', 'group1', 'group1', 'group1', 'group1', 'group1',
                    'group2', 'group2', 'group2', 'group2', 'group2', 'group2', 'group2', 'group2', 'group3'],
               'Month': ['2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12',
                    '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12'],
               'Status': ['Passive', 'Passive', 'Passive', 'Active', 'Active', 'Active', 'Passive', 'Passive',
                    'Active', 'Active', 'Passive', 'Passive', 'Passive', 'Active', 'Active', 'Active', 'Active']})

Я хотел бы перевести его в эту структуру:

df_new = pd.DataFrame({'Group': ['group1', 'group1', 'group1', 'group2', 'group2', 'group2', 'group3'],
                   'From': ['2019-05', '2019-08', '2019-11', '2019-04', '2019-06', '2019-09', '2019-12'],
                   'To': ['2019-07', '2019-10', '2019-12', '2019-05', '2019-08', '2019-11', '2019-12'],
                   'Status': ['Passive', 'Active', 'Passive', 'Active', 'Passive', 'Active', 'Active']})

Без переменной «Status» было бы довольно просто найти groupby и aggfun c, чтобы найти Период «мин» и «макс» в каждой группе. Однако я не знаю, как принять во внимание переменную «Статус». Проблема в том, что интервалы статуса здесь не являются непрерывными, поэтому, если я сгруппирую по «Статусу», у меня всегда будет только 2 группы для статуса (активная и пассивная), и интервалы будут смешанными.

Я думать о разделении фрейма данных на 2 фрейма данных: один со статусом «активный», а другой с «пассивным»; работая отдельно над этими двумя и слиться вместе снова. Но этот подход не кажется таким эффективным :( И так как один клиент может быть активным и пассивным много раз, довольно сложно разделить интервалы внутри каждой статус-группы.

Есть ли лучшее решение?

1 Ответ

3 голосов
/ 05 февраля 2020

Используйте groupby от Group и от помощника Серия смежных Status. С pandas v 0.25.0 + вы можете использовать именованных агрегатов , с min, max для "От" и "до" и last для "Статус" ':

s = df['Status'].ne(df['Status'].shift()).cumsum()

df_new = (df.groupby(['Group', s])
          .agg(From=('Month', 'min'),
               To=('Month', 'max'),
               Status=('Status', 'last'))
           .reset_index(level=0))

[out]

         Group     From       To   Status
Status                                   
1       group1  2019-05  2019-07  Passive
2       group1  2019-08  2019-10   Active
3       group1  2019-11  2019-12  Passive
4       group2  2019-04  2019-05   Active
5       group2  2019-06  2019-08  Passive
6       group2  2019-09  2019-11   Active
6       group3  2019-12  2019-12   Active

Как указывает @nhupn, при использовании более старой версии pandas агрегирование можно выполнить с помощью:

df_new = (df.groupby(['Group', s])
          .agg({'Month': [('From', 'min'),
                          ('To', 'max')],
                'Status': [('Status', 'last')]})
          .reset_index(level=0))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...