Условие между дублированными значениями в столбце - PullRequest
2 голосов
/ 27 марта 2019

Каждый клиент дублируется, если у него более одного плана. Я хочу установить статус для клиента:

Если у них есть каждый продукт с заполненным «cancelled_at», статус клиента отменяется, но если это не каждый продукт с заполненным «cancelled_at», а хотя бы один, статус «понижен», потому что он потерял продукт.

customer|canceled_at|status
x       |3/27/2018  |
x       |           |
y       |2/2/2018   |
y       |2/2/2018   |
z       |1/1/2018   |
a       |           |      

У меня уже есть отмененный статус, теперь мне нужно только понижение

df['status']=(df.groupby('customer')['canceled_at'].
  transform(lambda x: x.notna().all()).map({True:'canceled'})).fillna(df.status)
customer|canceled_at|status
x       |3/27/2018  |downgrade
x       |           |downgrade
y       |2/2/2018   |canceled
y       |2/2/2018   |canceled
z       |1/1/2018   |canceled
a       |           |      

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Вот способ сделать это:

import pandas as pd

def select_status(canceled):
    c = canceled.count()
    if c == 0:
        status = ''
    elif c == len(canceled):
        status = 'canceled'
    else:
        status = 'downgrade'
    return pd.Series(status, index=canceled.index)

df = pd.DataFrame({'customer': ['x', 'x', 'y', 'y', 'z', 'a'],
                   'canceled_at': ['3/27/2018', None, '2/2/2018', '2/2/2018', '1/1/2018', None]})
df['status'] = df.groupby('customer')['canceled_at'].apply(select_status)
print(df)

Вывод:

  customer canceled_at     status
0        x   3/27/2018  downgrade
1        x        None  downgrade
2        y    2/2/2018   canceled
3        y    2/2/2018   canceled
4        z    1/1/2018   canceled
5        a        None
1 голос
/ 27 марта 2019

Здесь можно сравнить столбец для отсутствия пропущенных значений и группировки по Series customer с GroupBy.transform и GroupBy.all, GroupBy.any для проверки всех значений True с (все не пропущены) или хотя бы одно значение не пропущено (все пропущено) и передайте его numpy.select:

g = df['canceled_at'].notna().groupby(df['customer'])
m1 = g.transform('all')
m2 = g.transform('any')

df['status'] = np.select([m1, m2],['canceled','downgrade'], np.nan)
print (df)
  customer canceled_at     status
0        x   3/27/2018  downgrade
1        x         NaN  downgrade
2        y    2/2/2018   canceled
3        y    2/2/2018   canceled
4        z    1/1/2018   canceled
5        a         NaN        nan

Или:

df['status'] = np.select([m1, m2],['canceled','downgrade'], '')
print (df)
  customer canceled_at     status
0        x   3/27/2018  downgrade
1        x         NaN  downgrade
2        y    2/2/2018   canceled
3        y    2/2/2018   canceled
4        z    1/1/2018   canceled
5        a         NaN         

Если группам NaN нужно преобразовать только в downgrade:

mask = df['canceled_at'].notna().groupby(df['customer']).transform('all')
df['status'] = np.where(mask,'canceled','downgrade')
print (df)
  customer canceled_at     status
0        x   3/27/2018  downgrade
1        x         NaN  downgrade
2        y    2/2/2018   canceled
3        y    2/2/2018   canceled
4        z    1/1/2018   canceled
5        a         NaN  downgrade  
...