#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