analysis of initial risk attitude distributions & population outcomes¶

Analyzing data generated from a batch run with 1000 iterations each per risk distribution

  • maximum run length of 3000 steps
  • convergence threshold at <=7% agents changing for two adjustment rounds in a row
In [13]:
import polars as pl


df = pl.read_csv("../../data/hawkdovemulti/dist_c7_3k_2024-02-27T162947_580557_model.csv")
In [14]:
total_runs = len(df)

print(f"Analyzing {total_runs} runs")
Analyzing 5000 runs

what % converged?¶

In [15]:
converged_df = df.filter(df["status"] == "converged")
len(converged_df)
Out[15]:
4594

almost all of them!

how long does it take to converge?¶

In [16]:
converged_df["Step"].describe()
Out[16]:
shape: (9, 2)
statisticvalue
strf64
"count"4594.0
"null_count"0.0
"mean"147.572921
"std"135.641494
"min"50.0
"25%"70.0
"50%"110.0
"75%"170.0
"max"2410.0
In [17]:
converged_df["Step"].plot.hist()
Out[17]:

compare different initial distributions¶

In [18]:
df["risk_distribution"].unique()
Out[18]:
shape: (5,)
risk_distribution
str
"skewed right"
"uniform"
"bimodal"
"skewed left"
"normal"

How many converged runs in each subset?

In [19]:
converged_df.group_by("risk_distribution").count()
/var/folders/mb/6qm4h4yx3yqdy2bv2sjyp4z00000gp/T/ipykernel_43782/1942186623.py:1: DeprecationWarning: `GroupBy.count` was renamed; use `GroupBy.len` instead
  converged_df.group_by("risk_distribution").count()
Out[19]:
shape: (5, 2)
risk_distributioncount
stru32
"uniform"938
"skewed right"987
"bimodal"710
"normal"996
"skewed left"963
In [20]:
# filter converged run data into subsets by risk distribution

subset = {}

for distribution in converged_df["risk_distribution"].unique():
    subset[distribution] = converged_df.filter(pl.col("risk_distribution") == distribution)

How does initial distribution affect convergence?¶

In [21]:
status_by_dist = df.group_by("risk_distribution", "status").count()
status_by_dist
/var/folders/mb/6qm4h4yx3yqdy2bv2sjyp4z00000gp/T/ipykernel_43782/3878793973.py:1: DeprecationWarning: `GroupBy.count` was renamed; use `GroupBy.len` instead
  status_by_dist = df.group_by("risk_distribution", "status").count()
Out[21]:
shape: (10, 3)
risk_distributionstatuscount
strstru32
"skewed left""running"37
"skewed right""converged"987
"bimodal""converged"710
"uniform""running"62
"skewed left""converged"963
"bimodal""running"290
"uniform""converged"938
"skewed right""running"13
"normal""running"4
"normal""converged"996
In [22]:
import altair as alt

alt.Chart(status_by_dist).mark_bar().encode(
    x='risk_distribution:N',
    y='count',
    color='status:N'
).properties(title="Simulation status (converged/running) by risk distribution", width=250, height=400)
Out[22]:
In [23]:
alt.Chart(converged_df).mark_boxplot(size=20).encode(
    x='risk_distribution:N',
    y='Step',
).properties(
    title=alt.TitleParams(
        "Simulation run length by risk distribution",  
        subtitle="(converged runs only)"), 
    width=350, height=450)
Out[23]:

population categories by risk distribution¶

In [24]:
import altair as alt
from simulatingrisk.hawkdovemulti import analysis_utils


uniform_chart = analysis_utils.graph_population_risk_category(
    analysis_utils.groupby_population_risk_category(subset["uniform"])
).properties(title="risk distribution: uniform/random")

normal_chart  = analysis_utils.graph_population_risk_category(
    analysis_utils.groupby_population_risk_category(subset["normal"])
).properties(title="risk distribution: normal")

bimodal_chart  = analysis_utils.graph_population_risk_category(
    analysis_utils.groupby_population_risk_category(subset["bimodal"])
).properties(title="risk distribution: bimodal")

skewedleft_chart  = analysis_utils.graph_population_risk_category(
    analysis_utils.groupby_population_risk_category(subset["skewed left"])
).properties(title="risk distribution: skewed left")

skewedright_chart  = analysis_utils.graph_population_risk_category(
    analysis_utils.groupby_population_risk_category(subset["skewed right"])
).properties(title="risk distribution: skewed right")

(uniform_chart | normal_chart | bimodal_chart | skewedleft_chart | skewedright_chart) \
.properties(title=alt.TitleParams("Population category by run over initial risk distributions", anchor="middle")).resolve_scale(y='shared')
/Users/rkoeser/workarea/env/simrisk/lib/python3.12/site-packages/simulatingrisk/hawkdovemulti/analysis_utils.py:28: MapWithoutReturnDtypeWarning: Calling `map_elements` without specifying `return_dtype` can lead to unpredictable results. Specify `return_dtype` to silence this warning.
  values=poprisk_grouped["risk_category"].map_elements(RiskState.category),
Out[24]: