2015-02-26 25 views
5

Generieren habe ich eine Pandas Datenrahmen, die wie folgt aussieht:eine Retentions Kohorte von einem Pandas Datenrahmen

+-----------+------------------+---------------+------------+ 
| AccountID | RegistrationWeek | Weekly_Visits | Visit_Week | 
+-----------+------------------+---------------+------------+ 
| ACC1  | 2015-01-25  |    0 | NaT  | 
| ACC2  | 2015-01-11  |    0 | NaT  | 
| ACC3  | 2015-01-18  |    0 | NaT  | 
| ACC4  | 2014-12-21  |   14 | 2015-02-12 | 
| ACC5  | 2014-12-21  |    5 | 2015-02-15 | 
| ACC6  | 2014-12-21  |    0 | 2015-02-22 | 
+-----------+------------------+---------------+------------+ 

Es ist im Wesentlichen ein Prüfprotokollblatt der Art, wie sie eine Kohortenanalyse für die Erstellung alle notwendigen Daten enthält.

Jede Registrierungswoche ist eine Kohorte. Um zu wissen, wie viele Menschen Teil der Kohorte sind ich verwenden kann:

visit_log.groupby('RegistrationWeek').AccountID.nunique() 

tun, was ich will eine Pivot-Tabelle mit den Registrierungs Wochen als Schlüssel erstellen. Die Spalten sollten die visit_weeks sein und die Werte sollten die Anzahl eindeutiger Konto-IDs sein, die mehr als 0 wöchentliche Besuche haben.

Zusammen mit den Gesamtkonten in jeder Kohorte kann ich dann Prozentsätze anstelle von absoluten Werten anzeigen.

Das Endprodukt würde wie folgt aussehen:

+-------------------+-------------+-------------+-------------+ 
| Registration Week | Visit_week1 | Visit_Week2 | Visit_week3 | 
+-------------------+-------------+-------------+-------------+ 
| week1    | 70%   | 30%   | 20%   | 
| week2    | 70%   | 30%   |    | 
| week3    | 40%   |    |    | 
+-------------------+-------------+-------------+-------------+ 

Ich versuchte, den Datenrahmen wie das Schwenken:

visit_log.pivot_table(index='RegistrationWeek', columns='Visit_Week') 

Aber ich habe den Wert Teil nicht festgenagelt. Ich muss die Kontonummer irgendwie zählen und die Summe durch die Registrierungswochenaggregation von oben dividieren.

Ich bin neu in Pandas, also wenn dies nicht der beste Weg, um Retention Kohorten zu tun, bitte erleuchte mich!

Dank

+0

Können Sie ein Beispiel Ihres Dataframe in eine gültige HTML-Tabelle einfügen? Das würde anderen erlauben, es in Pandas zu lesen, um ihre Antworten auf Ihre Frage zu QA zu geben. –

Antwort

9

Es gibt mehrere Aspekte auf Ihre Frage.

Was Sie mit den Daten erstellen können müssen Sie

Es several kinds of retention sind. Der Einfachheit halber werden wir nur zwei erwähnen:

  • Day-N-Aufbewahrung: Wenn ein Benutzer am Tag 0 registriert ist, hat sie sich am Tag N eingeloggt? (Der Logging-Tag N + 1 beeinflusst diese Metrik nicht). Um es zu messen, müssen Sie alle Protokolle Ihrer Benutzer verfolgen.
  • Rolling Retention: Wenn ein Benutzer am Tag 0 registriert, hat sie sich am Tag N oder einem beliebigen Tag danach eingeloggt? (Das Anmelden am Tag N + 1 wirkt sich auf diese Metrik aus). Um es zu messen, brauchen Sie nur die letzten bekannten Logs Ihrer Benutzer.
  • Wenn ich Ihre Tabelle richtig verstehe, haben Sie zwei relevante Variablen, um Ihre Kohorten-Tabelle zu erstellen: Registrierungsdatum und letztes Protokoll (Besuchswoche). Die Anzahl der wöchentlichen Besuche scheint irrelevant.

    Also mit diesem können Sie nur mit Option 2, rollende Retention gehen.

    Wie die Tabelle bauen

    Lassen Sie uns zunächst ein Dummy-Datensatz aufbauen, damit wir genug zu arbeiten und Sie können es reproduzieren:

    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))) 
    

    So, jetzt sollten wir etwas haben, das sieht wie folgt aus:

    users.head() 
    

    enter image description here

    Hier ist ein Code eine Kohorte-Tabelle zu erstellen:

    ### 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)))) 
             ]) 
    

    Damit wir die eigentliche Funktion erstellen:

    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 
    

    Jetzt können Sie es nennen, und das Ergebnis sehen:

    cohort_table(users) 
    

    enter image description here

    Hoffe, dass eshilft

    0

    Mit dem gleichen Format users Daten von rom_j Antwort wird dies sauberer/schneller, aber funktioniert nur unter der Annahme, dass es mindestens eine Anmeldung/Abwanderung pro Woche gibt. Keine schreckliche Annahme von ausreichend großen Datenmengen.

    users = users.applymap(lambda d: d.strftime('%Y-%m-%V') if pd.notnull(d) else d) 
    tab = pd.crosstab(signup_date, last_log) 
    totals = tab.T.sum() 
    retention_counts = ((tab.T.cumsum().T * -1) 
            .replace(0, pd.NaT) 
            .add(totals, axis=0) 
            ) 
    retention = retention_counts.div(totals, axis=0) 
    
    realined = [retention.loc[a].dropna().values for a in retention.index] 
    realigned_retention = pd.DataFrame(realined, index=retention.index) 
    
    Verwandte Themen