Начало 2020 года, вы - обычный продукт-мендежер, которому предложили развивать кредитный продукт в другой стране. Оффер принят, документы оформлены, пора за работу. Первое, что приходит в голову посмотреть, что там с экономикой продукта. И как вообще ведет себя продукт. Еще через пару дней совещание, на котором вас просят ответить на несколько вопросов:
1. Сейчас мы платим за привлечение клиента 695494. Какая стоимость привлечения для нас является приемлемой? Имеет ли смысл повысить стоимость привлечения на клиента, чтобы получить больший объем?
2. Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?
3. Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки. Как это сказалось на продукте?
В общем-то понятные вопросы, на которые стоит уметь отвечать любому владельцу продукта. Но есть проблема. Метрики, конечно, все посчитаны: LTV, СAC и прочее. Есть финансовая отчетность, где видны все расходы и доходы, и видно, что продукт в небольшом операционном плюсе. Но на вышеозначенные вопросы ответить сложно. Поиск ответов может занять кучу встреч и разговоров(которые еще и в меру субъективны), задач на аналитику(итерации чего занимают время) и попыток прокрутить дашборд(интерпретация которых может быть неверной).
Ответить на вопросы можно быстро и однозначно, четко посмотрев, что там в сырых данных. Большинство процессов в продукте оставляют следы в базах данных. А ядро почти любого финасового продукта - транзакции, в них и предлагается смотреть ниже.
Пример взят из реальной практики. То есть вот прям все взаправду, данные подшумлены, но это реальный портфель. И анализируются данные примерно таким образом.
Для того, чтобы анализировать, понадобятся следующие инструменты: Rstudio, dbeaver(или аналог). Далее рассматривается реальный пример, как можгут выглядеть эти данные и что с ними можно сделать.
Итак, транзакции. Напишем в базу нечто вроде select * from transactions t и посмотрим результат. Также узнаем курс местной валюты к доллару(для примера возмьем, что курс без динамики и составляет 0.00003 доллара за местную валюту).
slice(lk, 1:20)
Видим всю историю транзакций по всем клиентами. Проанализируем состав полей(обычно можно посмотреть в документации, но кое-что понять можно и так). У нас есть идентификаторы заемщика, контракта, и тразнакции. Дата выдачи кредита (disbursment_date). Отметка о пролонгации кредита(prolongations_count) - перенос даты выплаты за отдельный платеж. Размер и дата транзакции. Отметка о “мягком” удалении. Главное - тип транзакции(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='Выдача кредитов в месяц')
]
Аналитически видно, что масштабирование продукта в последние несколько месяцев остановилось. Выдаем столько же сколько и выдавали.
Глобально мы занимаемся масштабированием пользователей, ведь кредит без человека выдать сложно. А юнит экономика в таком - это сколько мы зарабатываем или теряем на одном пользоватале, заплатив за его привлечение.
Давайте посчитаем доходную часть. Чтобы это сделать, нужно для среднего пользовталеля взять кумулятивный баланс его доходов и расходов(сумму транзакций выдач и возвратов кредитов) и наложить на время его жизни. Удобнее работать с относительным временем, так сможем сравнивать пользователей, пришедших в разное время:
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))
]
Получившаяся кривая показывает его LTV c динамикой по времени. И это уже близко к ответу на первый вопрос о стоимости привлечения пользователя.
Но перед тем как пустится в эти рассуждения, стоит вспомнить, кто такой, этот средний пользователь. Мало ли, может, лучшие времена продукта давно позади. Поэтому стоит посмотреть этот же график, но разбив по поколениям и посмотрев последние 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)+tt+ff+
theme(legend.text = element_text(size=20),
legend.title = element_text(size=25))+
guides(colour = guide_legend(override.aes = list(size=10)))
# geom_vline(xintercept = c(140,180),col='red')
]
В принципе теперь, все что нужно для юнит экономики есть на этом графике.
Если каждая траектория - это поколение пользователей (месяц в котором выдан первый кредит), то мы можем сделать несколько важных выводов исходя из следующего:
Воспользуемся полученными знаниями и поррасуждаем об ответах на вопросы к предстоящему совещанию
1. Сейчас мы платим 695494. Какая стоимость привлечения для нас является приемлемой? Имеет ли смысл повысить стоимость привлечения на клиента, чтобы получить больший объем?
Ситуация выглядит следующим образом - у нас есть успешный продукт, который мы не масштабируем - и это проблема. Ожидания по доходности от клиента на дистанции год - 40-60 долларов. Текущие затраты на привлечение $20.8 (695494* 0.00003) В приницпе - увеличение стоимости привлечения наша экономика выдержит, портфель не станет убыточным. Но в продукте - длинный срок окупаемости клиента. Если мы можем позволить себе тратить сейчас - что бы заработать потом - эксперименты оправданы.
2. Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?
Портфель устойчиво положительный, с динамикой к росту за счет практик развития клиентов в первые дни жизни. Главное пространство для идей - механика работы с клиентами возраста 100+ дней. Там существенных прорывов пока не было.
3. Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки. Как это сказалось на продукте?
Вообще - видно что поколения в которых первый кредит был меньшим по размерам окупали себя чуть лучше. Четкий ответ - только через АБ тест.
Помните про скорость принятия решений? 2.2 млн строк рассказали о том, что происходит. Такой анализ занимает от 30 минут до пары часов. В зависимости от знания предметной области и грязи в данных. Для такого анализа не нужно ничего, кроме сырых данных и открытого ПО. Несколько десятков строк кода, чуть здравых размышлений и экономика продукта ясна, посчитана и выводы сделаны.
Из этих же данных несложно собирается еще несколько важных оценок и выводов , но о них в другой раз.
To be continued
Отдельное спасибо Наталье Ионовой. Идея, структура, редактура.