is a statistical approach used to answer the question: “How long will something last?” That “something” could range from a patient’s lifespan to the durability of a machine component or the duration of a user’s subscription.
One of the most widely used tools in this area is the Kaplan-Meier estimator.
Born in the world of biology, Kaplan-Meier made its debut tracking life and death. But like any true celebrity algorithm, it didn’t stay in its lane. These days, it’s showing up in business dashboards, marketing teams, and churn analyses everywhere.
But here’s the catch: business isn’t biology. It’s messy, unpredictable, and full of plot twists. This is why there are a couple of issues that make our lives more difficult when we try to use survival analysis in the business world.
First of all, we are typically not just interested in whether a customer has “survived” (whatever survival could mean in this context), but rather in how much of that individual’s economic value has survived.
Secondly, contrary to biology, it’s very possible for customers to “die” and “resuscitate” multiple times (think of when you unsubscribe/resubscribe to an online service).
In this article, we will see how to extend the classical Kaplan-Meier approach so that it better suits our needs: modeling a continuous (economic) value instead of a binary one (life/death) and allowing “resurrections”.
A refresher on the Kaplan-Meier estimator
Let’s pause and rewind for a second. Before we start customizing Kaplan-Meier to fit our business needs, we need a quick refresher on how the classic version works.
Suppose you had 3 subjects (let’s say lab mice) and you gave them a medicine you need to test. The medicine was given at different moments in time: subject a received it in January, subject b in April, and subject c in May.
Then, you measure how long they survive. Subject a died after 6 months, subject c after 4 months, and subject b is still alive at the time of the analysis (November).
Graphically, we can represent the 3 subjects as follows:
Now, even if we wanted to measure a simple metric, like average survival, we would face a problem. In fact, we don’t know how long subject b will survive, as it is still alive today.
This is a classical problem in statistics, and it’s called “right censoring“.
Right censoring is stats-speak for “we don’t know what happened after a certain point” and it’s a big deal in survival analysis. So big that it led to the development of one of the most iconic estimators in statistical history: the Kaplan-Meier estimator, named after the duo who introduced it back in the 1950s.
So, how does Kaplan-Meier handle our problem?
First, we align the clocks. Even if our mice were treated at different times, what matters is time since treatment. So we reset the x-axis to zero for everyone — day zero is the day they got the drug.

Now that we’re all on the same timeline, we want to build something useful: an aggregate survival curve. This curve tells us the probability that a typical mouse in our group will survive at least x months post-treatment.
Let’s follow the logic together.
- Up to time 3? Everyone’s still alive. So survival = 100%. Easy.
- At time 4, mouse c dies. This means that out of the 3 mice, only 2 of them survived after time 4. That gives us a survival rate of 67% at time 4.
- Then at time 6, mouse a checks out. Of the 2 mice that had made it to time 6, only 1 survived, so the survival rate from time 5 to 6 is 50%. Multiply that by the previous 67%, and we get 33% survival up to time 6.
- After time 7 we don’t have other subjects that are observed alive, so the curve has to stop here.
Let’s plot these results:

Since code is often easier to understand than words, let’s translate this to Python. We have the following variables:
kaplan_meier
, an array containing the Kaplan-Meier estimates for each point in time, e.g. the probability of survival up to time t.obs_t
, an array that tells us whether an individual is observed (e.g., not right-censored) at time t.surv_t
, boolean array that tells us whether each individual is alive at time t.surv_t_minus_1
, boolean array that tells us whether each individual is alive at time t-1.
All we have to do is to take all the individuals observed at t, compute their survival rate from t-1 to t (survival_rate_t
), and multiply it by the survival rate up to time t-1 (km[t-1]
) to obtain the survival rate up to time t (km[t]
). In other words,
survival_rate_t = surv_t[obs_t].sum() / surv_t_minus_1[obs_t].sum()
kaplan_meier[t] = kaplan_meier[t-1] * survival_rate_t
where, of course, the starting point is kaplan_meier[0] = 1
.
If you don’t want to code this from scratch, the Kaplan-Meier algorithm is available in the Python library lifelines
, and it can be used as follows:
from lifelines import KaplanMeierFitter
KaplanMeierFitter().fit(
durations=[6,7,4],
event_observed=[1,0,1],
).survival_function_["KM_estimate"]
If you use this code, you will obtain the same result we have obtained manually with the previous snippet.
So far, we’ve been hanging out in the land of mice, medicine, and mortality. Not exactly your average quarterly KPI review, right? So, how is this useful in business?
Moving to a business setting
So far, we’ve treated “death” as if it’s obvious. In Kaplan-Meier land, someone either lives or dies, and we can easily log the time of death. But now let’s stir in some real-world business messiness.
What even is “death” in a business context?
It turns out it’s not easy to answer this question, at least for a couple of reasons:
- “Death” is not easy to define. Let’s say you’re working at an e-commerce company. You want to know when a user has “died”. Should you count them as dead when they delete their account? That’s easy to track… but too rare to be useful. What if they just start shopping less? But how much less is dead? A week of silence? A month? Two? You see the problem. The definition of “death” is arbitrary, and depending on where you draw the line, your analysis might tell wildly different stories.
- “Death” is not permanent. Kaplan-Meier has been conceived for biological applications in which once an individual is dead there is no return. But in business applications, resurrection is not only possible but pretty frequent. Imagine a streaming service for which people pay a monthly subscription. It’s easy to define “death” in this case: it’s when users cancel their subscriptions. However, it’s pretty frequent that, some time after cancelling, they re-subscribe.
So how does all this play out in data?
Let’s walk through a toy example. Say we have a user on our e-commerce platform. Over the past 10 months, here’s how much they’ve spent:

To squeeze this into the Kaplan-Meier framework, we need to translate that spending behavior into a life-or-death decision.
So we make a rule: if a user stops spending for 2 consecutive months, we declare them “inactive”.
Graphically, this rule looks like the following:

Since the user spent $0 for two months in a row (month 4 and 5) we will consider this user inactive starting from month 4 on. And we will do that despite the user started spending again in month 7. This is because, in Kaplan-Meier, resurrections are assumed to be impossible.
Now let’s add two more users to our example. Since we have decided a rule to turn their value curve into a survival curve, we can also compute the Kaplan-Meier survival curve:

By now, you’ve probably noticed how much nuance (and data) we’ve thrown away just to make this work. User a came back from the dead — but we ignored that. User c‘s spending dropped significantly — but Kaplan-Meier doesn’t care, because all it sees is 1s and 0s. We forced a continuous value (spending) into a binary box (alive/dead), and along the way, we lost a whole lot of information.
So the question is: can we extend Kaplan-Meier in a way that:
- keeps the original, continuous data intact,
- avoids arbitrary binary cutoffs,
- allows for resurrections?
Yes, we can. In the next section, I’ll show you how.
Introducing “Value Kaplan-Meier”
Let’s start with the simple Kaplan-Meier formula we have seen before.
# kaplan_meier: array containing the Kaplan-Meier estimates,
# e.g. the probability of survival up to time t
# obs_t: array, whether a subject has been observed at time t
# surv_t: array, whether a subject was alive at time t
# surv_t_minus_1: array, whether a subject was alive at time t−1
survival_rate_t = surv_t[obs_t].sum() / surv_t_minus_1[obs_t].sum()
kaplan_meier[t] = kaplan_meier[t-1] * survival_rate_t
The first change we need to make is to replace surv_t
and surv_t_minus_1
, which are boolean arrays that tell us whether a subject is alive (1) or dead (0) with arrays that tell us the (economic) value of each subject at a given time. For this purpose, we can use two arrays named val_t
and val_t_minus_1
.
But this is not enough, because since we are dealing with continuous value, every user is on a different scale and so, assuming that we want to weigh them equally, we need to rescale them based on some individual value. But what value should we use? The most reasonable choice is to use their initial value at time 0, before they were influenced by whatever treatment we are applying to them.
So we also need to use another vector, named val_t_0
that represents the value of the individual at time 0.
# value_kaplan_meier: array containing the Value Kaplan-Meier estimates
# obs_t: array, whether a subject has been observed at time t
# val_t_0: array, user value at time 0
# val_t: array, user value at time t
# val_t_minus_1: array, user value at time t−1
value_rate_t = (
(val_t[obs_t] / val_t_0[obs_t]).sum()
/ (val_t_minus_1[obs_t] / val_t_0[obs_t]).sum()
)
value_kaplan_meier[t] = value_kaplan_meier[t-1] * value_rate_t
What we’ve built is a direct generalization of Kaplan-Meier. In fact, if you set val_t = surv_t
, val_t_minus_1 = surv_t_minus_1
, and val_t_0
as an array of 1s, this formula collapses neatly back to our original survival estimator. So yes—it’s legit.
And here is the curve that we would obtain when applied to these 3 users.

Let’s call this new version the Value Kaplan-Meier estimator. In fact, it answers the question:
How much percent of value is still surviving, on average, after x time?
We’ve got the theory. But does it work in the wild?
Using Value Kaplan-Meier in practice
If you take the Value Kaplan-Meier estimator for a spin on real-world data and compare it to the good old Kaplan-Meier curve, you’ll likely notice something comforting — they often have the same shape. That’s a good sign. It means we haven’t broken anything fundamental while upgrading from binary to continuous.
But here’s where things get interesting: Value Kaplan-Meier usually sits a bit above its traditional cousin. Why? Because in this new world, users are allowed to “resurrect”. Kaplan-Meier, being the more rigid of the two, would’ve written them off the moment they went quiet.
So how do we put this to use?
Imagine you’re running an experiment. At time zero, you start a new treatment on a group of users. Whatever it is, you can track how much value “survives” in both the treatment and control groups over time.
And this is what your output will probably look like:

Conclusion
Kaplan-Meier is a widely used and intuitive method for estimating survival functions, especially when the outcome is a binary event like death or failure. However, many real-world business scenarios involve more complexity — resurrections are possible, and outcomes are better represented by continuous values rather than a binary state.
In such cases, Value Kaplan-Meier offers a natural extension. By incorporating the economic value of individuals over time, it enables a more nuanced understanding of value retention and decay. This method preserves the simplicity and interpretability of the original Kaplan-Meier estimator while adapting it to better reflect the dynamics of customer behavior.
Value Kaplan-Meier tends to provide a higher estimate of retained value compared to Kaplan-Meier, due to its ability to account for recoveries. This makes it particularly useful in evaluating experiments or tracking customer value over time.