Ci sono diversi aspetti alla tua domanda.
Che cosa si può costruire con i dati che avete
ci sono several kinds of retention. Per semplicità, ne menzioniamo solo due:
- Ritenzione giorno-n: se un utente si è registrato il giorno 0, ha effettuato l'accesso il giorno N? (La registrazione nel giorno N + 1 non ha effetto su questa metrica). Per misurarlo, è necessario tenere traccia di tutti i registri dei propri utenti.
- Ritenzione di rotazione: se un utente si è registrato il giorno 0, ha effettuato l'accesso il giorno N o in qualsiasi giorno successivo a quello? (L'accesso al giorno N + 1 influisce su questa metrica). Per misurarlo, hai solo bisogno degli ultimi registri di conoscenza dei tuoi utenti.
Se comprendo correttamente la tabella, sono disponibili due variabili rilevanti per creare la tabella di coorte: data di registrazione e ultimo registro (visita settimana). Il numero di visite settimanali sembra irrilevante.
Quindi con questo si può andare solo con l'opzione 2, mantenimento del rotolamento.
Come costruire la tabella
In primo luogo, cerchiamo di costruire un insieme di dati fittizi set in modo da avere abbastanza per lavorare e si può riprodurlo:
import pandas as pd
import numpy as np
import math
import datetime as dt
np.random.seed(0) # so that we all have the same results
def random_date(start, end,p=None):
# Return a date randomly chosen between two dates
if p is None:
p = np.random.random()
return start + dt.timedelta(seconds=math.ceil(p * (end - start).days*24*3600))
n_samples = 1000 # How many users do we want ?
index = range(1,n_samples+1)
# A range of signup dates, say, one year.
end = dt.datetime.today()
from dateutil.relativedelta import relativedelta
start = end - relativedelta(years=1)
# Create the dataframe
users = pd.DataFrame(np.random.rand(n_samples),
index=index, columns=['signup_date'])
users['signup_date'] = users['signup_date'].apply(lambda x : random_date(start, end,x))
# last logs randomly distributed within 10 weeks of singing up, so that we can see the retention drop in our table
users['last_log'] = users['signup_date'].apply(lambda x : random_date(x, x + relativedelta(weeks=10)))
Così ora dovremmo avere qualcosa che assomiglia a questo:
users.head()
Ecco il codice per costruire una tabella di coorte:
### Some useful functions
def add_weeks(sourcedate,weeks):
return sourcedate + dt.timedelta(days=7*weeks)
def first_day_of_week(sourcedate):
return sourcedate - dt.timedelta(days = sourcedate.weekday())
def last_day_of_week(sourcedate):
return sourcedate + dt.timedelta(days=(6 - sourcedate.weekday()))
def retained_in_interval(users,signup_week,n_weeks,end_date):
'''
For a given list of users, returns the number of users
that signed up in the week of signup_week (the cohort)
and that are retained after n_weeks
end_date is just here to control that we do not un-necessarily fill the bottom right of the table
'''
# Define the span of the given week
cohort_start = first_day_of_week(signup_week)
cohort_end = last_day_of_week(signup_week)
if n_weeks == 0:
# If this is our first week, we just take the number of users that signed up on the given period of time
return len(users[(users['signup_date'] >= cohort_start)
& (users['signup_date'] <= cohort_end)])
elif pd.to_datetime(add_weeks(cohort_end,n_weeks)) > pd.to_datetime(end_date) :
# If adding n_weeks brings us later than the end date of the table (the bottom right of the table),
# We return some easily recognizable date (not 0 as it would cause confusion)
return float("Inf")
else:
# Otherwise, we count the number of users that signed up on the given period of time,
# and whose last known log was later than the number of weeks added (rolling retention)
return len(users[(users['signup_date'] >= cohort_start)
& (users['signup_date'] <= cohort_end)
& pd.to_datetime((users['last_log']) >= pd.to_datetime(users['signup_date'].map(lambda x: add_weeks(x,n_weeks))))
])
Con questo siamo in grado di creare la funzione attuale:
def cohort_table(users,cohort_number=6,period_number=6,cohort_span='W',end_date=None):
'''
For a given dataframe of users, return a cohort table with the following parameters :
cohort_number : the number of lines of the table
period_number : the number of columns of the table
cohort_span : the span of every period of time between the cohort (D, W, M)
end_date = the date after which we stop counting the users
'''
# the last column of the table will end today :
if end_date is None:
end_date = dt.datetime.today()
# The index of the dataframe will be a list of dates ranging
dates = pd.date_range(add_weeks(end_date,-cohort_number), periods=cohort_number, freq=cohort_span)
cohort = pd.DataFrame(columns=['Sign up'])
cohort['Sign up'] = dates
# We will compute the number of retained users, column-by-column
# (There probably is a more pythonesque way of doing it)
range_dates = range(0,period_number+1)
for p in range_dates:
# Name of the column
s_p = 'Week '+str(p)
cohort[s_p] = cohort.apply(lambda row: retained_in_interval(users,row['Sign up'],p,end_date), axis=1)
cohort = cohort.set_index('Sign up')
# absolute values to percentage by dividing by the value of week 0 :
cohort = cohort.astype('float').div(cohort['Week 0'].astype('float'),axis='index')
return cohort
Ora si può chiamare e vedere il risultato:
cohort_table(users)
Spero che sia utile
È possibile incollare un campione di DataFrame in una tabella HTML valida? Ciò consentirebbe ad altri di leggerlo in panda per rispondere alle domande del QA. –