Measuring user retention using cohort analysis with R

Cohort analysis is super important if you want to know if your service is in fact a leaky bucket despite nice growth of absolute numbers. There’s a good write up on that subject “Cohorts, Retention, Churn, ARPU” by Matt Johnson.

So how to do it using R and how to visualize it. Inspired by examples described in “Retention, Cohorts, and Visualizations” I came up with the following solution.

First, get the data in a suitable format, like this:

cohort  signed_up  active_m0  active_m1  active_m2
2011-10 12345      10432      8765       6754
2011-11 12345      10432      8765       6754
2011-12 12345      10432      8765       6754

Cohort here is in “YYYY-MM” format, signed_up is the number of users who have created accounts in the given month, active_m0 – number of users who have been active in the same month as they registered, active_m1 – number of users who have been active in the following month, and so forth. For newest cohorts you’ll be getting zeroes in some of active_mN columns, since there’s no data on them yet. This is taken into account in processing scripts.

require(plyr)

# Load SystematicInvestor's plot.table (https://github.com/systematicinvestor/SIT)
con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb'))
source(con)
close(con)

# Read the data
cohorts
# Let's convert absolute values to percentages (% of the registered users remaining active)
cohort_p as.numeric(df$active_m0/df$signed_up), as.numeric(df$active_m1/df$signed_up), as.numeric(df$active_m2/df$signed_up),
as.numeric(df$active_m3/df$signed_up), as.numeric(df$active_m4/df$signed_up), as.numeric(df$active_m5/df$signed_up),
as.numeric(df$active_m6/df$signed_up), as.numeric(df$active_m7/df$signed_up), as.numeric(df$active_m8/df$signed_up) ))

# Create a matrix
temp = as.matrix(cohort_p[,3:(length(cohort_p[1,])-1)])
colnames(temp) = paste('Month', 0:(length(temp[1,])-1), sep=' ')
rownames(temp) = as.vector(cohort_p$V1)

# Drop 0 values and format data
temp[] = plota.format(100 * as.numeric(temp), 0, '', '%')
temp[temp == " 0%"] # Plot cohort analysis table
plot.table(temp, smain='Cohort(users)', highlight = TRUE, colorbar = TRUE)

This code produces nice visualizations of the cohort analysis as a table:

I used articles “Visualizing Tables with plot.table” and “Response to Flowingdata Challenge: Graphing obesity trends” as an inspiration for this R code.

If you want to get nice colours as in the example above, you’ll need to adjust rainbow interval for plot.table. I managed to do it by editing functions code directly from R environment:

plot.table.helper.color <- edit(plot.table.helper.color)
function
(
 temp # matrix to plot
){
 # convert temp to numerical matrix
 temp = matrix(as.double(gsub('[%,$]', '', temp)), nrow(temp), ncol(temp))

highlight = as.vector(temp)
 cols = rep(NA, len(highlight))
 ncols = len(highlight[!is.na(highlight)])
 cols[1:ncols] = rainbow(ncols, start = 0, end = 0.3)

o = sort.list(highlight, na.last = TRUE, decreasing = FALSE)
 o1 = sort.list(o, na.last = TRUE, decreasing = FALSE)
 highlight = matrix(cols[o1], nrow = nrow(temp))
 highlight[is.na(temp)] = NA
 return(highlight)
}

Adjust interval in line 11 to 0.5, 0.6 to get shades of blue.
plot.table.helper.colorbar <- edit(plot.table.helper.colorbar)

function
(
 plot.matrix # matrix to plot
)
{
 nr = nrow(plot.matrix) + 1
 nc = ncol(plot.matrix) + 1

c = nc
 r1 = 1
 r2 = nr

rect((2*(c - 1) + .5), -(r1 - .5), (2*c + .5), -(r2 + .5), col='white', border='white')
 rect((2*(c - 1) + .5), -(r1 - .5), (2*(c - 1) + .5), -(r2 + .5), col='black', border='black')

y1= c( -(r2) : -(r1) )

graphics::image(x = c( (2*(c - 1) + 1.5) : (2*c + 0.5) ),
 y = y1,
 z = t(matrix( y1 , ncol = 1)),
 col = t(matrix( rainbow(len( y1 ), start = 0.5, end = 0.6) , ncol = 1)),
 add = T)
}

Adjust interval in line 21 to 0.5, 0.6 to get shades of blue.

Now if you want to draw the cycle-like graph:

# make matrix shorter for the graph (limit to 0-6 months)
temp = as.matrix(cohort_p[,3:(length(cohort_p[1,])-1)])
temp temp[temp == "0"]
library(RColorBrewer)
colnames(temp) = paste('Month', 0:(length(temp[1,])-1), 'retention', sep=' ')
palplot(temp[,1],pch=19,xaxt="n",col=pal[1],type="o",ylim=c(0,as.numeric(max(temp[,-2],na.rm=T))),xlab="Cohort by Month",ylab="Retention",main="Retention by Cohort")

for(i in 2:length(colnames(temp))) {
 points(temp[,i],pch=19,xaxt="n",col=pal[i])
 lines(temp[,i],pch=19,xaxt="n",col=pal[i])
}

axis(1,at=1:length(cohort_p$cohort),labels=as.vector(cohort_p$cohort),cex.axis=0.75)
legend("bottomleft",legend=colnames(temp),col=pal,lty=1,pch=19,bty="n")
abline(h=(seq(0,1,0.1)), col="lightgray", lty="dotted")

This code produces nice visualizations of the cohort analysis as multicolour cycle graph:


Comments

83 responses to “Measuring user retention using cohort analysis with R”

  1. This is great stuff. I’ve been asked to do produce subscription-based cohort models, i.e. How many people signed up? vs How many people subscribed in the following days? I’ve been doing most of my work in Excel, but I’m finding it hard to automate. Your code looks like something I’ll be able to learn a lot from. Aside from R, do you have any recommendations for how you could build something in Microsoft office after pulling data from a SQL query? Thanks for sharing!

  2. […] Measuring user retention using cohort analysis with R | Ivan Kuznetsov […]

  3. Great piece, Ivan! Thanks for this 🙂

  4. thanks for this article, when i try to run your script , it tell me that cohorts not found
    > con = gzcon(url(‘http://www.systematicportfolio.com/sit.gz’, ‘rb’))
    > source(con)
    > close(con)
    > cohorts
    Error: object ‘cohorts’ not found
    thanks in advance

  5. I reqd his post compleely about the diffgerence oof
    most rehent and prefeding technologies, it’s awesome article.

  6. Itss uch as yyou leadn my thoughts! Youu apear to graszp sso mucdh
    about this, succh as yoou wrrote thee ebook inn itt
    orr something. I ffeel thqt you simply can do wifh sopme p.c.

    to pressuure tthe message housse a little bit, however oother thann that, tha
    is exceellent blog. An excellennt read. I will ceryainly be back.

  7. Howdy! This iss kind oof offf topic but I nee
    some guuidance frokm aan estabhlished blog. Is iit very difficult to set up your own blog?
    I’m not very techincal but I can figure tings oout pretty fast.
    I’m thinking abot creating myy ownn butt I’m noot surfe wher
    tto start. Do you hqve any tils or suggestions? Many thanks

  8. Havee you ever thought about wrting an e-book or guet autboring onn other sites?
    I have a bloog based onn thee samke subjects youu discuss annd wold rreally lioke
    to have you share som stories/information. I kknow my subscriberts wouild ennjoy
    our work. If you are even reotely interested, feel free to senhd me aan e mail.

  9. What’s up all, her eveery one iss sharing these knowledge, thuys it’s gokod
    to read this weblog, and I used too pay a vusit thijs webpage daily.

  10. Jamesmub

    achat kamagra: acheter Kamagra sans ordonnance – pharmacie en ligne france pas cher

  11. Williamhow

    pommade ketum: fluocaril bi fluoré 250 – angine medicament sans ordonnance

  12. Williamhow

    curso online gratuito auxiliar de farmacia: se puede comprar viagra en españa sin receta – comprar viagra sin receta contrareembolso

  13. Williamhow

    comprar adventan sin receta: comprar eq zona sin receta – farmacia online genericos

  14. Williamhow

    pedido online farmacia: farmacia greco online – comprar viagra españa farmacia online

  15. Williamhow

    ozempic comprar sin receta andorra: Confia Pharma – donde puedo comprar viagra sin receta barcelona

  16. Williamhow

    tobradex unguento oftalmico: Farmacia Subito – kestine lio

  17. Hey there! Thiss plst could nnot be wrditten anny better!
    Reading thiss post reminds mme off mmy oldd
    rroom mate! He aways kept chattingg abnout this. I wijll forwwrd this write-up to him.

    Fairl certain he will have a good read. Thanos for sharing!

  18. BradleyNub

    aglae pillola scatola kestine prezzo niferex compresse

  19. MichaeldwebY

    zhekort spray nasale prezzo: quiz farmacia online – xanax 1 mg

  20. Thomasdut

    zolpidem prix pharmacie sans ordonnance: l’amoxicilline sans ordonnance – arnica montana 7 ch

  21. MichaeldwebY

    dicloreum per cervicale: Farmacia Subito – bentelan 1 mg senza ricetta

  22. Thomasdut

    exicort spray nasale: Farmacia Subito – ibuprofene 600 bustine

  23. Dannyfax

    http://farmaciasubito.com/# mascherine farmacia online

  24. Josephtut

    vitamine d en pharmacie sans ordonnance: douleur dentaire medicament sans ordonnance – ordonnance pharmacie en ligne

  25. BradleyNub

    monuril sans ordonnance pharmacie gel douche aderma voir un orl sans ordonnance

  26. MichaeldwebY

    monurelle plus: neodidro 0 266 mg prezzo – niferex prezzo

  27. Josephtut

    etacortilen collirio prezzo: Farmacia Subito – resilient 83 costo

  28. MichaeldwebY

    facoltГ  farmacia online: visunac collirio prezzo – modafinil farmacia online

  29. Dannyfax
  30. Josephtut

    puis-je consulter un orl sans ordonnance: Pharmacie Express – acheter tadalafil 5mg en ligne

  31. MichaeldwebY

    caudalie demaquillant: imodium avec ou sans ordonnance – blemish age defense skinceuticals

  32. BradleyNub

    spedra 200 mg gГ©nГ©rique que prendre pour une infection urinaire sans ordonnance vaccin grippe pharmacie sans ordonnance

  33. Josephtut

    vmp pasta per gatti controindicazioni: Farmacia Subito – xarelto 10 mg prezzo

  34. MichaeldwebY

    tobradex pomata prezzo: Farmacia Subito – senshio compresse prezzo

  35. BradleyNub

    se puede comprar prednisona sin receta test de antigenos farmacia online gactos de farmacia online gratis

  36. MichaeldwebY

    niferex a cosa serve: di base 25000 – buccolam 10 mg

  37. BradleyNub

    farmacia en casa online gastos de envГ­o gratis farmacia mallol sunyer online farmacia online sin gastos de envio

  38. Williamrib

    https://pharmexpress24.com/# russian pharmacy online usa

  39. PeterDralo

    http://pharmmex.com/# muscle relaxers mexico

  40. RogerRak

    meds from india: india online pharmacy – e pharmacy india

  41. CharlesMut

    purple pharmacy price list: canadian pharmacy no rx – mounjaro cost in mexico

  42. MatthewBlani

    Methocarbamol pharmacy customer care viagra propecia inhouse pharmacy

  43. RogerRak

    e pharmacy india: InPharm24 – buy medicines online in india

  44. MatthewBlani

    overseas pharmacy Pharm Mex mexican pharmacy stores near me

  45. CharlesMut

    cleocin online pharmacy: Prasugrel – premarin cream pharmacy

  46. Williamrib

    https://pharmexpress24.com/# prevacid online pharmacy

  47. RogerRak

    what to get at mexican pharmacy: Pharm Mex – international pharmacy online

  48. Randallmaymn

    best indian pharmacy: india pharmacy market outlook – retail pharmacy market in india

  49. MatthewBlani

    order medicine online india InPharm24 india medicine

  50. CharlesMut

    uk online pharmacy international delivery: kaiser permanente online pharmacy – winn dixie pharmacy

  51. RogerRak

    lexapro pharmacy coupons: asda viagra pharmacy – custom rx pharmacy kuna

  52. Randallmaymn

    los algodones purple pharmacy prices: mexican pharmacy coupon code – buy viagra in mexico

  53. Williamrib

    https://inpharm24.com/# india pharmacy viagra

  54. MatthewBlani

    all day pharmacy india ex officio member of pharmacy council of india india pharmacy reviews

  55. RogerRak

    india pharmacy of the world: history of pharmacy in india – online pharmacy in india

  56. CharlesMut

    medicine from india: india pharmacies – pharmacy india website

  57. MatthewBlani

    cheap online prescriptions Pharm Mex medicine mexico

  58. RogerRak

    medicine from india: medicine delivery in vadodara – b pharmacy salary in india

  59. Williamrib

    https://inpharm24.com/# online pharmacy company in india

  60. MatthewBlani

    asacol pharmacy celebrex target pharmacy generic zoloft online pharmacy

  61. CharlesMut

    the peoples pharmacy: Pharm Express 24 – concerta online pharmacy

  62. Randallmaymn

    levitra mexican pharmacy: Pharm Mex – mexico meds

  63. RogerRak

    worldwide pharmacy online: Pharm Express 24 – online pharmacy quick delivery

  64. MatthewBlani

    pharmacy store requirements Pharm Express 24 renova online pharmacy

  65. Randallmaymn

    tretinoin cream mexican pharmacy: mexican pharmacy methylphenidate – online pharmacy for pain relief

  66. RogerRak

    buy mounjaro from mexico: purple pharmacy mexico – adderall in mexican pharmacy

  67. CharlesMut

    divya pharmacy india: medicine online india – online medicine order

  68. MatthewBlani

    pharmacies in india InPharm24 pharmacy online india

  69. Williamrib

    https://inpharm24.com/# drugs from india

  70. RogerRak

    mexico pharmacy drug list: tijuana pharmacy prices – can you buy antibiotics over the counter in mexico

  71. CharlesMut

    india e-pharmacy market size 2025: pharmacies in india – ex officio member of pharmacy council of india

  72. MatthewBlani

    differin guardian pharmacy phendimetrazine online pharmacy cheapest pharmacy to fill prescriptions without insurance

  73. RogerRak

    india pharmacy reviews: india pharmacy delivery – online pharmacy app developer in india

  74. CharlesMut

    buy steroids from mexico: buy medications – percocet mexico

  75. MatthewBlani

    god of pharmacy in india InPharm24 b pharmacy fees in india

  76. RogerRak

    xanax cost in mexico: mexican pharmacy online medications – buy semaglutide online mexico

  77. Williamrib

    https://pharmmex.shop/# amoxicillin mexican store

  78. MatthewBlani

    buy drugs from india online pharmacy india ship to usa buy drugs from india

  79. RogerRak

    Cefixime: strattera online pharmacy – aciclovir in pharmacy

  80. CharlesMut

    meijers pharmacy: general health – target pharmacy montelukast

  81. MatthewBlani

    Atarax viagra apollo pharmacy rx express pharmacy hurley ms

  82. RogerRak

    mexican pharmacy mail order: mexican pharmacy chains – tramadol in mexico name

  83. Williamrib

    https://pharmmex.com/# overseas pharmacy

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.