In [29]:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
In [12]:
#df = pd.read_csv('SwissRe_CatLosses.csv')
df = pd.read_csv(r'SwissRe_CatLosses.csv')
print(df.tail(10))
    Year  Weather         EQ
45  2015    36.83   0.670000
46  2016    50.29  11.680000
47  2017   183.02   2.160000
48  2018   102.15   3.860000
49  2019    65.82   0.225841
50  2020   102.59   0.780000
51  2021   124.73   5.210000
52  2022   134.56   3.720000
53  2023   107.88   7.190000
54  2024   134.63   2.730000

Let's once again recreate the Swiss Re graph to check everything is working as expected.

In [15]:
weather_losses = df.iloc[:, 1]
eq_losses = df.iloc[:, 2]

years = df.iloc[:, 0]
values = df.iloc[:, 1]

plt.figure(figsize=(12, 6))
plt.bar(years, weather_losses, alpha=0.7, label='Weather Related')
plt.bar(years, eq_losses, alpha=0.7, bottom=weather_losses, label='EQ/Tsunami')

plt.xlabel('Year')
plt.ylabel('Insured Losses')
plt.title('Global Natural Catastrophe Insured Losses')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image
In [33]:
total_losses = df.iloc[:, 1] + df.iloc[:, 2]

ln_total = np.log(total_losses)
slope_total = np.polyfit(years, ln_total, 1)[0]
inflation_rate = np.exp(slope_total) - 1

on_leveled = total_losses * (1 + inflation_rate) ** (len(total_losses) - 1 - np.arange(len(total_losses)))
In [35]:
plt.figure(figsize=(12, 6))
plt.bar(years, on_leveled, alpha=0.7)
plt.xlabel('Year')
plt.ylabel('On-Leveled Losses')
plt.title('On-Leveled Global Natural Catastrophe Insured Losses (2024 dollars)')
plt.tight_layout()
plt.show()
No description has been provided for this image
In [37]:
cov_5yr = on_leveled.rolling(window=5).std() / on_leveled.rolling(window=5).mean()
cov_10yr = on_leveled.rolling(window=10).std() / on_leveled.rolling(window=10).mean()

plt.figure(figsize=(12, 6))
plt.plot(years, cov_5yr, marker='o', alpha=0.7, label='5-year CoV')
plt.plot(years, cov_10yr, marker='o', alpha=0.7, label='10-year CoV')
plt.xlabel('Year')
plt.ylabel('Coefficient of Variation')
plt.title('Rolling Coefficient of Variation - On-Leveled Losses')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image
In [39]:
mad_5yr = on_leveled.rolling(window=5).apply(lambda x: np.mean(np.abs(x - x.mean())))
mad_10yr = on_leveled.rolling(window=10).apply(lambda x: np.mean(np.abs(x - x.mean())))

plt.figure(figsize=(12, 6))
plt.plot(years, mad_5yr, marker='o', alpha=0.7, label='5-year MAD')
plt.plot(years, mad_10yr, marker='o', alpha=0.7, label='10-year MAD')
plt.xlabel('Year')
plt.ylabel('Mean Absolute Deviation')
plt.title('Rolling Mean Absolute Deviation - On-Leveled Losses')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image
In [41]:
mean_on_leveled = np.mean(on_leveled)
std_on_leveled = np.std(on_leveled)

mu = np.log(mean_on_leveled**2 / np.sqrt(std_on_leveled**2 + mean_on_leveled**2))
sigma = np.sqrt(np.log(1 + (std_on_leveled**2 / mean_on_leveled**2)))

percentiles = stats.lognorm.cdf(on_leveled, s=sigma, scale=np.exp(mu)) * 100

plt.figure(figsize=(12, 6))
plt.plot(years, percentiles, marker='o', alpha=0.7)
plt.axhline(y=50, color='r', linestyle='--', alpha=0.5, label='Median')
plt.axhline(y=10, color='gray', linestyle='--', alpha=0.3)
plt.axhline(y=90, color='gray', linestyle='--', alpha=0.3)
plt.xlabel('Year')
plt.ylabel('Percentile')
plt.title('Percentile Position Over Time - On-Leveled Losses (Lognormal Fit)')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image