evolutionary-game-dynamics 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evolutionary_game_dynamics/__init__.py +26 -0
- evolutionary_game_dynamics/analysis.py +140 -0
- evolutionary_game_dynamics/plotting.py +622 -0
- evolutionary_game_dynamics/response_functions.py +154 -0
- evolutionary_game_dynamics/simulation.py +847 -0
- evolutionary_game_dynamics/utils.py +303 -0
- evolutionary_game_dynamics-0.1.0.dist-info/METADATA +408 -0
- evolutionary_game_dynamics-0.1.0.dist-info/RECORD +11 -0
- evolutionary_game_dynamics-0.1.0.dist-info/WHEEL +5 -0
- evolutionary_game_dynamics-0.1.0.dist-info/licenses/LICENSE +21 -0
- evolutionary_game_dynamics-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# evolutionary_game_dynamics/__init__.py
|
|
2
|
+
|
|
3
|
+
# Core utilities
|
|
4
|
+
from .utils import generate_all_distributions
|
|
5
|
+
|
|
6
|
+
# Simulation engine
|
|
7
|
+
from .simulation import run_sensitivity
|
|
8
|
+
|
|
9
|
+
# Plotting utilities
|
|
10
|
+
from .plotting import (
|
|
11
|
+
generate_all_outputs,
|
|
12
|
+
plot_recovery_heatmap_grid,
|
|
13
|
+
plot_pre_shock_heatmap_grid,
|
|
14
|
+
heatmap_standard_deviation_grid,
|
|
15
|
+
plot_individual_run,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"generate_all_distributions",
|
|
20
|
+
"run_sensitivity",
|
|
21
|
+
"generate_all_outputs",
|
|
22
|
+
"plot_recovery_heatmap_grid",
|
|
23
|
+
"plot_pre_shock_heatmap_grid",
|
|
24
|
+
"heatmap_standard_deviation_grid",
|
|
25
|
+
"plot_individual_run",
|
|
26
|
+
]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from .utils import *
|
|
2
|
+
|
|
3
|
+
def build_table_norm_epsilon_memory(results_df):
|
|
4
|
+
d = results_df.copy()
|
|
5
|
+
|
|
6
|
+
# First compute simple aggregations using agg()
|
|
7
|
+
base = (
|
|
8
|
+
d.groupby(["pair", "epsilon", "memory_length"], observed=True)
|
|
9
|
+
.agg(
|
|
10
|
+
mean_pre=("pre_freq", "mean"),
|
|
11
|
+
mean_post=("post_freq", "mean"),
|
|
12
|
+
n_runs=("run_id", "count"),
|
|
13
|
+
n_runs1=("run_id", "nunique"),
|
|
14
|
+
sd_pre=("pre_freq", "std"),
|
|
15
|
+
sd_post=("post_freq", "std")
|
|
16
|
+
)
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Now compute recovery-related columns using apply() on full groups
|
|
20
|
+
rec = (
|
|
21
|
+
d.groupby(["pair", "epsilon", "memory_length"], observed=True)
|
|
22
|
+
.apply(lambda g: pd.Series({
|
|
23
|
+
"mean_rec": safe_mean_recovery(g),
|
|
24
|
+
"sd_rec": safe_sd_recovery(g),
|
|
25
|
+
"frac_returned":safe_frac_returned(g)
|
|
26
|
+
}))
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
table = base.join(rec).reset_index()
|
|
30
|
+
|
|
31
|
+
table.rename(columns={
|
|
32
|
+
"pair": "Norm pair",
|
|
33
|
+
"epsilon": "Epsilon",
|
|
34
|
+
"memory_length": "Memory length",
|
|
35
|
+
"mean_pre": "Mean relative frequency-pre shock (%)",
|
|
36
|
+
"mean_post": "Mean relative frequency-post shock (%)",
|
|
37
|
+
"mean_rec": "Mean recovery time (Count of timeperiods)",
|
|
38
|
+
"sd_pre": "Pre-shock relative frequency standard deviation",
|
|
39
|
+
"sd_post": "Post-shock relative frequency standard deviation",
|
|
40
|
+
"sd_rec": "Recovery time standard deviation",
|
|
41
|
+
"frac_returned":"Fraction of runs returning to pre-shock norm (%)",
|
|
42
|
+
"n_runs":"Runs count",
|
|
43
|
+
"n_runs1":"Runs count unique"
|
|
44
|
+
}, inplace=True)
|
|
45
|
+
|
|
46
|
+
return table
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_table_norm_shock_pair(results_df):
|
|
51
|
+
d = results_df.copy()
|
|
52
|
+
|
|
53
|
+
base = (
|
|
54
|
+
d.groupby(["pair", "shock_joint"], observed=True)
|
|
55
|
+
.agg(
|
|
56
|
+
mean_pre=("pre_freq", "mean"),
|
|
57
|
+
mean_post=("post_freq", "mean"),
|
|
58
|
+
n_runs=("run_id", "count"),
|
|
59
|
+
n_runs1=("run_id", "nunique"),
|
|
60
|
+
sd_pre=("pre_freq", "std"),
|
|
61
|
+
sd_post=("post_freq", "std")
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
rec = (
|
|
66
|
+
d.groupby(["pair", "shock_joint"], observed=True)
|
|
67
|
+
.apply(lambda g: pd.Series({
|
|
68
|
+
"mean_rec": safe_mean_recovery(g),
|
|
69
|
+
"sd_rec": safe_sd_recovery(g),
|
|
70
|
+
"frac_ret": safe_frac_returned(g)
|
|
71
|
+
}))
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
table = base.join(rec).reset_index()
|
|
75
|
+
|
|
76
|
+
table.rename(columns={
|
|
77
|
+
"pair": "Norm pair",
|
|
78
|
+
"shock_joint": "Shock Pair",
|
|
79
|
+
"mean_pre": "Mean relative frequency-pre shock (%)",
|
|
80
|
+
"mean_post": "Mean relative frequency-post shock (%)",
|
|
81
|
+
"mean_rec": "Mean recovery time (Count of timeperiods)",
|
|
82
|
+
"frac_ret": "Fraction of runs returning to pre-shock norm (%)",
|
|
83
|
+
"sd_pre": "Pre-shock relative frequency standard deviation",
|
|
84
|
+
"sd_post": "Post-shock relative frequency standard deviation",
|
|
85
|
+
"sd_rec": "Recovery time standard deviation",
|
|
86
|
+
"n_runs":"Runs count",
|
|
87
|
+
"n_runs1":"Runs count unique"
|
|
88
|
+
}, inplace=True)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
return table
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def build_table_norm_initial_state_bin(results_df, bins=np.arange(0,110,10)):
|
|
97
|
+
|
|
98
|
+
records = []
|
|
99
|
+
|
|
100
|
+
for pair_str in results_df["pair"].unique():
|
|
101
|
+
d = results_df[results_df["focal_pair"] == pair_str].copy()
|
|
102
|
+
d["init_share_self"] = d["init_share_focal"] * 100
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
d["init_bin"] = pd.cut(d["init_share_self"], bins=bins, include_lowest=True)
|
|
108
|
+
d["init_bin_label"] = d["init_bin"].apply(
|
|
109
|
+
lambda x: f"({int(x.left)}, {int(x.right)}]" if pd.notna(x) else "NA"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
agg = (
|
|
113
|
+
|
|
114
|
+
d.groupby(["init_bin_label", "pair","memory_length"], observed=True)
|
|
115
|
+
.agg(
|
|
116
|
+
mean_pre=("pre_freq", "mean"),
|
|
117
|
+
sd_pre=("pre_freq", "std"),
|
|
118
|
+
n_runs=("run_id", "nunique")
|
|
119
|
+
)
|
|
120
|
+
.reset_index()
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
agg["Initial state pair"] = pair_str
|
|
124
|
+
records.append(agg)
|
|
125
|
+
|
|
126
|
+
table = pd.concat(records, ignore_index=True)
|
|
127
|
+
|
|
128
|
+
table.rename(columns={
|
|
129
|
+
"init_bin_label": "Initial state pair share - bins (%)",
|
|
130
|
+
"mean_pre": "Mean relative frequency-pre shock (%)",
|
|
131
|
+
"sd_pre": "Pre-shock relative frequency standard deviation",
|
|
132
|
+
"pair":"Outcome pair",
|
|
133
|
+
"n_runs":"Runs count"
|
|
134
|
+
}, inplace=True)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
return table
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|