#python #pandas #group-by #cumulative-sum
#python #pandas #группировка по #кумулятивная сумма
Вопрос:
Я хочу создать график, который будет отображать совокупный средний доход за каждый «Год на борту» (первая транзакция клиента) за определенный период времени. Но я допускаю ошибки при группировании необходимой мне информации.
Игрушечные данные:
dataset = {'ClientId': [1,2,3,1,2,3,1,2,3,1,2,3,4,4,4,4,4,4,4],
'Year Onboarded': [2018,2019,2020,2018,2019,2020,2018,2019,2020,2018,2019,2020,2016,2016,2016,2016,2016,2016,2016],
'Year': [2019,2019,2020,2019,2019,2020,2018,2020,2020,2020,2019,2020,2016,2017,2018,2019,2020,2017,2018],
'Revenue': [100,50,25,30,40,50,60,100,20,40,100,20,5,5,8,4,10,20,8]}
df = pd.DataFrame(data=dataset)
Объяснение: у клиентов есть обозначенный «Год на борту», и они совершают транзакцию каждый упомянутый «Год».
Затем я подсчитываю годы, прошедшие с момента подключения клиентов, чтобы сделать мой график визуально более привлекательным.
df['Yearsdiff'] = df['Year']-df['Year Onboarded']
Чтобы рассчитать совокупный средний доход, я попробовал следующие методы:
- Первая попытка:
df = df.join(df.groupby(['Year']).expanding().agg({ 'Revenue': 'mean'})
.reset_index(level=0, drop=True)
.add_suffix('_roll'))
df.groupby(['Year Onboarded', 'Year']).last().drop(columns=['Revenue'])
Выходные данные начинают накапливаться, но последняя строка больше не накапливается (не уверен, почему).
- Вторая попытка:
df.groupby(['Year Onboarded','Year']).agg('mean')
.groupby(level=[1])
.agg({'Revenue':np.cumsum})
Но это не работает должным образом, я пробовал и другие способы, но не добился хороших результатов.
Чтобы визуализировать совокупный средний доход, я просто использую sns.lineplot
Моя цель — получить график, аналогичный приведенному ниже, но для этого мне сначала нужно правильно сгруппировать мои данные.
График ожидаемого результата
Годы, которые мы видим на графике, представляют собой «Год на борту», а не «Год».
Может кто-нибудь помочь мне рассчитать совокупный средний доход, который работает для построения графика, подобного приведенному выше? Спасибо
Кроме того, данные, предоставленные в наборе данных toy, наверняка не дадут чего-то похожего на примерный график, но идея должна быть там.
Ответ №1:
Вот как я бы это сделал, и, учитывая, что данные об игрушках не совпадают, вероятно, следует внести некоторые изменения, но в целом:
import seaborn as sns
df1 = df.copy()
df1['Yearsdiff'] = df1['Year']-df1['Year Onboarded']
df1['Revenue'] = df.groupby(['Year Onboarded'])['Revenue'].transform('mean')
#Find the average revenue per Year Onboarded
df1['Revenue'] = df1.groupby(['Yearsdiff'])['Revenue'].transform('cumsum')
#Calculate the cumulative sum of Revenue (Which is now the average per Year Onboarded) per Yearsdiff (because this will be our X-axis in the plot)
sns.lineplot(x=df1['Yearsdiff'],y=df1['Revenue'],hue=df1['Year'])
#Finally plot the data, using the column 'Year' as hue to account for the different years.
Комментарии:
1. Я действительно пробовал что-то подобное, но, похоже, это не сработало. Также предполагается, что год на графике должен быть «Год на борту», я должен был упомянуть об этом, извините
Ответ №2:
Вы можете создать скользящее среднее значение следующим образом:
df['rolling_mean'] = df.groupby(['Year Onboarded'])['Revenue'].apply(lambda x: x.rolling(10, 1).mean())
df
# ClientId Year Onboarded Year Revenue rolling_mean
# 0 1 2018 2019 100 100.000000
# 1 2 2019 2019 50 50.000000
# 2 3 2020 2020 25 25.000000
# 3 1 2018 2019 30 65.000000
# 4 2 2019 2019 40 45.000000
# 5 3 2020 2020 50 37.500000
# 6 1 2018 2018 60 63.333333
# 7 2 2019 2020 100 63.333333
# 8 3 2020 2020 20 31.666667
# 9 1 2018 2020 40 57.500000
# 10 2 2019 2019 100 72.500000
# 11 3 2020 2020 20 28.750000
# 12 4 2016 2016 5 5.000000
# 13 4 2016 2017 5 5.000000
# 14 4 2016 2018 8 6.000000
# 15 4 2016 2019 4 5.500000
# 16 4 2016 2020 10 6.400000
# 17 4 2016 2017 20 8.666667
# 18 4 2016 2018 8 8.571429
Комментарии:
1. Что означает (10,1) в rolling() ?
2. Окно (обязательно) и минимальные периоды (необязательно)