Churn hazard by tenure
WITH RECURSIVE months(n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM months WHERE n < 12
),
activation AS (
SELECT s.id, e.at AS t0, s.canceled_at
FROM subscriptions s
JOIN subscription_events e ON e.subscription_id = s.id AND e.kind = 'activate'
WHERE s.billing = 'monthly'
),
bounds AS (SELECT datetime(MAX(at)) AS data_end FROM subscription_events),
exposure AS (
SELECT m.n AS tenure_month,
CASE WHEN datetime(a.t0, '+' || m.n || ' months') <= b.data_end
AND (a.canceled_at IS NULL OR datetime(a.canceled_at) >= datetime(a.t0, '+' || (m.n - 1) || ' months'))
THEN 1 ELSE 0 END AS at_risk,
CASE WHEN datetime(a.canceled_at) >= datetime(a.t0, '+' || (m.n - 1) || ' months')
AND datetime(a.canceled_at) < datetime(a.t0, '+' || m.n || ' months')
THEN 1 ELSE 0 END AS canceled
FROM months m CROSS JOIN activation a CROSS JOIN bounds b
)
SELECT tenure_month,
SUM(at_risk) AS subscriptions_at_risk,
SUM(canceled) AS cancels,
ROUND(100.0 * SUM(canceled) / SUM(at_risk), 2) AS hazard_pct
FROM exposure
GROUP BY tenure_month
ORDER BY tenure_month;View data table
| tenure_month | subscriptions_at_risk | cancels | hazard_pct |
|---|---|---|---|
| 1 | 1269 | 14 | 1.1 |
| 2 | 1225 | 107 | 8.73 |
| 3 | 1101 | 91 | 8.27 |
| 4 | 987 | 68 | 6.89 |
| 5 | 890 | 26 | 2.92 |
| 6 | 837 | 32 | 3.82 |
| 7 | 777 | 22 | 2.83 |
| 8 | 728 | 26 | 3.57 |
| 9 | 686 | 23 | 3.35 |
| 10 | 641 | 27 | 4.21 |
| 11 | 593 | 21 | 3.54 |
| 12 | 548 | 20 | 3.65 |
does not hold on the current window early hazard 6.03333 is below 1.8x late hazard 3.525