Análisis de productos en la práctica con R

Problemático

El meta moderno para la gestión de productos se basa en datos.





Todos quieren un enfoque analítico y la capacidad de tomar decisiones sobre la gran cantidad de datos de productos que están disponibles. Pero en realidad, hay una falta de información sobre cómo hacer esto exactamente. Qué herramientas usar, cómo tomar decisiones y cómo explorar los datos. Me gustaría compartir precisamente el aspecto práctico de este tema en el formato de un caso.





Parte introductoria

A principios de 2020, usted es un gerente de producto ordinario al que se le ofreció desarrollar un producto de préstamo en otro país. Se ha aceptado la oferta, se han completado los documentos, es hora de ponerse manos a la obra. 





Lo primero que me viene a la mente es ver qué está pasando con la economía del producto. Y cómo se comporta el producto en general.





Después de un par de días más, una reunión donde se le pide que responda algunas preguntas:





  1. Ahora pagamos por atraer a un cliente 695494. ¿Cuál es el costo aceptable de atraer para nosotros? ¿Tiene sentido aumentar el costo por cliente para obtener más volumen?





  2. ¿Qué tan saludable es la economía de cartera y qué dinámicas hay aquí y ahora?





  3. Recientemente cambiamos el enfoque al tamaño de la emisión y comenzamos a emitir cheques más pequeños en los primeros préstamos. ¿Cómo afectó esto al producto?





En general, preguntas claras que cualquier propietario de producto debería poder responder. 





. , , : LTV, CAC . , , , .





. ( ), ( ) ( ).





, , . .





- , .





. , , . .





, , : R ,Rstudio,dbeaver( ). , .





, .   select * from transactions t .





Rows: 2,226,532
Columns: 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 table

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
glimpse(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)))]

      
      



- ( ), :





  1. , - .





  2. , .





  3. 0, .





  4. , , .









  1. . , (150 180).





  2. . , 2018 , . “” 10-40 . 2019 : .





  3. 40 60 . . , , 120-150 3





  4. 90 , .





,





1. 695494. ? , ?





- , - . - 40-60 . $20.8 (695494* 0.00003)





- , . - . 





- - . 





2. ?





, . - 100+ . 





.





3. . ? 





- . - .





El trabajo del gerente de producto es tomar decisiones. 2,2 millones de líneas hablaron sobre lo que estaba sucediendo. Dicho análisis toma de 30 minutos a un par de horas, dependiendo del conocimiento del área temática y de la suciedad en los datos. Este análisis no requiere más que datos sin procesar y software de código abierto.





Varias docenas de líneas de código, un poco de sentido común y la economía del producto es clara, calculada y se extraen conclusiones.





Varias evaluaciones y conclusiones más importantes se recopilan fácilmente a partir de los mismos datos, pero sobre ellos en un tiempo de arco.








All Articles