A loan is right-censored when observation ends before default occurs: its later default time is unknown, not proof that it will never default. Treating a performing borrower with a short history as a confirmed non-default can hide this uncertainty. section 4.2.2
A short loan history
A borrower is still performing after two months, but may default in month six. The two-month record is incomplete; it does not establish that the borrower will remain non-defaulting. section 4.2.2
Listing 4.2 Survival analysis example [4]
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from lifelines import KaplanMeierFitter
np.random.seed(42)
# Generate 50 synthetic loans with ~10% default by 12 months
N = 50
time_to_default = []
event_observed = []
for _ in range(N):
r = np.random.rand() #1
if r < 0.1: #2
possible_months = [3,4,5,6,7,8,9,10]
d_month = np.random.choice(possible_months)
time_to_default.append(d_month)
event_observed.append(1) #3
else:
time_to_default.append(12)
event_observed.append(0) #4
df_surv = pd.DataFrame({
"loan_id": range(1, N+1),
"time_to_default": time_to_default,
"event_observed": event_observed
})
# Fit the Kaplan–Meier model
kmf = KaplanMeierFitter() #5
kmf.fit(
durations=df_surv["time_to_default"],
event_observed=df_surv["event_observed"],
label="Loan Survival"
)
# Plot the KM survival function
kmf.plot_survival_function() #6
plt.title("Kaplan–Meier Survival Curve (~10% Default)")
plt.xlabel("Months on Book")
plt.ylabel("Survival Probability")
plt.grid(True)
plt.show()
The synthetic survival example distinguishes observed defaults from loans with no default observed by month 12. section 4.2.2
