Найти месяц первой покупки в данных клиента

#python #pandas

#python #панды

Вопрос:

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

Печатать очень сложно, поэтому вот скриншот:

введите описание изображения здесь

Вы можете увидеть для customer_id 1 (красный), что они впервые купили в августе 2019 года (зеленый). Это означает, что клиенту 12 месяцев. Я получил число 12, считая в обратном порядке с самого последнего месяца.

Как я могу извлечь эту информацию программно для всех клиентов?

Я хотел бы добавить дополнительный столбец, tenure который подсчитывает, сколько лет клиентам в месяцах.

Я думаю, я должен попытаться посчитать количество столбцов назад / вперед, пока не найду первое число, отличное от «nan».

Но я понятия не имею, как это сделать. Я попробовал несколько предложений из похожих вопросов здесь. Транспонирование фрейма данных и использование Series.first_valid_index() для каждого клиента или использование сочетания df.isnull() и idxmax() , но я не смог заставить его работать.

Любая помощь приветствуется. Я уверен, что это легко исправить, но я заблудился.

Мой образец df:

 
df.to_dict()


{'customer_id': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10},
 'Jan 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Feb 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: 1.0,
  9: nan},
 'Mar 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Apr 19': {0: nan,
  1: 1.0,
  2: 1.0,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'May 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: 1.0,
  7: nan,
  8: nan,
  9: nan},
 'Jun 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Jul 19': {0: nan,
  1: nan,
  2: nan,
  3: 1.0,
  4: nan,
  5: nan,
  6: 2.0,
  7: nan,
  8: nan,
  9: 2.0},
 'Aug 19': {0: 1.0,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: 1.0,
  9: nan},
 'Sep 19': {0: 2.0,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Oct 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: 1.0,
  6: nan,
  7: nan,
  8: 1.0,
  9: nan},
 'Nov 19': {0: 1.0,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: 1.0,
  8: nan,
  9: nan},
 'Dec 19': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: 1.0,
  7: nan,
  8: nan,
  9: nan},
 'Jan 20': {0: nan,
  1: nan,
  2: nan,
  3: 1.0,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Feb 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Mar 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Apr 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'May 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Jun 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Jul 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: nan,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan},
 'Aug 20': {0: nan,
  1: nan,
  2: nan,
  3: nan,
  4: 1.0,
  5: nan,
  6: nan,
  7: nan,
  8: nan,
  9: nan}}
  

Ответ №1:

d ваш словарь из вопроса:

 from itertools import count

df = pd.DataFrame(d).set_index('customer_id')
df['tenure'] = df.rename(columns=lambda x, c=count(len(df.columns)-1, -1): next(c)).idxmin(axis=1)
print(df)
  

С принтами:

              Jan 19  Feb 19  Mar 19  Apr 19  May 19  Jun 19  Jul 19  Aug 19  Sep 19  Oct 19  Nov 19  Dec 19  Jan 20  Feb 20  Mar 20  Apr 20  May 20  Jun 20  Jul 20  Aug 20  tenure
customer_id                                                                                                                                                                        
1               NaN     NaN     NaN     NaN     NaN     NaN     NaN     1.0     2.0     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      12
2               NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      16
3               NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      16
4               NaN     NaN     NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN      13
5               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     1.0       0
6               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      10
7               NaN     NaN     NaN     NaN     1.0     NaN     2.0     NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      15
8               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN       9
9               NaN     1.0     NaN     NaN     NaN     NaN     NaN     1.0     NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      18
10              NaN     NaN     NaN     NaN     NaN     NaN     2.0     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN      13
  

Ответ №2:

Идея заключается в преобразовании столбцов в месячные периоды в цифрах и проверке первого не пропущенного значения с помощью DataFrame.notna with DataFrame.idxmax , добавленного DataFrame.where для предотвращения совпадения с первым столбцом, если в строке отсутствуют только значения. Последнее вычитание из значения индекса vals с правой стороны на Series.rsub :

 df = df.set_index('customer_id')
df1 = df.notna()
df1.columns = pd.to_datetime(df1.columns, format='%b %y').to_period('m').astype('int')
s = df1.idxmax(axis=1).where(df1.any(axis=1))

df['tenure'] = s.rsub(df1.columns[-1])
  

 print (df)
             Jan 19  Feb 19  Mar 19  Apr 19  May 19  Jun 19  Jul 19  Aug 19  
customer_id                                                                   
1               NaN     NaN     NaN     NaN     NaN     NaN     NaN     1.0   
2               NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN   
3               NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN   
4               NaN     NaN     NaN     NaN     NaN     NaN     1.0     NaN   
5               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
6               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
7               NaN     NaN     NaN     NaN     1.0     NaN     2.0     NaN   
8               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
9               NaN     1.0     NaN     NaN     NaN     NaN     NaN     1.0   
10              NaN     NaN     NaN     NaN     NaN     NaN     2.0     NaN   

             Sep 19  Oct 19  Nov 19  Dec 19  Jan 20  Feb 20  Mar 20  Apr 20  
customer_id                                                                   
1               2.0     NaN     1.0     NaN     NaN     NaN     NaN     NaN   
2               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
3               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
4               NaN     NaN     NaN     NaN     1.0     NaN     NaN     NaN   
5               NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   
6               NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN   
7               NaN     NaN     NaN     1.0     NaN     NaN     NaN     NaN   
8               NaN     NaN     1.0     NaN     NaN     NaN     NaN     NaN   
9               NaN     1.0     NaN     NaN     NaN     NaN     NaN     NaN   
10              NaN     NaN     NaN     NaN     NaN     NaN     NaN     NaN   

             May 20  Jun 20  Jul 20  Aug 20  tenure  
customer_id                                          
1               NaN     NaN     NaN     NaN      12  
2               NaN     NaN     NaN     NaN      16  
3               NaN     NaN     NaN     NaN      16  
4               NaN     NaN     NaN     NaN      13  
5               NaN     NaN     NaN     1.0       0  
6               NaN     NaN     NaN     NaN      10  
7               NaN     NaN     NaN     NaN      15  
8               NaN     NaN     NaN     NaN       9  
9               NaN     NaN     NaN     NaN      18  
10              NaN     NaN     NaN     NaN      13