Habe die Funktion der Todesuhr noch etwas erweitert. Es lassen sich jetzt die Charakteristiken einer zweiten Person eingeben und es wird berechnet, basierend auf der Annahme, dass die Todesjahre normalverteilt sind mit einer Standardabweichung von 11 Jahren (Mittelwert dieser beiden Publikationen), wie wahrscheinlich es ist, dass Person 2 vor Person 1 stirbt. Dies einmal gemäß den unveränderten Lebenserwartungen aus den Sterbetafeln 2019 des Statistischen Bundesamts wie auch den veränderten Lebenserwartungen gemäß den Inputs zu Bewegung, Übergewicht, Rauchen, etc … Es lässt sich jetzt ebenfalls ein Testjahr (im Beispiel-Output 2030) eingeben und gemäß der Normalverteilung wird angezeigt, wie wahrscheinlich es ist, dass die jeweiligen Personen vor diesem Testjahr sterben.
Beispiel-Output für mich und eine gewisse andere Person:
------ Values for Person 1 ------
Birth Year: 1983
Gender: Male
Expected Remaining Lifespan (Table): 42
Expected Remaining Lifespan (Adjusted): 36
Expected Death Year (Table): 2063
Expected Death Year (Adjusted): 2057
Probability of Dying before 2030 (Table): 0.13 %
Probability of Dying before 2030 (Adjusted): 0.74 %
------ Values for Person 2 ------
Birth Year: 1958
Gender: Female
Expected Remaining Lifespan (Table): 22
Expected Remaining Lifespan (Adjusted): 26
Expected Death Year (Table): 2043
Expected Death Year (Adjusted): 2047
Probability of Dying before 2030 (Table): 11.86 %
Probability of Dying before 2030 (Adjusted): 5.79 %
------ Simulation Based on Normally Distributed Death Years ------
Probability of Person 2 Dying Before Person 1 (Table): 90.06 %
Probability of Person 2 Dying Before Person 1 (Adjusted): 73.00 %
Wie wissenschaftlich sind die Berechnungen?
- Grundlage für alles ist ein fast perfekter Fit der Sterbetafeln 2019, separat für Männer und Frauen, da die Unterschiede der Verläufe recht deutlich sind
def funcm(x):
return (79.02-1.317*x**0.8806)/(1+0.000004896*x**2.776)
def funcf(x):
return (83.82-1.334*x**0.8906)/(1+0.000000820*x**3.136)
- Die Annahme der Normalverteilung der Todesjahre ist in der Praxis gut erfüllt
- Die Standardabweichung müsste sich exakt aus den Sterbetafeln bestimmen lassen. Aber solange ich nicht weiß wie, bleiben die 11 Jahre als Annahme. Dürfte keine großen Verzerrungen bringen
- Die maximale Erhöhung / Reduktion der Lebenserwartung durch einen gegebenen Lifestyle-Faktor ist akademischen Quellen entnommen
- Größtes Problem ist die lineare Addition der Erhöhung / Reduktion der Lebenserwartungen. Rauchen bringt eine Reduktion bis zu 9 Jahre (bei smoking_scale = 1), Übergewicht bis zu 5 Jahre (bei obesity_scale = 1), das heißt aber nicht, dass es bei übergewichtigen Rauchern bis zu 9 + 5 = 14 Jahren sind. So funktioniert das nicht, aber ohne die jeweiligen Korrelationen zu kennen, bleibt es die beste Annahme
- Die Wahl der Skalenwerte ist subjektiv. Wer nie geraucht hat, setzt smoking_scale = 0. Wer seit dem Alter von 10 Jahren drei Packungen pro Tag raucht, setzt smoking_scale = 1. Wer irgendwo dazwischen liegt, setzt irgendwas wohlpassendes dazwischen. Was ist wohlpassend? Das muss jeder selbst entscheiden.
Der Code mit ausführlichen Kommentaranweisungen zum Input und Links zu den Quellen. Funktioniert auch in diesem Online-Compiler.
import scipy
from scipy import stats
import numpy as np
# USER INPUT: SPECIFY CURRENT YEAR AND TEST YEAR
currentyear = 2021
testyear = 2030
# USER INPUT: SPECIFY GENDER AND BIRTH YEAR FOR PERSON 1
# if male set to 1, otherwise to 0
male = 1
birthyear = 1983
# USER INPUT: SPECIFY CHARACTERISTICS FOR PERSON 1
# USER INPUT: ONLY ADJUST SCALE VALUES
# from 0 to 1
# https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3395188/
exercise_scale = 0.3
exercise_add = 7
# from 0 to 1
# https://www.acpjournals.org/doi/abs/10.7326/0003-4819-138-1-200301070-00008
obesity_scale = 0.3
obesity_red = 5
# from 0 to 1
# https://www.bmj.com/content/345/bmj.e7093.full.pdf+html
smoking_scale = 0.7
smoking_red = 9
# from 0 to 1
# https://jamanetwork.com/journals/jama/article-abstract/2513561
wealth_scale = 0.6
wealth_add = 12
# from 0 to 1
# https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2366041/
education_scale = 0.8
education_add = 3.5
# from 0 to 1
# https://pubmed.ncbi.nlm.nih.gov/21593516/
mental_disorder_scale = 0.7
mental_disorder_red = 15
# USER INPUT: SPECIFY IF COMPARISON TO SECOND PERSON SHALL BE MADE
# To Compare to Another Person, set to 1. Otherwise 0
testperson = 1
# USER INPUT: SPECIFY GENDER AND BIRTH YEAR FOR PERSON 2
# if male set to 1, otherwise to 0
tp_male = 0
tp_birthyear = 1958
# USER INPUT: SPECIFY CHARACTERISTICS FOR PERSON 2
# USER INPUT: ONLY ADJUST SCALE VALUES
# Set to 1 to copy all following characteristics from person 1
copyall = 0
# from 0 to 1
# https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3395188/
tp_exercise_scale = 0.3
exercise_add = 7
# from 0 to 1
# https://www.acpjournals.org/doi/abs/10.7326/0003-4819-138-1-200301070-00008
tp_obesity_scale = 0.0
obesity_red = 5
# from 0 to 1
# https://www.bmj.com/content/345/bmj.e7093.full.pdf+html
tp_smoking_scale = 0.1
smoking_red = 9
# from 0 to 1
# https://jamanetwork.com/journals/jama/article-abstract/2513561
tp_wealth_scale = 0.7
wealth_add = 12
# from 0 to 1
# https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2366041/
tp_education_scale = 0.2
education_add = 3.5
# from 0 to 1
# https://pubmed.ncbi.nlm.nih.gov/21593516/
tp_mental_disorder_scale = 0.4
mental_disorder_red = 15
# ----------------------
# END OF ALL USER INPUTS
# ----------------------
# Functions are fits from Sterbetafeln 2019 for males and females
def funcm(x):
return (79.02-1.317*x**0.8806)/(1+0.000004896*x**2.776)
def funcf(x):
return (83.82-1.334*x**0.8906)/(1+0.000000820*x**3.136)
if copyall > 0.5:
tp_exercise_scale = exercise_scale
tp_obesity_scale = obesity_scale
tp_smoking_scale = smoking_scale
tp_wealth_scale = wealth_scale
tp_education_scale = education_scale
tp_mental_disorder_scale = mental_disorder_scale
print('------ Values for Person 1 ------')
age = currentyear-birthyear
if male > 0.5:
years_left = round(funcm(age),0)
else:
years_left = round(funcf(age),0)
deathyear_table = currentyear+years_left
deathyear = deathyear_table + exercise_scale*exercise_add - obesity_scale*obesity_red - smoking_scale*smoking_red + wealth_scale*wealth_add + education_scale*education_add - mental_disorder_scale*mental_disorder_red
years_left_adj = deathyear-currentyear
print()
print('Birth Year:', birthyear)
if male > 0.5:
print('Gender: Male')
else:
print('Gender: Female')
print()
print('Expected Remaining Lifespan (Table):', "%.0f" % years_left)
print('Expected Remaining Lifespan (Adjusted):', "%.0f" % years_left_adj)
print()
print('Expected Death Year (Table):', "%.0f" % deathyear_table)
print('Expected Death Year (Adjusted):', "%.0f" % deathyear)
z1 = (testyear-deathyear_table)/11
p1 = 100*stats.norm.cdf(z1)
z2 = (testyear-deathyear)/11
p2 = 100*stats.norm.cdf(z2)
print()
print('Probability of Dying before', testyear, '(Table):', "%.2f" % p1, '%')
print('Probability of Dying before', testyear, '(Adjusted):', "%.2f" % p2, '%')
if testperson > 0.5:
print()
print()
print('------ Values for Person 2 ------')
tp_age = currentyear-tp_birthyear
if tp_male > 0.5:
tp_years_left = round(funcm(tp_age),0)
else:
tp_years_left = round(funcf(tp_age),0)
tp_deathyear_table = currentyear+tp_years_left
tp_deathyear = tp_deathyear_table + tp_exercise_scale*exercise_add - tp_obesity_scale*obesity_red - tp_smoking_scale*smoking_red + tp_wealth_scale*wealth_add + tp_education_scale*education_add - tp_mental_disorder_scale*mental_disorder_red
tp_years_left_adj = tp_deathyear-currentyear
print()
print('Birth Year:', tp_birthyear)
if tp_male > 0.5:
print('Gender: Male')
else:
print('Gender: Female')
print()
print('Expected Remaining Lifespan (Table):', "%.0f" % tp_years_left)
print('Expected Remaining Lifespan (Adjusted):', "%.0f" % tp_years_left_adj)
print()
print('Expected Death Year (Table):', "%.0f" % tp_deathyear_table)
print('Expected Death Year (Adjusted):', "%.0f" % tp_deathyear)
tp_z1 = (testyear-tp_deathyear_table)/11
tp_p1 = 100*stats.norm.cdf(tp_z1)
tp_z2 = (testyear-tp_deathyear)/11
tp_p2 = 100*stats.norm.cdf(tp_z2)
print()
print('Probability of Dying before', testyear, '(Table):', "%.2f" % tp_p1, '%')
print('Probability of Dying before', testyear, '(Adjusted):', "%.2f" % tp_p2, '%')
print()
print()
print('------ Simulation Based on Normally Distributed Death Years ------')
year1_table = np.random.normal(deathyear_table,11,50000)
year2_table = np.random.normal(tp_deathyear_table,11,50000)
count = 0
i = 0
while i < len(year1_table):
if year2_table[i] < year1_table[i]:
count = count+1
i += 1
prob = 100*count/i
print()
print('Probability of Person 2 Dying Before Person 1 (Table):', "%.2f" % prob, '%')
year1 = np.random.normal(deathyear,11,50000)
year2 = np.random.normal(tp_deathyear,11,50000)
count = 0
i = 0
while i < len(year1):
if year2[i] < year1[i]:
count = count+1
i += 1
prob = 100*count/i
print('Probability of Person 2 Dying Before Person 1 (Adjusted):', "%.2f" % prob, '%')