Первая часть про про разбор юнит экономики на реальных примерах

Вводная часть

Ничего не предвещало и было начало 2020 года. Вы обычный продукт мендежер, которому предложили развивать кредитный продукт в какой нибудь другой стране. Оффер принят, документы оформлены - пора за работу. Первое что приходит в голову посмотреть - что там с экономикой. Как вообще себя ведет продукт. А тут еще через пару дней совещание, на котором вас просят расказать - пару вопросов.

  1. Какая стоимость привлечения для нас является приемлемой? Сейчас мы платим 695494. - имеет ли смысл повысить стоимость привлечения на клиента что бы получить больший объем?
  2. Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?
  3. Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки - как это сказалось на продукте?

В общем то понятные вопросы, на которые стоит уметь отвечать любому владельцу продукта. Но есть проблема. Метрики конечно все посчитаны. LTV, СAC и прочее. Есть фин отчетность - где все все расходы и доходы и видно что продукт в небольшом операционном плюсе.

Но на вышеозначенные вопросы - ответить сложно с такого прикупа. Поиск ответов может занять кучу встреч и разговоров, задач на анлитику и попыток прокрутить дешборд.

Есть другая идея - четко посмотреть что там в данных. Большинство процессов в продукте - оставляют следы в базах данных. Ядро почти любого продукта финасового продукта - транзакции. В них и посмотрим

Анализируй это

напишем в базу нечто вроде select * from transactions t и посмотрим результат так же узнаем курс местной валюты к доллару ( для примера возмьем что курс без динамики и составляет 0.00003 доллара за местную валюту)

slice(lk, 1:20)

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

У нас есть айди заемщика, контракта, и тразнакции. Дата выдачи кредита (disbursment_date ) - отметка о пролонгации кредита (перенос даты выплаты за отдельный платеж) и размер и дата транзакции. Есть еще отметка о “мягком” удалении. Главное - тип транзакции ( ContractAdd- возврат денег заемщиком, DisburseTransaction - выплата денег заемщику )

Теперь об экономике продукта. Принципиально кредитиный бизнес работает просто. (как и большинство бизнесов) Заплатили что бы привести пользователя, дали кредит, собрали денег - дали еще кредит.

Два финансовых потока - от нас к пользователю и от пользователя к нам формируют нашу выручку по продукту. А в нашей табличке есть все данные, что бы посчитать.

Чуть обработаем данные и приведем их нужную форму. Назовем транзакции удобно и сделаем отрицательными транзакции выдачи кредитов. (поля z_type и am)

lk %>% data.table()->lk1
lk1 %>% glimpse()
## Rows: 2,226,532
## Columns: 11
## $ X1                  <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15…
## $ borrower_id         <dbl> 2, 2, 2, 6, 6, 12, 12, 12, 12, 16, 20, 20, 20, 20…
## $ con_id              <dbl> 1, 1, 1, 2, 2, 4, 4, 4, 4, 5, 7, 7, 7, 7, 8, 9, 9…
## $ disbursement_date   <date> 2017-11-23, 2017-11-23, 2017-11-23, 2017-11-24, …
## $ prolongations_count <dbl> 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3, 3, 0, 0, 0…
## $ loan_type           <chr> "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", …
## $ date                <date> 2017-12-15, 2017-11-23, 2017-12-06, 2017-11-24, …
## $ type                <chr> "Payments::Transaction::ContractAddTransaction", …
## $ amount              <dbl> 250000, 1000000, 1200000, 2500000, 3500000, 10400…
## $ id                  <dbl> 325, 2, 127, 5, 587, 557500, 557499, 557504, 5575…
## $ deleted_at          <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
lk1[,':='(z_type=z_type<-fifelse(type=='Payments::Transaction::ContractAddTransaction','add','disb'),am=amount*fifelse(z_type=='add',1,-1))][1:20,c(-1,-11,-8,-6)]
lk1[disbursement_date<'2020-01-01' & date<='2020-03-01',c(-1,-11,-8,-6)]->lk1

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

lk1[,.(total_in_blns=sum(am*for_ex)/1e6),.(z_type)]

Ясный и понятный результат - транзакции от заемщиков (add)значительно превышают транзакции от выдачи кредита (disb) А ведь часть кредитов наверняка только выданна

заодно разберемся с каким темпом выдвавали кредиты

lk1[!is.na(disbursement_date)&z_type=='disb',.(sum=sum(am*for_ex*-1,na.rm = T)/1e6),.(date=floor_date(disbursement_date,'month',))][,
ggplot(.SD,aes(date,sum,label=round(sum,2)))+
geom_col(fill=polar_night[2])+ff+tt+
  geom_text(aes(y=sum+0.1),col=aurora[1])+
  labs(x='месяц выдачи',y='выдача в миллионах долларов',title='Выдача кредитов в месяц')
  

]

Аналитически видно - что масштабирование продукта пока не происходит. Выдаем столько же сколько и выдавали. (конечно можно погрузится в вопрос - может перестали выдавать повторные)

Юнит экономика

Мы масштабируем пользователей. (кредит без человека выдать сложно). А юнит эконмика - это сколько мы зарабатываем или теряем на одном пользоватале, заплатив за его привлечение.

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

Получившаяся кривая - покажет его LTV c динамикой по времени. Это уже близко к ответу на вопрос - за сколько мы можем привлекать пользоваталя.

lk1[][,':='( min_date=min(disbursement_date)),.(borrower_id)][,c("gen",'dif'):=.(floor_date(min_date,'1 month'),as.numeric(date-min_date))][,n:=uniqueN(borrower_id),][,
  .(sum=sum(am*for_ex),n=unique(n)),
  .(dif)
][order(dif)][,":="(bal=bal<-sum/n,cum=cumsum(bal))][,
                           ggplot(.SD,aes(dif,cum))+
                             geom_line()+
                             tt+ff+
                                  labs(x='дни жизни заемщика',y='доход в USD',col='поколение',title='LTV клиента по поколениям и по годам')+
                             scale_y_continuous(breaks = seq(-200,200,20),labels =paste0('$',seq(-200,200,20),'k' ))+
                             scale_x_continuous(breaks = seq(0,1000,20))
                           
                           ]

Но перед тем как пустится в эти рассуждения - стоит вспомнить. Что средний пользователь - штука довольно абстрактная. Мало ли, может лучшие времена продукта давно позади. Стоит посмотреть этот же график, но разбив по поколениям и посмотрев последние 24 поколения. сразу же наложим сюда стоимость привлечения и разобьем по годам

lk1[][,':='( min_date=min(disbursement_date)),.(borrower_id)][,c("gen",'dif'):=.(floor_date(min_date,'1 month'),as.numeric(date-min_date))][,n:=uniqueN(borrower_id),.(gen)][,
  .(sum=sum(am*0.00003),n=unique(n)),
  .(gen,dif)
][order(gen,dif)][,":="(bal=bal<-sum/n)][,':='(cum=cumsum(bal),m_dif=max(dif)),.(gen)][dif<=m_dif-30 & gen %between% c('2018-01-01','2021-03-31')][,
                           ggplot(.SD,aes(dif,cum,col=factor(gen)))+
                             geom_line()+
                             facet_wrap(~factor(year(gen),levels = c(2019,2018)),nrow=2)+tt+ff+
                             labs(x='дни жизни заемщика',y='доход в USD',col='поколение',title = 'LTV клиента по поколениям и по годам')+
                             scale_y_continuous(breaks = seq(-200,200,20),labels =paste0('$',seq(-200,200,20),'k' ))+
                             scale_x_continuous(breaks = seq(0,1000,20))+
                             geom_hline(yintercept = 695494*for_ex,color='red',size=1)+
                             geom_hline(yintercept = 0,color='dark red',linetype='dashed')+
                             geom_text(inherit.aes = F,aes(x=as.Date(600),y=695494*for_ex+3,group=1),label='Стоимость привлечения клиента = $20.86',col='red',size=6)
                           
                           ]

Ок. В принципе все что нужно для юнит экономики - на этом графике.

Мы тут ради ответов а не картинки смотреть

1. Какая стоимость привлечения для нас является приемлемой? Сейчас мы платим 695494 ($20.8) - имеет ли смысл повысить стоимость привлечения на клиента что бы получить больший объем?

Вообще, максимальная стоимость привлечения - около 80 долларов. Это правда выводит срок окупаемости поколения в 460-600 дней.
В практическом смысле запас явно есть и если есть и 5-10 долларов к стоимости привлечения за нелинейный рост количества - выглядит разумным. Если мы наши операционные расходы не слишком велики - то экономика продукта это явно перенесет. А с учетом того, что мы не наращиваем объемы, имея позитивную юнит экономику - проэксперементировать с этим явно стоит.

2. Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?

Портфель устойчиво положительный, с динамикой к росту. Каждое поколение окупает себя быстрее,чем предыдущие и имеет лучшую тракеторию

3. Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки - как это сказалось на продукте?

По положению стартовой точки на графиках (нулевой день - это день выдачи первого кредита) видно что размер выданного кредита стал меньше. Без АБ тестов сложно сказать с уверенностью - что стало лучше - но есть основания считать что это пошло на пользу.

Вывод и всякое такое

Это пример из реальной практики. То есть вот прям все взаправду, данные подшумлены, но это реальный портфель. И анализируются данные примерно таким образом.

2.2 млн строк рассказали о том что происходит. Помните про скорость принятия решений? Такой анализ занимает от 30 минут до пары часов. В зависимости от знания предметной области и грязи в данных.

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

Когда мы окупаем, сколько стоит привлекать, становится ли лучше экономика, как мы работаем.