model_wrapper.py
Contents
model_wrapper.py
#
Initialize#
# Run dependencies
%run ./model_python_lib_utils.ipynb
%run ./model_python_lib_event_counts.ipynb
%run ./model_python_lib_decision_functions.ipynb
%run ./python_lib_visualization.ipynb
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
File /var/folders/vc/0d4071bd7rbd6q1btkk05jcw0000gn/T/ipykernel_3371/3777295251.py:9, in <cell line: 9>()
7 import numpy as np
8 import pandas as pd
----> 9 from scipy import stats
10 import seaborn as sns
12 from utils import N_ROUNDS
ModuleNotFoundError: No module named 'scipy'
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Input In [1], in <cell line: 5>()
3 get_ipython().run_line_magic('run', './model_python_lib_event_counts.ipynb')
4 get_ipython().run_line_magic('run', './model_python_lib_decision_functions.ipynb')
----> 5 get_ipython().run_line_magic('run', './python_lib_visualization.ipynb')
File /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/IPython/core/interactiveshell.py:2305, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
2303 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2304 with self.builtin_trap:
-> 2305 result = fn(*args, **kwargs)
2306 return result
File /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/IPython/core/magics/execution.py:717, in ExecutionMagics.run(self, parameter_s, runner, file_finder)
715 with preserve_keys(self.shell.user_ns, '__file__'):
716 self.shell.user_ns['__file__'] = filename
--> 717 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
718 return
720 # Control the response to exit() calls made by the script being run
File /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/IPython/core/interactiveshell.py:2811, in InteractiveShell.safe_execfile_ipy(self, fname, shell_futures, raise_exceptions)
2809 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2810 if raise_exceptions:
-> 2811 result.raise_error()
2812 elif not result.success:
2813 break
File /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/IPython/core/interactiveshell.py:251, in ExecutionResult.raise_error(self)
249 raise self.error_before_exec
250 if self.error_in_exec is not None:
--> 251 raise self.error_in_exec
[... skipping hidden 1 frame]
File /var/folders/vc/0d4071bd7rbd6q1btkk05jcw0000gn/T/ipykernel_3371/3777295251.py:9, in <cell line: 9>()
7 import numpy as np
8 import pandas as pd
----> 9 from scipy import stats
10 import seaborn as sns
12 from utils import N_ROUNDS
ModuleNotFoundError: No module named 'scipy'
Read data#
df = read_rps_data(os.path.join("data", DEFAULT_FILE))
df.head()
game_id | version | is_sona_autocredit | sona_experiment_id | sona_credit_token | sona_survey_code | round_index | player_id | is_bot | bot_strategy | bot_move_probabilities | round_begin_ts | player_move | player_rt | player_outcome | player_outcome_viewtime | player_points | player_total | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 1 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | {'win': {'0': {'rock': {'rock': 0.049999999999... | 1583904283047 | rock | 2091 | tie | 3951 | 0 | 0 |
1 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 1 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | {'win': {'0': {'rock': {'rock': 0.049999999999... | 1583904283047 | rock | 0 | tie | 0 | 0 | 0 |
2 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 2 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | {'win': {'0': {'rock': {'rock': 0.049999999999... | 1583904289171 | paper | 2886 | loss | 1741 | -1 | 0 |
3 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 2 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | {'win': {'0': {'rock': {'rock': 0.049999999999... | 1583904289171 | scissors | 0 | win | 0 | 3 | 0 |
4 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 3 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | {'win': {'0': {'rock': {'rock': 0.049999999999... | 1583904293847 | scissors | 1676 | tie | 2040 | 0 | -1 |
Add bot predictors#
Initialize columns
# TODO may want to move these to `utils.py` as globals so that functions in `event_counts.py` can reference them there
# Add columns corresponding to opponent move counts
supplementary_cols = [
'opponent_move',
'previous_move', 'opponent_previous_move',
'previous_outcome', 'opponent_previous_outcome',
'previous_transition', 'opponent_previous_transition',
'current_transition',
'opponent_prev2_transition'
]
event_counts = [
# transition counts
'up_transition_count', 'down_transition_count', 'stay_transition_count',
'cournot_up_transition_count', 'cournot_down_transition_count', 'cournot_stay_transition_count',
# outcome-dependent transition counts
'win_up_count', 'win_down_count', 'win_stay_count',
'loss_up_count', 'loss_down_count', 'loss_stay_count',
'tie_up_count', 'tie_down_count', 'tie_stay_count',
# dual transition outcome counts
'up_win_up_count', 'up_win_down_count', 'up_win_stay_count',
'up_loss_up_count', 'up_loss_down_count', 'up_loss_stay_count',
'up_tie_up_count', 'up_tie_down_count', 'up_tie_stay_count',
'down_win_up_count', 'down_win_down_count', 'down_win_stay_count',
'down_loss_up_count', 'down_loss_down_count', 'down_loss_stay_count',
'down_tie_up_count', 'down_tie_down_count', 'down_tie_stay_count',
'stay_win_up_count', 'stay_win_down_count', 'stay_win_stay_count',
'stay_loss_up_count', 'stay_loss_down_count', 'stay_loss_stay_count',
'stay_tie_up_count', 'stay_tie_down_count', 'stay_tie_stay_count'
]
opponent_counts = [
# base move counts
'opponent_rock_count', 'opponent_paper_count', 'opponent_scissors_count',
# transition counts
'opponent_up_transition_count', 'opponent_down_transition_count', 'opponent_stay_transition_count',
'opponent_cournot_up_transition_count', 'opponent_cournot_down_transition_count', 'opponent_cournot_stay_transition_count',
# outcome-dependent transition counts
'opponent_win_up_count', 'opponent_win_down_count', 'opponent_win_stay_count',
'opponent_loss_up_count', 'opponent_loss_down_count', 'opponent_loss_stay_count',
'opponent_tie_up_count', 'opponent_tie_down_count', 'opponent_tie_stay_count',
# dual transition outcome counts
'opponent_up_win_up_count', 'opponent_up_win_down_count', 'opponent_up_win_stay_count',
'opponent_up_loss_up_count', 'opponent_up_loss_down_count', 'opponent_up_loss_stay_count',
'opponent_up_tie_up_count', 'opponent_up_tie_down_count', 'opponent_up_tie_stay_count',
'opponent_down_win_up_count', 'opponent_down_win_down_count', 'opponent_down_win_stay_count',
'opponent_down_loss_up_count', 'opponent_down_loss_down_count', 'opponent_down_loss_stay_count',
'opponent_down_tie_up_count', 'opponent_down_tie_down_count', 'opponent_down_tie_stay_count',
'opponent_stay_win_up_count', 'opponent_stay_win_down_count', 'opponent_stay_win_stay_count',
'opponent_stay_loss_up_count', 'opponent_stay_loss_down_count', 'opponent_stay_loss_stay_count',
'opponent_stay_tie_up_count', 'opponent_stay_tie_down_count', 'opponent_stay_tie_stay_count'
]
df = add_col(df, supplementary_cols, value = '')
df = add_col(df, event_counts, value = 1)
df = add_col(df, opponent_counts, value = 1)
# df.head()
Populate new columns with counts
game_split = separate_df(df)
game_split = get_event_counts(df, game_split)
df = pd.concat(game_split).reset_index(drop = True)
df.head(8)
game_id | version | is_sona_autocredit | sona_experiment_id | sona_credit_token | sona_survey_code | round_index | player_id | is_bot | bot_strategy | ... | opponent_down_tie_stay_count | opponent_stay_win_up_count | opponent_stay_win_down_count | opponent_stay_win_stay_count | opponent_stay_loss_up_count | opponent_stay_loss_down_count | opponent_stay_loss_stay_count | opponent_stay_tie_up_count | opponent_stay_tie_down_count | opponent_stay_tie_stay_count | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 1 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 1 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 2 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
3 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 2 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
4 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 3 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
5 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 3 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
6 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 4 | c82739a2-9e24-4c1b-840f-9eb00d10cd9b | 0 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
7 | 30aea025-4c7b-41c0-bd03-363cc73bf583 | 2 | 1 | 1768 | 19421bc286424246b6b1e873e7a55a8e | 32028 | 4 | f1c3a029-e381-4f79-afbe-677ef9416f04 | 1 | outcome_transition_dual_dependency | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
8 rows × 114 columns
Compute probabilities#
# TODO make these programmatic (esp. final set)
# Move baserate probabilities
df = add_prob(
df,
'opponent_rock_count', 'opponent_paper_count', 'opponent_scissors_count',
'p_opponent_rock', 'p_opponent_paper', 'p_opponent_scissors'
)
# Transition probabilities
df = add_prob(
df,
'opponent_up_transition_count', 'opponent_down_transition_count', 'opponent_stay_transition_count',
'p_opponent_transition_up', 'p_opponent_transition_down', 'p_opponent_transition_stay'
)
df = add_prob(
df,
'opponent_cournot_up_transition_count', 'opponent_cournot_down_transition_count', 'opponent_cournot_stay_transition_count',
'p_opponent_cournot_transition_up', 'p_opponent_cournot_transition_down', 'p_opponent_cournot_transition_stay'
)
# Outcome-transition probabilities
df = add_prob(
df,
'opponent_win_up_count', 'opponent_win_down_count', 'opponent_win_stay_count',
'p_opponent_win_up', 'p_opponent_win_down', 'p_opponent_win_stay'
)
df = add_prob(
df,
'opponent_loss_up_count', 'opponent_loss_down_count', 'opponent_loss_stay_count',
'p_opponent_loss_up', 'p_opponent_loss_down', 'p_opponent_loss_stay'
)
df = add_prob(
df,
'opponent_tie_up_count', 'opponent_tie_down_count', 'opponent_tie_stay_count',
'p_opponent_tie_up', 'p_opponent_tie_down', 'p_opponent_tie_stay'
)
# Dual transition outcome probabilities
df = add_prob(
df,
'opponent_up_win_up_count', 'opponent_up_win_down_count', 'opponent_up_win_stay_count',
'p_opponent_up_win_up', 'p_opponent_up_win_down', 'p_opponent_up_win_stay'
)
df = add_prob(
df,
'opponent_up_loss_up_count', 'opponent_up_loss_down_count', 'opponent_up_loss_stay_count',
'p_opponent_up_loss_up', 'p_opponent_up_loss_down', 'p_opponent_up_loss_stay'
)
df = add_prob(
df,
'opponent_up_tie_up_count', 'opponent_up_tie_down_count', 'opponent_up_tie_stay_count',
'p_opponent_up_tie_up', 'p_opponent_up_tie_down', 'p_opponent_up_tie_stay'
)
df = add_prob(
df,
'opponent_down_win_up_count', 'opponent_down_win_down_count', 'opponent_down_win_stay_count',
'p_opponent_down_win_up', 'p_opponent_down_win_down', 'p_opponent_down_win_stay'
)
df = add_prob(
df,
'opponent_down_loss_up_count', 'opponent_down_loss_down_count', 'opponent_down_loss_stay_count',
'p_opponent_down_loss_up', 'p_opponent_down_loss_down', 'p_opponent_down_loss_stay'
)
df = add_prob(
df,
'opponent_down_tie_up_count', 'opponent_down_tie_down_count', 'opponent_down_tie_stay_count',
'p_opponent_down_tie_up', 'p_opponent_down_tie_down', 'p_opponent_down_tie_stay'
)
df = add_prob(
df,
'opponent_stay_win_up_count', 'opponent_stay_win_down_count', 'opponent_stay_win_stay_count',
'p_opponent_stay_win_up', 'p_opponent_stay_win_down', 'p_opponent_stay_win_stay'
)
df = add_prob(
df,
'opponent_stay_loss_up_count', 'opponent_stay_loss_down_count', 'opponent_stay_loss_stay_count',
'p_opponent_stay_loss_up', 'p_opponent_stay_loss_down', 'p_opponent_stay_loss_stay'
)
df = add_prob(
df,
'opponent_stay_tie_up_count', 'opponent_stay_tie_down_count', 'opponent_stay_tie_stay_count',
'p_opponent_stay_tie_up', 'p_opponent_stay_tie_down', 'p_opponent_stay_tie_stay'
)
# df.head(8)
Calculate Expected Value#
Filter bot rows, any rows without interpretable values for previous move, etc.
# Filter out non-nan, agent-only rows and add expected value calculations
df_agent = drop_bot_rows(df)
df_agent = df_agent.dropna(subset=['previous_move']) # TODO why is this necessary?
# NB: need this for cournot transition tracking
df_agent = df_agent[df_agent['previous_move'] != 'none']
df_agent = df_agent[df_agent['previous_move'] != '']
df_agent = df_agent[df_agent['opponent_previous_move'] != '']
# outcome-transition
df_agent = df_agent[df_agent['opponent_previous_transition'] != '']
df_agent = df_agent[df_agent['opponent_prev2_transition'] != '']
# df_agent.head(25)
# df_agent.shape
Compute expected value
# EV for move base rates
df_agent = ev_move_baserate(df_agent)
# EV for transitions
df_agent = ev_transitions(df_agent)
df_agent = ev_cournot(df_agent)
# EV for outcome-transitions
df_agent = ev_previous_outcome(df_agent)
# EV for dual outcome-transitions
df_agent = ev_previous_outcome_previous_transition(df_agent)
# df_agent.head(6)
# df_agent.shape
<ipython-input-1-a2bbd7e510ee>:75: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['filler_1'] = points_lookup(agent_move, transition_move_lookup("transition_up", df_agent[move])).tolist()
<ipython-input-1-a2bbd7e510ee>:76: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['filler_2'] = points_lookup(agent_move, transition_move_lookup("transition_down", df_agent[move])).tolist()
<ipython-input-1-a2bbd7e510ee>:77: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['filler_3'] = points_lookup(agent_move, transition_move_lookup("transition_stay", df_agent[move])).tolist()
<ipython-input-1-a2bbd7e510ee>:78: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['prod_1'] = df_agent[prob1] * df_agent.filler_1
<ipython-input-1-a2bbd7e510ee>:79: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['prod_2'] = df_agent[prob2] * df_agent.filler_2
<ipython-input-1-a2bbd7e510ee>:80: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['prod_3'] = df_agent[prob3] * df_agent.filler_3
<ipython-input-1-a2bbd7e510ee>:81: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent['ev_transitions'] = df_agent['prod_1'] + df_agent['prod_2'] + df_agent['prod_3']
<ipython-input-1-a2bbd7e510ee>:83: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_agent[ev_col_name] = df_agent['ev_transitions']
# Test
# model7 = df_agent.copy()
# model7['ev_rock'] = model7['ev_outcome_dual_depend_rock']
# model7['ev_paper'] = model7['ev_outcome_dual_depend_paper']
# model7['ev_scissors'] = model7['ev_outcome_dual_depend_scissors']
# # Compute softmax distribution (1 min.)
# m7_softmax = get_softmax_probabilities(
# model7,
# ['ev_rock', 'ev_paper', 'ev_scissors']
# )
# # Select agent move based on softmax computed above (1 min.)
# model7 = pick_move(model7, m7_softmax)
# # Evaluate outcome of agent move choices in simulation above
# model7 = assign_agent_outcomes(model7)
# plot_summary_coarse = win_summary(groupby_f_data(model7, 'agent_outcome', 5), 'agent_outcome')
# plot_summary_fine = win_summary(groupby_f_data(model7, 'agent_outcome', 60), 'agent_outcome')
# plot_summary_fine = plot_summary_fine[plot_summary_fine['bin'] <= '50']
# plot_win_rates(plot_summary_coarse)
# plot_win_rates(plot_summary_fine)