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 | 1260 | 14 | 1.11 |
| 2 | 1218 | 105 | 8.62 |
| 3 | 1098 | 89 | 8.11 |
| 4 | 971 | 67 | 6.9 |
| 5 | 885 | 26 | 2.94 |
| 6 | 835 | 32 | 3.83 |
| 7 | 770 | 22 | 2.86 |
| 8 | 722 | 24 | 3.32 |
| 9 | 678 | 23 | 3.39 |
| 10 | 636 | 27 | 4.25 |
| 11 | 585 | 20 | 3.42 |
| 12 | 539 | 19 | 3.53 |
does not hold on the current window early hazard 5.94667 is below 1.8x late hazard 3.46167