How long does a subscription account really last?
Your billing export can answer that question two ways, and they differ by nearly half. This is the reproducible analysis behind our survival lesson: 320 B2B accounts, a third of them still running, and every figure derived when the document is knitted rather than typed in.
Watch the lesson first, if you like
Seven minutes, and it walks this exact dataset. Everything below is the source it was built from.
The problem, in one line of your own data
You export your accounts. Some have a churn date. Some do not, because they are still paying you right now. If you average the ones that ended, you have answered a question nobody asked: how long did the accounts that already left last? The accounts still running are not missing data. An account alive at day 400 is telling you something exact: this one lasted at least 400 days. Drop it and you throw away the good news, every time, in the same direction.
What the two answers actually are
- Accounts320
- Churned210
- Still running110
- Naive median301 d
- True median540 d
- Understated by44.26%
Count every account for exactly as long as you actually watched it, and half the book of business outlasts 540 days, with a 95% confidence interval of 451 to 637. The figure from averaging only the churned accounts was 301 days. The error is not noise, and it does not point both ways: dropping the survivors can only ever shorten the answer.
Survival at the anchors you would put in a plan
| Anchor | Still active | 95% CI |
|---|---|---|
| 1 year | 0.6137 | 0.5618 – 0.6703 |
| 2 years | 0.3671 | 0.3125 – 0.4313 |
| 3 years | 0.2305 | 0.1788 – 0.2973 |
If you need an average rather than a median, use the restricted mean and say the window out loud: over a 730-day horizon it is 470.03 days. A mean lifetime is not identifiable without a stated horizon, which is exactly what that number is for.
The finding the single average was hiding
Split the same accounts by whether onboarding was completed, and two very different businesses appear inside one book.
| Group | Accounts | Median lifetime | 95% CI |
|---|---|---|---|
| Onboarding completed | 217 | 703 days | 599 – 800 |
| Not completed | 103 | 257 days | 190 – 374 |
Roughly 2.7× the median lifetime. The log-rank test puts the chance of a split this clean arising from luck at 1.83e-12, and the hazard ratio says an account that skipped onboarding carries about 2.66× the risk of leaving at any given moment, with an interval of 2.00 to 3.52 that sits well clear of 1.
Download it and re-run it
Every figure on this page is derived when the document is knitted, not typed in. Re-run the source and you should get the same numbers, or we have a problem worth hearing about.
- survival.html · The knitted document, with the curves945 KB
- survival.Rmd · R Markdown source, seeded and self-generating9 KB
- survival_accounts.csv · The 320 accounts22 KB
- survival_check.R · The check against R's own survival functions2 KB
- survival_check.py · The independent Python rewrite4 KB
Why there are three implementations, not one
Every number here was computed three ways: by the document itself, by R's standard survival functions called directly, and by a Python rewrite of Kaplan-Meier, the log-rank test and Cox regression built from scratch rather than imported from a library. All three agree to every digit shown. A second library agreeing with the first mostly proves they share an author's assumptions; an independent reimplementation agreeing is a stronger claim, and it is the one we wanted to be able to make. Twenty-one event days carry more than one churn, so all three use Efron's handling of ties rather than Breslow.
The honest limit
The 44.26% gap compares medians, 301 days against 540. It is not a statement about means, and we have deliberately not computed a mean lifetime for the whole book, because a mean is not identifiable without a stated horizon. That is what the restricted mean above is for, and why it names its window. The dataset is generated, seeded and reproducible rather than a customer's data, so it demonstrates the method honestly without publishing anyone's accounts.
Run it on your own accounts
You need one row per account: how long you watched it, whether it ended, and any group you want to compare. The column that matters most is the one people delete: keep the empty churn date, because that emptiness is the information.