<jupyter_start><jupyter_text>First, lets define some priors for the AI players using Beta distributions. We'll use two separate priors-one for proposing, another for accepting. Here are prior distributions of offers made by AI players A, B, and C, where A is a "stingy" player, B is a "fair" player, and C is a "generous" player:<jupyter_code>priors.ai <- data.frame(player=c('A', 'B', 'C'),
                        offer.s1=c(5, 20, 20),
                        offer.s2=c(20, 20, 5),
                        accept.s1=c(20, 20, 5),
                        accept.s2=c(5, 20, 20))
priors.ai %>% crossing(offer=seq(from=0, to=1, by=0.01)) %>%
    mutate(poffer=dbeta(offer, offer.s1, offer.s2)) %>%
    ggplot(aes(x=offer, y=poffer, color=player)) +
    geom_line() + theme_classic() + ylab('P(offer=X | player)') +
    ggtitle('When AI proposes, P(offer=X | player)')<jupyter_output><empty_output><jupyter_text>Now, here are prior probabilities of the same players accepting a given offer. Again, players A, B, and C are stingy, fair, and generous. Here, instead of using the Beta distributions themselves, we're using the CDFs of the Beta distributions to get sigmoid-like curves.<jupyter_code>priors.ai %>% crossing(offer=seq(from=0, to=1, by=0.01)) %>%
    mutate(paccept=pbeta(offer, accept.s1, accept.s2)) %>%
    ggplot(aes(x=offer, y=paccept, color=player)) +
    geom_line() + theme_classic() +
    ylab('P(Accept | offer=X, player)') +
    ggtitle('When AI accepts, P(Accept | offer=X, player)')<jupyter_output><empty_output><jupyter_text>Now, let's define similar priors for a large set of participants, some of which are assigned to proposeoffers to the AI players, and others are assigned to accept offers from the AI players. Instead of usinga fixed prior for all players, we sample prior parameters using normal hyperpriors.Sadly, I don't yet know how participants are likely to respond, so here let's pretend that they willbehave similarly to each AI player. In reality, however, participants are likely to be more variable,accepting poor offers from stingy players while rejecting poor offers from generous players, and givingstingy offers to exploitable players while giving more generous offers to hardball players.<jupyter_code>N <- 100  # number of participants
priors.subj <- data.frame(id=1:N,
                          condition=rep(c('propose', 'accept'), each=N/2),
                          subj.s1=rnorm(N, mean=10, sd=3),
                          subj.s2=rnorm(N, mean=10, sd=3))

priors.subj %>% filter(condition == 'propose') %>%
    crossing(offer=seq(from=0, to=1, by=0.01)) %>%
    mutate(poffer=dbeta(offer, subj.s1, subj.s2)) %>%
    ggplot(aes(x=offer, y=poffer)) +
    stat_smooth(method="loess", span=0.1, se=TRUE, alpha=0.3) + theme_classic() +
    ylab('P(offer=X | player)') +
    ggtitle('When Participant proposes, P(offer=X)')

priors.subj %>% filter(condition == 'accept') %>%
    crossing(offer=seq(from=0, to=1, by=0.01)) %>%
    mutate(paccept=pbeta(offer, subj.s1, subj.s2)) %>%
    ggplot(aes(x=offer, y=paccept)) + 
    stat_smooth(method="loess", span=0.1, se=TRUE, alpha=0.3) + theme_classic() +
    ylab('P(Accept | offer=X, player)') +
    ggtitle('When Participant accepts, P(Accept | offer=X)')<jupyter_output>Warning message:
“Removed 2 rows containing non-finite values (stat_smooth).”<jupyter_text>Now, using these priors, we can simulate trial data for each participant and AI player. Offers are drawn using draws from the Beta priors of the human/AI proposer, and acceptances/rejections are drawn usinga binomial distribution with a rate of acceptance defined by the human/AI Beta CDF priors.<jupyter_code>TRIALS <- 25 # number of trials per subj/AI
df <- priors.subj %>% crossing(priors.ai) %>%
    mutate(ai.s1=ifelse(condition == 'propose', accept.s1, offer.s1),
           ai.s2=ifelse(condition == 'propose', accept.s2, offer.s2)) %>%
    select(-offer.s1, -offer.s2, -accept.s1, -accept.s2) %>%
    crossing(trial=1:TRIALS) %>%
    rowwise %>%
    mutate(offer=ifelse(condition=='propose',
                        rbeta(1, subj.s1, subj.s2),
                        rbeta(1, ai.s1, ai.s2)),
           accept=ifelse(condition=='propose',
                         rbinom(1, 1, pbeta(offer, ai.s1, ai.s2)),
                         rbinom(1, 1, pbeta(offer, subj.s1, subj.s2))),
           earning=ifelse(accept, offer, 0))<jupyter_output><empty_output><jupyter_text>Finally, let's try to recover this information using a mixed-effects model:<jupyter_code>m <- glmer(accept ~ player * offer * condition + (1 | id),
           family=binomial(link='logit'),
           data=df)
m %>% ggpredict(terms=c('offer [all]', 'player', 'condition')) %>% plot()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13963774220724515, 'fraction_numerical': 0.02169334456613311, 'mean_word_length': 3.6742125984251968, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '383544', 'license': 'MIT', 'n_tokens_mistral': 1696, 'n_tokens_neox': 1553, 'n_words': 438, 'path': 'sim/sim.ipynb', 'repo_name': 'IMC-Lab/UG-causation', 'size': '4748'}