|
|
import gradio as gr |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
from numpy.random import default_rng |
|
|
import io |
|
|
|
|
|
|
|
|
def generate_custom_model_points( |
|
|
mp_count_val, seed_val, age_min_val, age_max_val, |
|
|
sa_min_val, sa_max_val, policy_terms_selection_val, |
|
|
include_sex_val, policy_count_fixed_val |
|
|
): |
|
|
""" |
|
|
Generates seriatim model points based on user-defined parameters. |
|
|
""" |
|
|
rng = default_rng(int(seed_val)) |
|
|
mp_count_val = int(mp_count_val) |
|
|
age_min_val = int(age_min_val) |
|
|
age_max_val = int(age_max_val) |
|
|
sa_min_val = float(sa_min_val) |
|
|
sa_max_val = float(sa_max_val) |
|
|
|
|
|
|
|
|
policy_id_col = np.arange(1, mp_count_val + 1) |
|
|
|
|
|
|
|
|
age_at_entry = rng.integers(low=age_min_val, high=age_max_val + 1, size=mp_count_val) |
|
|
|
|
|
|
|
|
if include_sex_val: |
|
|
sex_options = ["M", "F"] |
|
|
sex_col = np.fromiter(map(lambda i: sex_options[i], rng.integers(low=0, high=len(sex_options), size=mp_count_val)), np.dtype('<U1')) |
|
|
else: |
|
|
sex_col = np.full(mp_count_val, "U") |
|
|
|
|
|
|
|
|
if not policy_terms_selection_val: |
|
|
policy_terms_selection_val = [10, 15, 20] |
|
|
policy_term_options = np.array(policy_terms_selection_val).astype(int) |
|
|
policy_term_col = rng.choice(policy_term_options, size=mp_count_val) |
|
|
|
|
|
|
|
|
sum_assured_col = np.round((sa_max_val - sa_min_val) * rng.random(size=mp_count_val) + sa_min_val, -3) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
max_duration_val = policy_term_col * 12 - 1 |
|
|
|
|
|
max_duration_val = np.maximum(1, max_duration_val) |
|
|
duration_mth_col = (rng.random(size=mp_count_val) * max_duration_val).astype(int) + 1 |
|
|
|
|
|
duration_mth_col = np.minimum(duration_mth_col, max_duration_val) |
|
|
|
|
|
duration_mth_col = np.maximum(1, duration_mth_col) |
|
|
|
|
|
|
|
|
|
|
|
if policy_count_fixed_val: |
|
|
policy_count_col_val = np.ones(mp_count_val, dtype=int) |
|
|
else: |
|
|
policy_count_col_val = rng.integers(low=1, high=101, size=mp_count_val) |
|
|
|
|
|
|
|
|
data_dict = { |
|
|
"policy_id": policy_id_col, |
|
|
"age_at_entry": age_at_entry, |
|
|
"sex": sex_col, |
|
|
"policy_term": policy_term_col, |
|
|
"policy_count": policy_count_col_val, |
|
|
"sum_assured": sum_assured_col, |
|
|
"duration_mth": duration_mth_col |
|
|
} |
|
|
|
|
|
model_point_df = pd.DataFrame(data_dict) |
|
|
|
|
|
return model_point_df |
|
|
|
|
|
|
|
|
with gr.Blocks() as demo: |
|
|
gr.Markdown("# Actuarial Model Points Generator") |
|
|
gr.Markdown( |
|
|
"Configure the parameters below to generate a custom set of seriatim model points. " |
|
|
"The generated table can be viewed and downloaded as an Excel file." |
|
|
) |
|
|
|
|
|
df_state = gr.State() |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### Generation Parameters") |
|
|
|
|
|
mp_count_input = gr.Slider( |
|
|
minimum=100, maximum=50000, value=10000, step=100, |
|
|
label="Number of Model Points" |
|
|
) |
|
|
seed_input = gr.Number( |
|
|
value=12345, precision=0, label="Random Seed" |
|
|
) |
|
|
|
|
|
gr.Markdown("#### Age Parameters") |
|
|
age_min_input = gr.Slider( |
|
|
minimum=18, maximum=40, value=20, step=1, label="Minimum Age at Entry" |
|
|
) |
|
|
age_max_input = gr.Slider( |
|
|
minimum=41, maximum=80, value=59, step=1, label="Maximum Age at Entry" |
|
|
) |
|
|
|
|
|
gr.Markdown("#### Sum Assured Parameters ($)") |
|
|
sum_assured_min_input = gr.Number( |
|
|
value=10000, label="Minimum Sum Assured" |
|
|
) |
|
|
sum_assured_max_input = gr.Number( |
|
|
value=1000000, label="Maximum Sum Assured" |
|
|
) |
|
|
|
|
|
gr.Markdown("#### Policy Options") |
|
|
policy_terms_input = gr.CheckboxGroup( |
|
|
choices=[5, 10, 15, 20, 25, 30], value=[10, 15, 20], |
|
|
label="Available Policy Terms (Years)" |
|
|
) |
|
|
include_sex_input = gr.Checkbox( |
|
|
value=True, label="Include Sex (M/F)" |
|
|
) |
|
|
policy_count_fixed_input = gr.Checkbox( |
|
|
value=True, label="Fixed Policy Count = 1 (Uncheck for variable count 1-100)" |
|
|
) |
|
|
|
|
|
generate_btn = gr.Button("Generate Model Points", variant="primary") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
model_points_display = gr.Dataframe(label="Generated Model Points") |
|
|
download_excel_btn = gr.DownloadButton( |
|
|
label="Download Excel", |
|
|
value="model_points.xlsx", |
|
|
variant="secondary" |
|
|
) |
|
|
|
|
|
|
|
|
def handle_generate_button_click( |
|
|
mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed |
|
|
): |
|
|
if int(age_m) >= int(age_mx): |
|
|
gr.Warning("Minimum Age must be less than Maximum Age.") |
|
|
return df_state.value, df_state.value |
|
|
if float(sa_m) >= float(sa_mx): |
|
|
gr.Warning("Minimum Sum Assured must be less than Maximum Sum Assured.") |
|
|
return df_state.value, df_state.value |
|
|
if not p_terms: |
|
|
gr.Warning("No Policy Terms selected. Using defaults: [10, 15, 20].") |
|
|
|
|
|
|
|
|
gr.Info("Generating model points... Please wait.") |
|
|
df = generate_custom_model_points( |
|
|
mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed |
|
|
) |
|
|
gr.Info(f"{len(df)} model points generated successfully!") |
|
|
return df, df |
|
|
|
|
|
def handle_download_button_click(current_df_to_download): |
|
|
if current_df_to_download is None or current_df_to_download.empty: |
|
|
gr.Warning("No data available to download. Generate model points first.") |
|
|
empty_excel_output = io.BytesIO() |
|
|
pd.DataFrame().to_excel(empty_excel_output, index=False) |
|
|
empty_excel_output.seek(0) |
|
|
return empty_excel_output |
|
|
|
|
|
excel_output = io.BytesIO() |
|
|
current_df_to_download.to_excel(excel_output, sheet_name='ModelPoints', engine='xlsxwriter', index=False) |
|
|
excel_output.seek(0) |
|
|
return excel_output |
|
|
|
|
|
|
|
|
inputs_list = [ |
|
|
mp_count_input, seed_input, age_min_input, age_max_input, |
|
|
sum_assured_min_input, sum_assured_max_input, policy_terms_input, |
|
|
include_sex_input, policy_count_fixed_input |
|
|
] |
|
|
|
|
|
generate_btn.click( |
|
|
fn=handle_generate_button_click, |
|
|
inputs=inputs_list, |
|
|
outputs=[model_points_display, df_state] |
|
|
) |
|
|
|
|
|
download_excel_btn.click( |
|
|
fn=handle_download_button_click, |
|
|
inputs=[df_state], |
|
|
outputs=[download_excel_btn] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |