Разбираемся в отличии среднего чека от ARPU на примере одного интернет-магазина

от автора

Ко мне обратился коллега с вопросами про бизнес-метрики – средний чек и ARPU. Может ли показатель быть одинаков для двух метрик и не изменчив от месяца к месяцу, особенно в рамках одного бизнеса, у которого фиксированное кол-во продуктов и одна цена. Плюс, для чего бизнес старается растить данные метрики.

В этой статье я разобрался в бизнес-метриках и ответил на вопросы:

  • Что такое ARPU и средний чек? Как их рассчитывать? На какие вопросы они отвечают и для чего нужны? 

  • Могут ли они ARPU и средний чек быть  равны между собой? Будут ли отличаться в динамике месяц от месяца?

  • Что если в бизнесе кол-во продуктов фиксировано и все они с одинаковой ценой? Будет ли показатель от месяца к месяцу одинаков? А если рассчитывать среднюю выручку?

Разберемся обо всем по порядку. А для наглядности – рассчитаем данные метрики на реальных данных интернет-магазина. 

Погнали!

Что такое ARPU и средний чек? Как их рассчитывать? На какие вопросы они отвечают и для чего нужны?

Wiki дает довольно простенькое определение метрик:

Средний чек – рассматривает отношение дохода ко всем транзакциям за определенный период. Это сумма revenue на количество всех транзакций за конкретный период.

ARPU –  рассматривает отношение дохода к числу пользователей в определенный период. Это сумма revenue на количество пользователей, которые могли сделать, а могли и не сделать транзакцию в конкретный период.

Уже видим существенное отличие в знаменателе, у среднего чека это транзакции, у ARPU — это пользователи, которые могут совершать транзакции. Также видим, что в таком сравнении средний чек показывает большую точность в доходности бизнеса, так как в ARPU учитывается сегмент не платящих пользователей, которые могут оседать «мертвой» массой, искажающей картину. 

Для повышения точности, лучше рассчитывать ARPPU(average revenue per paying user) — средний доход на платящего пользователя. Опять же, есть отличие в сравнении с средним чеком, так как в знаменателе расчета ARPPU учитываются именно пользователи, совершившие одну или более транзакций за конкретный (сравниваемый) период.

Итак, ARPU (average revenue per user) — выручка продукта за определенный период, разделенная на количество активных пользователей за этот же период. Например, переходящих по разделам сайта, кликающим на кнопки, скроллящим страницы, имеющим длительную сессию и т.д..

Метрика отвечает на вопрос: сколько выручки приносит средний активный пользователей за изучаемый период времени. То есть грубо означает средний доход от клиента за период времени (определение клиента зависит от бизнеса). Метрику можно использовать, когда нужно оцифровать ценность продукта для пользователей.

Но лучше взять ARPPU — выручка на платящих пользователей (например, совершающие покупки, подкл. платные услуги, принимающие офферы, апсейялящие тариф и т.д.). То есть, учитывает не пользователей, а тех кто совершал платежи, в течение времени. Метрика помогает оценить, например как восприняли покупатели изменения цен.

Средний чек помогает понять выручку по заказам, а не по клиентам. То есть это вся выручка за месяц, разделенная на количество заказов (транзакций). Она показывает сколько денег приходится на один заказ (не на одного покупателя).

Опять же, в одном заказе (транзакции) может быть несколько продуктов – например, как в маркетплейсах, когда  в одной транзакции пользователя  может быть несколько товаров из разных категорий и с разной ценой. Например: iPhone и мороженое Baskin Robins.

Таким образом, три метрики — это разные показатели, с разными формулами расчета и отвечающими на разные запросы бизнеса.

ARPU помогает оценить финансовый потенциал компании – чем он выше и ближе к ARPPU, тем больше пользователей готовы платить за продукт. Или привлечь инвесторов, или оценить изменения в тарифной сетке. 

Учитывая количество платящих пользователей, можно оценить, за счет чего повышается доход. Доход может расти не за счет повышения цен, а за счет увеличения доли платящих пользователей. 

Также с помощью ARPU можно проаналитить результаты рекламных кампаний и качество трафика.

Средний чек — один из основных показателей успешности развития компании. По-хорошему, он должен расти, а не уменьшаться. 

Средний чек помогает оценить платежеспособность аудитории, выявить сезонность, оценить эффективность интерфейса сайта или приложения в сценариях целевых действий.

Даже если растет выручка, снижение среднего чека может говорить о том, что выручка растет за счет привлечения новых клиентов. Но в долгосрочной перспективе падает покупательская способность и необходимо корректировать цены.

Так, в месяц выхода нового iPhone существенно растет средний чек в категории товаров «гаджеты и техника». Или пользователи охотно и лучше всего оформляют подписку через тариф—конструктор, при этом в данном продукте самый низкий средний чек. Возможно, здесь нужно предоставить «коробочное» решение – тариф, который включает  в себя самые популярные подписки и выше в цене.

Могут ли ARPU и средний чек быть равны между собой? Будут ли отличаться в динамике месяц от месяца?

Нам нужен датасет. Лезем на kaggle, и берем датасет какого-нибудь e-shop.

Для анализа и расчета метрик нам нужна примерно следующая таблица:

Дата|id_пользователя|id_заказа или транзакции или продукта|название продукта|цена

Я взял вот этот датасет.

# Загружаем датасет df = pd.read_csv('sales_transactions.csv') df.head()

Работа с исходным датасетом

  • Переименуем названия столбцов для удобства.

  • Проверим качество данных (наличие пропусков, некорректные записи, запредельные значения и т.д.).

  • Приведем id транзакций, продукта и пользователей к удобному формату.

  • Приведем дату к удобному формату.

  • Проведем небольшой EDA (какие страны есть в датасете, приведем цену к единой валюте и поймем, есть ли различия и т.д.).

# Переименовываем столбцы для удобства df.set_axis(['transaction_id', 'date', 'product_id', 'product',                     'price', 'quantity', 'user_id', 'country'], axis = 'columns', inplace = True)
# Количествово строк в датасете df.shape
(536350, 8)
# Проверка на наличие пропусков for row in df.columns:     print('Кол-во пропусков в столбце ', row, '=', df[row].isnull().sum())

Пропущено 55 записей id пользователей

Это нехорошо – скорее всего это тех.баг или еще что-то из-за чего нет айдишек. Проверим.

# Пропуски в id пользаков нельзя восстановить, поэтому заменим их на ноль. df['user_id'] = df['user_id'].fillna(0)  # Посмотрим записи по таким пользователям df[df['user_id'] == 0]

Ага, у пользователей с отсутствием id в большинстве случаев отрицательная запись по количеству товаров, и transaction_id начинается с буквы «C», что означает – «возврат товара». Из данной выборки всего одна запись с положительным количеством товаров, но так же без id пользователя.

2983525582456/27/201922734Set Of 6 Ribbons Vintage Christmas10.2580.0United Kingdom

В нашем датасете всего 536 350 строк, доля строк с пропущенными id пользователей составляет меньше одного процента. Их можно удалить, без потери качества данных.

Заодно проверим, сколько у нас возвратов товара.

# Если первая буква «C» в айдишке указывает на «возврат», найдем общее количество возвратов. import re  def cancelation(x) :     x = str(x)     pattern = r'[C]'     return re.findall(pattern, x)  cancel = df['transaction_id'].apply(lambda x: True if 'C' in cancelation(x) else False)  print("Количество возвратов {}".format(cancel.sum()))

Количество возвратов 8 585

# Делаем отдельный столбец с обозначением возвратов. Понадобится для исключения «возвратов» df['cancel'] = cancel  # Считаем df['cancel'].value_counts(normalize=True)*100

Количество возвратов составляет 8 585 тыс. Это примерно полтора процента от основного датасета. Их мы тоже вычистим.

# Удалим значения с возвратами index_cancel = df[df['cancel']==True].index  df.drop(index=index_cancel, inplace=True)  # Удалим значения с нулевыми id пользаков df = df[df['user_id'] != 0]

Проверим, остались ли у нас отрицательные значения по количеству продуктов. Да и в целом, грубо прикинем по максимальным и минимальным значениям датасета (квартили)

Отрицательных значений нет, но мы видим, что есть запредельное значение по максимальному количеству товаров, 80 995 шт. чего-то. Взглянем детальней.

Ммм, один пользователь купил 80 тыс. маленьких птичек из крафтовой бумаги. Хах, у всех свои причуды. Посмотрим, есть ли еще какие-либо транзакции у данного пользователя.

Данный пользователь ранее покупал щетку и кисть для чистки кладовой. Возможно, это какой-нибудь офис-менеджер, сделавший огромный заказ (бумажных птичек) в качестве подарков сотрудникам компании или украшения офиса. То есть, это может быть реальный заказ, а не тех.баг. Однако, для нашего дальнейшего исследования по расчету среднего чека и ARPU, данное количество товара в транзакции будет выглядеть как «выброс» тянущий на себя среднее значение. Поэтому мы удалим данный заказ.

Но это очень плохая практика и на работе так лучше не делать. Потому что это реальный пользователь с настоящей покупкой, которая может оказаться «китом» среди остальных. И удаление таких пользователей приводит к искажению действительности в понимании показателей бизнеса.

Также убедимся, что у нас предоставлены данные за весь период и нет каких-либо пробелов. Для этого, сгруппируем количество транзакций (предположительно они были каждый день) по дате, и отрисуем график для наглядности.

# Смотрим период данных print('Начало периода: ', df['date'].min()) print('Конец периода: ', df['date'].max())  cnt_transaction = df.groupby('date')['transaction_id'].count().reset_index()    sns.set(font_scale=1.2) plot = cnt_transaction.plot( x = 'date', y = 'transaction_id',                          grid = True, rot=45,                          legend=False, figsize=(17,5)) plt.title('Кол-во транзакций в динамике') plt.xlabel('') plt.ylabel('Кол-во транзакций') plt.ylim(bottom=0);
Начало периода:  2018-12-01 00:00:00 Конец периода:  2019-12-09 00:00:00

Отлично! Данные представлены за весь указанный период.

Цена на товары указана в фунтах стрелингов – об этом я узнал из описания к датасету. Для нашей задачи (нахождение среднего чека и ARPU) удобнее перевести цены товаров в рубли.

Для этого парсим с страницы банка актуальный курс по валютам. Получаем датасет, находим нужную валюту и значение курса, перемножаем на цену и записываем новую цену в рублях в отдельный столбец price_rubls

import requests data = requests.get('https://www.cbr-xml-daily.ru/daily_json.js').json() df['price_rubls'] = df['price'].apply(lambda x: x * data['Valute']['GBP']['Value']).astype(int)

Итак, датасет готов для работы.

Посмотрим какие страны представлены в датасете, выведем топ-15 по количеству записей.

df['country'].value_counts().head(15)
United Kingdom    477769 France             10393 Germany            10240 EIRE                7807 Belgium             2507 Spain               2386 Netherlands         2326 Switzerland         2303 Portugal            1838 Australia           1631 Norway               927 Austria              884 Iceland              787 Finland              686 Italy                624 Name: country, dtype: int64

Ого! Кажется, этот интернет-магазин продает по всему миру, а не только в Британии, как я думал ранее.

Во время работы с датасетом я обратил внимание, что у одной даты могут быть неуникальные транзакции, и в записях одной транзакции может находится несколько продуктов с разными product_id, но одинаковым user_id.

Также стоит обратить внимание на столбец quantity.

Таким образом, для нашей задачи нужно сагрегировать датасет в примерную витрину:

Средний чек

date | transaction_id | выручка с одной транзакции (сумма всех позиций (кол-во товаров (quantity) * цену(price_rubls)), внутри одной транзакции) 

ARPU

Аналогичная витрина, только вместо transaction_id берем user_id

# Рассчитываем выручку с одного продукта внутри транзакции (количество продукта умнажаем на цену). df['revenue_per_transaction'] = (df['quantity']*df['price_rubls']).astype(int)

Теперь посмотрим топ-15 стран по выручке за весь период. Прикинем, с каким масштабом мы имеем дело, чтобы в дальнейшем рассчитанные средний чек и ARPU соотносились со здравым смыслом.

country_group = (df.groupby('country', as_index=False)['revenue_per_transaction'].sum()                  .sort_values(by='revenue_per_transaction', ascending=False)                  .head(15))  plt.figure(figsize=(17,10)) sns.set_style('darkgrid') sns.barplot(y = 'country',             x = 'revenue_per_transaction',             data = country_group,             palette = 'RdBu')  plt.title('Топ-15 стран по выручке') plt.xlabel('Выручка') plt.ylabel('');
country_group['revenue_per_transaction'] = (country_group['revenue_per_transaction'].apply(lambda x: '{0:,}'.                                                                                            format(int(x)).replace(',', ' '))) country_group

Ого! Запредельные числа. Вы только вдумайтесь, выручка Британии за год сотавила 6 179 180 204 (Шесть миллиардов сто семьдесят девять миллионов сто восемьдесят тысяч двести четыре)

Но вернемся к нашей основной задаче – сравнение среднего чека и ARPU. Будут ли они одинаковы? Будет ли метрика одинакова от месяца к месяцу?
А при фиксированном количестве продуктов и неизменной цене на данные продукты, будет ли показатель от месяца к месяцу одинаков?

Средний чек

Мы посчитали выручку для каждого продукта внутри транзакции. Теперь посчитаем итоговую выручку по всем позициям (продуктам) внутри транзакции и сгруппируем по дате.

# Для этого группируем по дате и транзакции, агрегируем сумму по посчтианной выручке за продукт group_date_tr = (df.groupby(['date','transaction_id'], as_index=False).agg({'revenue_per_transaction':'sum'})                  .sort_values(by='date'))  group_date_tr

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

# Переводим дату в месяц group_date_tr['month'] = group_date_tr['date'].astype('datetime64[M]')  # Группируем по месяцу, рассчитываем количество уникальных транзакций и сумму по всем транзакциям month_average_cheack = group_date_tr.groupby('month', as_index=False).agg({'transaction_id':'nunique',                                                     'revenue_per_transaction':'sum'})  # Переводим количество транзакций в нужный формат month_average_cheack['transaction_id'] = month_average_cheack['transaction_id'].astype(int)  # Рассчитываем средний чек. Сумма на количество month_average_cheack['average_check'] = ((month_average_cheack['revenue_per_transaction'] / month_average_cheack['transaction_id'])                                          .astype(int))
# Представим на графике в динамике по месяцам plot = month_average_cheack.plot(x = 'month', y = 'average_check',                          grid=True, rot=45,                          legend=False, figsize=(17,8)) plt.title('Средний чек в динамике по месяцам') plt.xlabel('') plt.ylabel('Средний чек') plt.show();

Ага! Видим, что от месяца к месяцу средний чек отличается. Но визуализация подобрана неудачно. Сделаем более информативно

fig = px.bar(month_average_cheack, x='month', y='average_check', color='average_check',               title='Средний чек по месяцам') fig.update_xaxes(title='Месяц') fig.update_yaxes(title='Средний чек') fig.show()

Теперь можно наглядно сравнить. И сделать вывод, что самый высокий средний чек был в январе 19го, далее была просадка. Также средний чек рос осенью 19го. Сезонность по декабрю и январю, и от года к году сравнить не можем, так как ограничены изначальным периодом датасета.

ARPU

Проделываем все то же самое, но с user_id. И в итоге сумму по всем транзакциям делим на количество уникальных пользователей.

В датасете представлены только пользователи совершившие покупку, то есть только платящие. И соответственно в данном случае ARPU=ARPPU

ARPU так же, как и средний чек отличается от месяца к месяцу. Также видим высокий показатель за январь 19го, но, что интересно, более плавный и последовательный рост с июня по август, в сравнении со средним чеком. Видимо цены не менялись, но прибавлялись пользователи.

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

Вот и все.

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

Так, а если рассчитать среднюю выручку и сравнить средний чек месяц к месяцу?

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

Пожалуйста. Мы получили усредненный показатель, но он также отличается от месяца к месяцу.

Что если в бизнесе кол-во продуктов фиксировано и все они с одинаковой ценой? Будет ли показатель от месяца к месяцу одинаков? А если рассчитывать среднюю выручку?

Так, ну а что, если у нас фиксированное количество продукта и неизменная цена? Да в принципе, ничего особенного, метрики также будут отличаться, потому что количество транзакций в случае среднего чека и количество пользователей для ARPU будут разными.

Но а все же, если количество пользователей будет одинаковым, и количество транзакций, и количество продуктов, и цена. Например, подписка на премиум-тариф от Кинопоиска (придумываю на ходу). У нас ограниченное и неизменное количество пользователей (закрытый клуб, новичков не пускаем, старички все в принятии и не уходят), всего один продукт (подписка на тариф), цена тоже зафиксирована (не снижаем по акциям, не поднимаем по инфляции). Тогда да, возможно. Но и формула при этом меняется – средняя выручка = среднему чек = ARPU. Но я такого пока не встречал.

Мой полный notebook можно скачать здесь


ссылка на оригинал статьи https://habr.com/ru/articles/761490/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *