Guide for cohort-based analytics including retention analysis, customer lifetime value calculation, behavioral segmentation, funnel analysis, and time-based cohort tracking with Python and SQL implementations.
A skill is a written procedure a bot loads when a job calls for it. This one is a single file, SKILL.md, and the whole file is on this page.
You are an expert cohort analyst who builds retention curves, calculates lifetime value, segments users by behavior, and translates cohort patterns into product and business strategy.
When to Use
Use this skill when:
User asks about cohort analyst techniques or best practices
Guide for cohort-based analytics including retention analysis, customer lifetime value calculation, behavioral segmentation, funnel analysis, and time-based cohort tracking with Python and SQL implementations.
How much does it cost?+
Nothing. It ships with Murage, which is open source. Your bots run on the AI plan you already have.
Can I change it?+
Yes. Open it in Settings → Skills to read, edit or duplicate it. Skill Guard scans it again after every edit.
Give your first job to Murage.
Download the app, connect the AI you already pay for, and tell your Chief of Staff what needs doing. Plan on about ten minutes from install to a working team.
What it teaches a bot, what it covers, and the whole file to read.
The principle
“
You are an expert cohort analyst who builds retention curves, calculates lifetime value, segments users by behavior, and translates cohort patterns into product and business strategy.
User wants to implement or improve their approach to cohort analyst
Do NOT use when:
The request falls outside the scope of cohort analyst
User needs a different specialized skill for their specific situation
The topic requires professional consultation beyond general guidance
Retention Analysis
Building a Cohort Retention Table
python
import pandas as pd
import numpy as np
def build_retention_table(df, user_col, date_col, freq='M'):
"""
Build a cohort retention table from event data.
Parameters:
df: DataFrame with user events
user_col: column name for user identifier
date_col: column name for event date
freq: 'M' for monthly, 'W' for weekly
"""
df = df.copy()
df[date_col] = pd.to_datetime(df[date_col])
# Assign cohort based on first activity
df['cohort'] = (
df.groupby(user_col)[date_col]
.transform('min')
.dt.to_period(freq)
)
# Activity period
df['activity_period'] = df[date_col].dt.to_period(freq)
# Period number (0 = acquisition period)
df['period_number'] = (
df['activity_period'].astype(int) - df['cohort'].astype(int)
)
# Cohort size
cohort_sizes = (
df.groupby('cohort')[user_col]
.nunique()
.rename('cohort_size')
)
# Active users per cohort per period
retention_data = (
df.groupby(['cohort', 'period_number'])[user_col]
.nunique()
.reset_index()
.rename(columns={user_col: 'active_users'})
)
# Merge cohort sizes
retention_data = retention_data.merge(
cohort_sizes, left_on='cohort', right_index=True
)
# Calculate retention rate
retention_data['retention_rate'] = (
retention_data['active_users'] / retention_data['cohort_size']
)
# Pivot to matrix form
retention_matrix = retention_data.pivot_table(
index='cohort',
columns='period_number',
values='retention_rate',
)
return retention_matrix, cohort_sizes
SQL Retention Query
sql
WITH user_cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', MIN(event_date)) AS cohort_month
FROM events
GROUP BY user_id
),
activity AS (
SELECT
e.user_id,
uc.cohort_month,
DATE_TRUNC('month', e.event_date) AS activity_month,
DATE_DIFF('month', uc.cohort_month,
DATE_TRUNC('month', e.event_date)) AS period_number
FROM events e
JOIN user_cohorts uc ON e.user_id = uc.user_id
),
cohort_sizes AS (
SELECT cohort_month, COUNT(DISTINCT user_id) AS cohort_size
FROM user_cohorts
GROUP BY cohort_month
),
retention AS (
SELECT
a.cohort_month,
a.period_number,
COUNT(DISTINCT a.user_id) AS active_users
FROM activity a
GROUP BY a.cohort_month, a.period_number
)
SELECT
r.cohort_month,
r.period_number,
r.active_users,
cs.cohort_size,
ROUND(100.0 * r.active_users / cs.cohort_size, 2) AS retention_pct
FROM retention r
JOIN cohort_sizes cs ON r.cohort_month = cs.cohort_month
ORDER BY r.cohort_month, r.period_number;
def funnel_analysis(df, steps, user_col='user_id', timestamp_col='timestamp'):
"""
Calculate conversion funnel metrics.
steps: list of (step_name, filter_condition) tuples
"""
results = []
for i, (step_name, condition) in enumerate(steps):
users_at_step = df.query(condition)[user_col].nunique()
if i == 0:
conversion_from_prev = 1.0
conversion_from_top = 1.0
else:
conversion_from_prev = users_at_step / results[i-1]['users']
conversion_from_top = users_at_step / results[0]['users']
results.append({
'step': i + 1,
'step_name': step_name,
'users': users_at_step,
'conversion_from_previous': conversion_from_prev,
'conversion_from_top': conversion_from_top,
'dropoff_from_previous': 1 - conversion_from_prev if i > 0 else 0,
})
return pd.DataFrame(results)
# Example usage
steps = [
('Visit Homepage', "event == 'page_view' and page == 'home'"),
('View Product', "event == 'product_view'"),
('Add to Cart', "event == 'add_to_cart'"),
('Begin Checkout', "event == 'checkout_start'"),
('Complete Purchase', "event == 'purchase'"),
]
funnel = funnel_analysis(events_df, steps)
SQL Funnel Query
sql
WITH funnel AS (
SELECT
user_id,
MAX(CASE WHEN event = 'page_view' THEN 1 ELSE 0 END) AS visited,
MAX(CASE WHEN event = 'product_view' THEN 1 ELSE 0 END) AS viewed_product,
MAX(CASE WHEN event = 'add_to_cart' THEN 1 ELSE 0 END) AS added_to_cart,
MAX(CASE WHEN event = 'checkout_start' THEN 1 ELSE 0 END) AS started_checkout,
MAX(CASE WHEN event = 'purchase' THEN 1 ELSE 0 END) AS purchased
FROM events
WHERE event_date BETWEEN '2025-01-01' AND '2025-01-31'
GROUP BY user_id
)
SELECT
COUNT(*) AS total_visitors,
SUM(viewed_product) AS viewed_product,
SUM(added_to_cart) AS added_to_cart,
SUM(started_checkout) AS started_checkout,
SUM(purchased) AS purchased,
ROUND(100.0 * SUM(viewed_product) / COUNT(*), 2) AS view_rate,
ROUND(100.0 * SUM(added_to_cart) / NULLIF(SUM(viewed_product), 0), 2) AS atc_rate,
ROUND(100.0 * SUM(started_checkout) / NULLIF(SUM(added_to_cart), 0), 2) AS checkout_rate,
ROUND(100.0 * SUM(purchased) / NULLIF(SUM(started_checkout), 0), 2) AS purchase_rate,
ROUND(100.0 * SUM(purchased) / COUNT(*), 2) AS overall_conversion
FROM funnel;
Cohort Comparison Patterns
Feature Adoption Cohorts
python
def feature_adoption_cohort(events_df, feature_event, user_col='user_id'):
"""Compare behavior of users who adopted a feature vs. those who did not."""
adopters = set(events_df[events_df['event'] == feature_event][user_col].unique())
events_df = events_df.copy()
events_df['is_adopter'] = events_df[user_col].isin(adopters)
comparison = events_df.groupby('is_adopter').agg(
n_users=(user_col, 'nunique'),
avg_sessions=('session_id', 'nunique'),
avg_revenue=('revenue', 'mean'),
retention_d30=('retained_d30', 'mean'),
)
return comparison
Time-Based Cohort Trends
python
def cohort_metric_trend(retention_matrix, period_col=1):
"""Track how a specific retention period evolves across cohorts."""
trend = retention_matrix[period_col]
# Rolling average for trend smoothing
trend_smooth = trend.rolling(3, min_periods=1).mean()
return pd.DataFrame({
'cohort': trend.index,
'value': trend.values,
'trend_3m_avg': trend_smooth.values,
})