Проблематика
Современная мета управления продуктом подразумевает управление на основании данных.
Все хотят аналитического подхода и способности принимать решения на куче данных о продукте которые есть. Но в реальности есть недостаток информации о том, как именно это делать. Какие инструменты использовать, как принимать решения и как исследовать данные. Я бы хотел поделится именно практическим аспектом этого вопроса в формате одного кейса.
Вводная часть
Начало 2020 года, вы - обычный продукт-менеджер, которому предложили развивать кредитный продукт в другой стране. Оффер принят, документы оформлены, пора за работу.
Первое, что приходит в голову посмотреть, что там с экономикой продукта. И как вообще ведет себя продукт.
Еще через пару дней совещание, на котором вас просят ответить на несколько вопросов:
-
Сейчас мы платим за привлечение клиента 695494. Какая стоимость привлечения для нас является приемлемой? Имеет ли смысл повысить стоимость привлечения на клиента, чтобы получить больший объем?
-
Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?
-
Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки. Как это сказалось на продукте?
В общем-то понятные вопросы, на которые стоит уметь отвечать любому владельцу продукта.
Но есть проблема. Метрики, конечно, все посчитаны: LTV, CAC и прочее. Есть финансовая отчетность, где видны все расходы и доходы, и видно, что продукт в небольшом операционном плюсе.
Но на вышеозначенные вопросы ответить сложно. Поиск ответов может занять кучу встреч и разговоров (которые еще и в меру субъективны), задач на аналитику(итерации чего занимают время) и попыток прокрутить дашборд (интерпретация которых может быть неверной).
Ответить на вопросы можно быстро и однозначно, четко посмотрев, что там в сырых данных. Большинство процессов в продукте оставляют следы в базах данных.
А ядро почти любого финансового продукта - транзакции, в них и предлагается смотреть ниже.
Анализируй это
Пример взят из реальной практики. То есть вот прям все взаправду, данные подшумлены, но это реальный портфель. И анализируются данные примерно таким образом.
Для того, чтобы анализировать, понадобятся следующие инструменты: R ,Rstudio,dbeaver(или аналог). Далее рассматривается реальный пример, как могут выглядеть эти данные и что с ними можно сделать.
Итак, транзакции. Напишем в базу нечто вроде select * from transactions t и посмотрим результат.
Rows: 2,226,532Columns: 10$ borrower_id 2, 2, 2, 6, 6, 12, 12, 12, 12, 16, 20, 20, 20, 20, 22, 23, 23, 33, 33, 39, 39, 36, 36$ con_id 1, 1, 1, 2, 2, 4, 4, 4, 4, 5, 7, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13$ disbursement_date 2017-11-23, 2017-11-23, 2017-11-23, 2017-11-24, 2017-11-24, 2017-11-27, 2017-11-27, $ prolongations_count 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1$ loan_type "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "pdl", "$ date 2017-12-15, 2017-11-23, 2017-12-06, 2017-11-24, 2017-12-25, 2017-12-29, 2017-11-27, $ type "Payments::Transaction::ContractAddTransaction", "Payments::Transaction::DisburseTran$ amount 250000, 1000000, 1200000, 2500000, 3500000, 1040000, 1500000, 10000, 1470000, 1500000$ id 325, 2, 127, 5, 587, 557500, 557499, 557504, 557507, 17, 182865, 182874, 182869, 1828$ deleted_at NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N
Видим всю историю транзакций по всем клиентами. Проанализируем состав полей(обычно можно посмотреть в документации, но кое-что понять можно и так).
У нас есть идентификаторы заемщика, контракта, и транзакции. Дата выдачи кредита (disbursment_date). Отметка о пролонгации кредита (prolongations_count) - перенос даты выплаты за отдельный платеж. Размер и дата транзакции. Отметка о "мягком" удалении.
Главное - тип транзакции(ContractAdd- возврат денег заемщиком, DisburseTransaction - выплата денег заемщику).
Теперь поговорим об экономике продукта. Принципиально кредитный бизнес работает просто(как и большинство бизнесов): заплатили, чтобы привести пользователя -> выдали кредит -> собрали деньги -> выдали еще кредит.
Выручку по продукту формируют два финансовых потока: от нас к пользователю и от пользователя к нам.
И в нашей табличке есть все данные, чтобы это посчитать.
Также узнаем курс местной валюты к доллару(для примера возьмем, что курс без динамики и составляет 0.00003 доллара за местную валюту).
-
я намеренно пропускаю тонкости анализа данных: вроде проверки таблицы на содержание, осмотр распределений, очистку и все прочее, так как статья о принятии решений, а не о программизме в данных.
-
для любителей R, данных в табличке прилично, больше 2 млн. Для таких датасетов предпочитаю data table. Но можно и на tidyverse(по запросу покажу как)
Теперь посмотрим на структуру данных и займемся обработкой.
Чуть обработаем их и приведем данные в нужный нам формат. Назовем транзакции удобно и сделаем отрицательными транзакции выдачи кредитов (поля z_type и am):
lk %>% data.table()->lk1 #Создаем отдельный объект вида data tablelk1[,':='(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)]->lk1glimpse(lk1) #посмотрим на получившийся фаил
$ borrower_id 2, 2, 2, 6, 6, 12, 12, 12, 12, 16, 20, 20, 20, 20, 22, 23, 23, 33, 33, 39, 39, 36, 36$ con_id 1, 1, 1, 2, 2, 4, 4, 4, 4, 5, 7, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13$ disbursement_date 2017-11-23, 2017-11-23, 2017-11-23, 2017-11-24, 2017-11-24, 2017-11-27, 2017-11-27, $ prolongations_count 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1$ date 2017-12-15, 2017-11-23, 2017-12-06, 2017-11-24, 2017-12-25, 2017-12-29, 2017-11-27, $ amount 250000, 1000000, 1200000, 2500000, 3500000, 1040000, 1500000, 10000, 1470000, 1500000$ id 325, 2, 127, 5, 587, 557500, 557499, 557504, 557507, 17, 182865, 182874, 182869, 1828$ z_type "add", "disb", "add", "disb", "add", "add", "disb", "add", "add", "disb", "disb", "ad$ am 250000, -1000000, 1200000, -2500000, 3500000, 1040000, -1500000, 10000, 1470000, -150
Давайте посмотрим на главное и посчитаем, прибыльный ли портфель.
Для этого посмотрим транзакции за все время. И так как цифры крупные, посмотрим сразу в миллионах:
lk1[,.(total_in_mln=sum(am*for_ex)/1e6),.(z_type)]
total_in_mln |
|
---|---|
add |
58.33176 |
disb |
-45.49114 |
Видим ясный и понятный результат: транзакции от заемщиков (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)))]
Если каждая траектория - это поколение пользователей (месяц в котором выдан первый кредит), то мы можем сделать несколько важных выводов исходя из следующего:
-
Точка, из которой начинаются линии - размер первого кредита.
-
Чем выше траектория, тем больше денег на одного пользователя мы заработали в этом поколении.
-
Чем раньше траектория поколения пересекает 0, тем быстрее мы начинаем зарабатывать на привлеченном пользователе.
-
Чем раньше линия пересекает линию стоимости привлечения, тем раньше мы зарабатываем достаточно, чтобы окупать его в данном поколении.
Выводы
-
Продукт становится лучше. Траектории более поздних поколений пересекают ноль и стоимость привлечения раньше, чем траектории старых поколений (150 дней против 180).
-
Разница в темпах окупаемости объясняется скорее стартовой точкой и первой парой кредитов. Например, поколения конца 2018 года окупались лучше, имея меньшую сумму первого кредита и большую сумму второго. Это можно понять по провалу на траектории на 10-40 днях. Так же в 2019 году: поколения с меньшей средней суммой первого кредита окупали себя намного быстрее.
-
На дистанции в один год мы заработаем на одном пользователе от 40 до 60 долларов. Максимальный размер заработка неизвестен. Ни одно поколение пока не вышло на плато, но экстраполируя, оценка в 120-150 долларов на дистанции в 3 года выглядит разумной
-
Наиболее существенное влияние на траекторию оказывают события первых 90 дней, после этого темп роста плюс минус одинаковый.
Мы тут ради ответов, а не картинки смотреть
Воспользуемся полученными знаниями и порассуждаем об ответах на вопросы к предстоящему совещанию
1. Сейчас мы платим 695494. Какая стоимость привлечения для нас является приемлемой? Имеет ли смысл повысить стоимость привлечения на клиента, чтобы получить больший объем?
Ситуация выглядит следующим образом - у нас есть успешный продукт, который мы не масштабируем - и это проблема. Ожидания по доходности от клиента на дистанции год - 40-60 долларов. Текущие затраты на привлечение $20.8 (695494* 0.00003)
В принципе - увеличение стоимости привлечения наша экономика выдержит, портфель не станет убыточным. Но в продукте - длинный срок окупаемости клиента.
Если мы можем позволить себе тратить сейчас - чтобы заработать потом - эксперименты оправданы.
2. Насколько здоровой выглядит экономика портфеля и какая динамика здесь и сейчас?
Портфель устойчиво положительный, с динамикой к росту за счет практик развития клиентов в первые дни жизни. Главное пространство для идей - механика работы с клиентами возраста 100+ дней.
Там существенных прорывов пока не было.
3. Мы недавно изменили подход к размеру выдачи и стали в первые кредиты выдавать меньшие чеки. Как это сказалось на продукте?
Вообще - видно что поколения в которых первый кредит был меньшим по размерам окупали себя чуть лучше. Четкий ответ - только через АБ тест.
Итог
Работа продукт менеджера это принимать решения. 2.2 млн строк рассказали о том, что происходит. Такой анализ занимает от 30 минут до пары часов, в зависимости от знания предметной области и грязи в данных. Для такого анализа не нужно ничего, кроме сырых данных и открытого ПО.
Несколько десятков строк кода, чуть здравых размышлений и экономика продукта ясна, посчитана и выводы сделаны.
Из этих же данных несложно собирается еще несколько важных
оценок и выводов , но о них в дуговой раз.