clvkit.CohortMatrix#
- class CohortMatrix(matrix, *, metric, period)[source]#
Bases:
objectA cohort-by-period matrix of retention or revenue, and its heatmap.
Rows are acquisition cohorts (the period of a customer’s first observed purchase); columns are whole periods elapsed since that cohort’s own period. Cell values are:
metric="retention"the number of distinct customers of that cohort active in that period (a customer buying three times in one period counts once).
metric="revenue"the total amount those customers spent in that period.
Recent cohorts have been observed for fewer periods, so the matrix is a triangle: cells past a cohort’s observation window are
NaN, never0. A zero means “observed, nobody bought”; missing means “not yet knowable”. Because of thoseNaNcells the retention matrix is float-typed even though it counts customers.>>> matrix = CohortMatrix.from_transactions(df, period="M") >>> matrix.to_pandas(relative=True) # retention rates >>> matrix.plot() # the heatmap
There is no
fit(): a pivot has no state to estimate.- classmethod from_transactions(transactions, *, period='M', metric='retention', customer_id_col='customer_id', datetime_col='date', amount_col='amount', datetime_format=None, engine='pandas')[source]#
Pivot a raw transaction log into a cohort-by-period matrix.
periodis any pandas offset alias ("M","W","Q","Y"); it sets both the cohort grain and the column grain, since a cohort matrix only makes sense when both use the same clock.The observation window ends at the last transaction in the log, and that is what makes a cell unobserved rather than zero.
engine="dask"takes adask.dataframe.DataFrameand reduces the log without holding it in memory; the matrix it returns is the same pandas one, since a cohort-by-period grid is small whatever built it. It needs the optionaldaskextra.
- to_pandas(*, relative=False)[source]#
The matrix as a DataFrame: cohorts down, periods across.
relative=Truedivides every cohort by its own period-0 value — retention rates rather than counts, or a revenue index rather than currency. That is the comparable view, since cohorts differ in size.
- to_json(*, relative=False)[source]#
Cohort-keyed JSON, the same shape as
to_pandas().Unobserved cells serialise as
null, keeping the triangle’s shape legible outside pandas.
- plot(ax=None, *, relative=True, **kwargs)[source]#
Draw the cohort heatmap — the standard triangle chart.
Defaults to the relative view because that is what the chart is read for: how fast each cohort decays, independent of how big it was.
- Parameters:
ax (Axes | None)
relative (bool)
- Return type:
Axes