stratEst is a software package for the estimation of finite mixture models of discrete choice strategies in the statistical computing environment R (R Core Team, 2020). Discrete choice strategies can be customized by the user to fit the environment in which choices are made. The parameters of the strategy estimation model describe the behavior of each strategy and how frequent each strategy is in the population. The estimation function of the package uses the expectation maximization algorithm and the Newton-Raphson method to find the maximum likelihood estimates of the model parameters. The estimation function can also be used to fit a strategy estimation model with individual level covariates to explain the selection of strategies by individuals. The package contains functions for data processing and simulation, strategy generation, parameter tests, model checking, and model selection. This page provides a short introduction to the package. For a comprehensive introduction to the package, please see the published paper or the package vignette.
Please cite the following article when using the package:
Dvorak, F. (2023). stratEst: a software package for strategy frequency estimation. Journal of the Economic Science Association, 9, 337–349. https://doi.org/10.1007/s40881-023-00141-7
The most recent CRAN version of stratEst can be installed by executing the following command in the R console:
install.packages("stratEst")
The development version of the package can be installed from GitHub with the help of the package devtools (Wickham, Hester, and Chang 2020):
install.packages("devtools")
library(devtools)
install_github("fdvorak/stratEst")
After the installation, the package is loaded into memory and attached to the search path with the command:
library(stratEst)
I illustrate the core features of the package on the basis of the game rock-paper-scissors. In each period of this game, two players simultaneously choose one of three possible actions: rock, paper or scissors. The winner of the period is determined by the following rule: rock crushes scissors, scissors cuts paper, and paper covers rock. If both players choose the same action, this results in a tie. Rock-paper-scissors has a unique Nash equilibrium. The Nash equilibrium suggest that every player uses the same strategy. This strategy plays each of the three actions with probability one-third.
The data set WXZ2015
contains the data of a
rock-paper-scissors experiment conducted by Wang, Xu,
and Zhou (2014). The data contains the observations 72 university
students playing 300 periods of the rock-paper-scissors game in groups
of six participants. In each period, each participant is randomly
matched with another participant from the own group. In the experiment,
35.7 percent of all actions are rock (r
), 32.2 percent are
paper (p
), and 32.1 percent are scissors (s
)
which seems to be fairly inline with the Nash equilibrium
prediction.
There are many other choice strategies which can explain the observed distribution of choices. Wang et al. (2014) show that a conditional response strategy provides a better explanation for the data than the Nash equilibrium strategy. The conditional response strategy is more complex than Nash play as it takes the outcome of the previous period into account for the choice in current period.
The observed distribution of choices can also be explained by a finite mixture model of several strategies. To give an example, consider a uniform mixture of three types of players, one who always plays rock, one who always plays paper, and one who always plays scissors.
This example illustrates how to use the package in order to fit and compare different strategy estimation models to the data of the rock-paper-scissors experiment. The different strategy estimation models are selected to illustrate the features of the package and lack the theoretical justification provided by Wang et al. (2014) for the conditional response strategy.
The strategy generation function of the package is
stratEst.strategy()
. The following code creates two
strategies: a mixed strategy with unspecified choice probabilities, and
the Nash strategy.
rps = c("r", "p", "s")
mixed = stratEst.strategy(choices = rps)
nash = stratEst.strategy(choices = rps, prob.choices = rep(1/3, 3))
The argument choices
expects a character vector with the
names of the choices. The argument prob.choice
can be used
to define the choice probabilities of the strategy. If printed out in
the console, the strategies look like this:
print(mixed)
## prob.r prob.p prob.s
## 1 NA NA NA
print(nash)
## prob.r prob.p prob.s
## 1 0.333 0.333 0.333
The objects mixed
and nash
returned by the
strategy function are data frames of class
stratEst.strategy
. Since the choice probabilities of the
mixed strategy were not specified, the choice probabilities are
NA
. This indicates to the estimation function that these
parameters should be estimated from the data.
The strategies nash
and mixed
are simple
strategies in the sense that the choice probabilities of these
strategies do not change from one situation to the next. The strategies
only have one internal state and one associated set of choice
probabilities. More complex strategies have several states with
different sets of choice probabilities. The complex strategies
transition from one state to the other after some input is observed. The
input may be a specific situation or history of events in the game.
To illustrate the concept, a strategy is generated which randomizes
in the first period and subsequently imitates the choice of the previous
period. The following code generates the strategy
imitate
:
last.choice = c(NA, rps)
imitate = stratEst.strategy(choices = rps, inputs = last.choice,
num.states = 4,
prob.choices = c(rep(1/3, 3), 1, 0, 0,
0, 1, 0, 0, 0, 1),
tr.inputs = rep(c(2, 3, 4), 4))
What changed compared to the previous function calls is that the
argument inputs
is used to define a set of inputs. This set
contains the names of all possible choices in the last period of the
game. The value NA
in the set indicates that the input can
be missing. This is the case in the first period when no information
from the previous period exists. The argument num.states
defines the number of states of the strategy. The argument
tr.inputs
defines the deterministic state transitions for
all possible inputs in all states. The result is a strategy with four
states. Each state is represented by one row of the object
imitate
.
print(imitate)
## prob.r prob.p prob.s tremble tr(r) tr(p) tr(s)
## 1 0.333 0.333 0.333 NA 2 3 4
## 2 1.000 0.000 0.000 NA 2 3 4
## 3 0.000 1.000 0.000 NA 2 3 4
## 4 0.000 0.000 1.000 NA 2 3 4
The strategy imitate
has a column named
tr(x)
for each possible input x
. An exception
is the element NA
that indicates the missing input in the
first period. The values supplied to the argument tr.inputs
appear in row wise order.
The strategy imitate
also contains a column with the
name tremble
. The values in this column indicate the
probability to choose one of the choices not prescribed by the strategy
in the current state. A tremble probability is usually necessary for a
pure strategy with choice probabilities of zero and one. The purpose of
the tremble probability is to avoid that a single deviation an
individual from the choice pattern of the pure strategy results in a
likelihood of zero that the individual uses the strategy. The tremble
probability can be specified by the argument trembles
. If
the argument is missing, the probability of a tremble is
NA
. This signals to the estimation function that the
parameter should be estimated from the data.
The strategy imitate
transitions from one state to the
other by the following deterministic rule.In the first period, the
strategy observes the input NA
since there is no
information on the previous choice available. By convention, whenever
the input is NA
, the strategy moves to its start state. The
start state of the strategy is the state represented by the first row.
The strategy makes a choice according to the choice probabilities in the
first row. In period two, the strategy observes the input (either rock,
paper or scissors) and moves to the next state defined by the value of
tr(input)
in the current state. The values supplied to
tr.inputs
define the desired behavior of the strategy
imitate
. It randomly makes a choice in the first period,
and subsequently plays rock after rock, paper after paper, and scissors
after scissors.
In order fit the strategies to the rock-paper-scissors data, the data
must be in a suitable format. The function stratEst.data()
can be used to reshape the raw data.
data.WXZ2014 <- stratEst.data(data = WXZ2014, choice = "choice",
input = c("choice"), input.lag = 1,
id = "id", game = "game",
period = "period")
To the first argument of the function, we pass a
data.frame
object with variables in columns. We need to
specify the variable in the data which contains the discrete choices
using the argument choice
. The argument input
allows us to select one or more variable names which serve as input for
the strategies in the estimation. If we select more than one variable,
the function concatenates the values of these variables to a unique
factor level. For this example, we only need one input variable, the
choices of the participants in the experiment. As the input should
reflect the choice in the previous period we specify a lag of one
period. The arguments id
, game
, and
period
uniquely identify the participant, and the period
within the game.
The function stratEst.data()
returns an data frame
object of class stratEst.data
. We can inspect this object
by printing it to the console with the command
print(data.WXZ2015)
.
The function has two mandatory arguments which are data
and strategies
. The object passed to argument
data
must be of class stratEst.data
. The
object passed to argument strategies
must be a list of
stratEst.strategy
objects. The following code fits four
different models to the rock-paper-scissors data:
model.nash <- stratEst.model(data = data.WXZ2014,
strategies = list("nash" = nash))
model.mixed <- stratEst.model(data = data.WXZ2014,
strategies = list("mixed" = mixed))
model.imitate <- stratEst.model(data = data.WXZ2014,
strategies = list("imitate" = imitate))
model.mixture <- stratEst.model(data = data.WXZ2014,
strategies = list("nash" = nash,
"imitate" = imitate))
The estimation function stratEst()
estimates the model
parameters and returns a list object of class
stratEst.model
. The elements of this list can be accessed
with the syntax model$object
where object is an object name
in names(model)
. The generic function
summary()
prints a summary of a fitted model to the
console.
The function stratEst.check()
can be used to inspect the
global model fit. It summarizes the log likelihood of the model, the
number of free model parameters, and the values of three information
criteria. The three information criteria are the Akaike information
criterion (aic
), the Bayesian information criterion
(bic
), and Integrated classification likelihood
(icl
).
models <- list(model.nash, model.mixed, model.imitate, model.mixture)
compare <- do.call(rbind, unlist(lapply(models, stratEst.check),
recursive = F))
rownames(compare) <- c("model.nash", "model.mixed", "model.imitate",
"model.mixture")
print(compare)
## loglike free.par aic bic icl
## model.nash -23730.03 0 47460.05 47460.05 47460.05
## model.mixed -23704.04 2 47412.09 47416.64 47416.64
## model.imitate -23205.91 1 46413.82 46416.10 46416.10
## model.mixture -22358.43 2 44720.87 44725.42 44728.34
We see that the fit of the model with the mixed strategy is better
than the fit of the model with the Nash strategy. The values of the
information criteria indicate that this is true even if we take into
account that the model with the mixed strategy has more free parameters.
The estimated choice probabilities of the mixed strategy can be accessed
with the command model.mixed$probs.par
. The estimated
choice probabilities reflect the overall distribution of choices. We can
test whether the estimated choice probabilities differ from one-third
using the function stratEst.test()
. With the option
par = "probs"
, the function performs a t test for each
estimated choice probability:
t.probs <- stratEst.test(model = model.mixed, par = "probs", values = 1/3, plot = FALSE)
print(t.probs)
## estimate diff std.error t.value df p.value
## probs.par.1 0.3223 -0.0111 0.0014 -8.0838 70 0
## probs.par.2 0.3566 0.0232 0.0013 17.6404 70 0
## probs.par.3 0.3212 -0.0122 0.0012 -10.3417 70 0
The model with the strategy imitate
yields a better fit
than the model with the mixed strategy despite having one free parameter
less. However, the best global fit is obtained the mixture model of
nash
and imitate
. The log likelihood of the
mixture model is substantially larger than the log likelihood of all
other models. The following commands print the estimated shares and
strategies of this model the console:
print(model.mixture$shares, digits = 2)
## nash imitate
## share 0.58 0.42
print(model.mixture$strategies, digits = 3)
## $nash
## prob.r prob.p prob.s tr(p) tr(r) tr(s) tremble
## 1 0.333 0.333 0.333 1 1 1 NA
##
## $imitate
## prob.r prob.p prob.s tremble tr(r) tr(p) tr(s)
## 1 0.333 0.333 0.333 NA 2 3 4
## 2 1.000 0.000 0.000 0.391 2 3 4
## 3 0.000 1.000 0.000 0.391 2 3 4
## 4 0.000 0.000 1.000 0.391 2 3 4
The estimated shares suggest that each strategy is used by
approximately half of the participants in the experiment. The fitted
tremble parameter of the strategy imitate
indicates that a
different choice than the one predicted by the strategy is chosen in 39
percent of all observations. In these observations, the strategy
suggests that players randomly pick one of the other choices.
This example illustrates how to replicate the strategy estimation results of the seminal strategy estimation study by Dal Bo and Frechette (2011). The study reports results on the evolution of cooperation in the indefinitely repeated prisoner’s dilemma across six different treatments. The six treatments differ in the stage-game parameters and the continuation probability \(\delta\) of the repeated game.
The stage-game parameters are depicted in Figure below where the parameter R is either 32, 40 or 48. For each value of R two treatments exist with \(\delta\) of 1/2 or 3/4 resulting in 2 times three between subject design with six treatments overall.
C | D | |
---|---|---|
C | R,R | 12,50 |
D | 50,12 | 25,25 |
Dal Bo
and Frechette (2011) report the results of treatment-wise strategy
frequency estimation for six candidate strategies: Always Defect (ALLD),
Always Cooperate (ALLC), Tit-For-Tat (TFT), Grim-Trigger (GRIM),
Win-Stay-Lose-Shift (WSLS), and a trigger strategy with two periods of
punishment (T2). The six strategies are the elemenets of the list
strategies.DF2011
. The Tit-For-Tat strategy looks like
this:
plot(strategies.DF2011$TFT, title = "TFT")
The strategy TFT chooses between the alternatives defect
(d
) and cooperate (c
). State transitions are
triggered by four different inputs: The four inputs reflect the
combination of actions in the last period. The first letter represents
the own action in the last period, and the second letter the action of
the other player. All strategies in the list
strategies.DF2011
have the same structure of choices and
inputs.
The data frame DF2011
contains the experimental data
collected by Dal Bo
and Frechette (2011). The data can be inspected in the console with
the command print(DF2011)
.
The following code creates a stratEst.data
frame which
fits the structure of strategies:
data.DF2011 <- stratEst.data(data = DF2011, choice = "choice",
input = c("choice","other.choice"),
input.lag = 1)
The options input = c("choice","other.choice")
and
input.lag = 1
create the input variable by concatenating
the own and the other player’s choice of the previous period. The
following model estimation commmand can be used to replicate the
findings of Dal Bo
and Frechette (2011):
model.DF2011 <- stratEst.model(data = data.DF2011,
strategies = strategies.DF2011,
sample.id = "treatment" )
The command estimates one vector of shares and one tremble parameter for each treatment. The estimated shares are the strategy shares reported in the first column of Table 7 on page 424 of Dal Bo and Frechette (2011).
print(round(do.call(rbind, model.DF2011$shares), 2))
## ALLD ALLC GRIM TFT WSLS T2
## treatment.D5R32 0.92 0.00 0.00 0.08 0.00 0.00
## treatment.D5R40 0.78 0.08 0.04 0.10 0.00 0.00
## treatment.D5R48 0.53 0.07 0.00 0.38 0.02 0.00
## treatment.D75R32 0.65 0.00 0.00 0.35 0.00 0.00
## treatment.D75R40 0.11 0.30 0.27 0.33 0.00 0.00
## treatment.D75R48 0.00 0.08 0.12 0.56 0.00 0.24
Fudenberg, Rand and Dreber (2011) conduct a prisoner’s dilemma experiment in which intended choices are implemented with noise. The stage-game payoffs are such that cooperation means paying a cost \(c\) to give a benefit \(b\) to the other player. The authors run four between subjects treatments. The cost \(c\) is fixed at 2 points experimental currency in every treatment. The benefit to cost ratio \(b/c\) varies across treatments and took the values 1.5, 2, 2.5, and 4.
Because of the noisy implementation of choices, Fudenberg
et al. (2011) add several lenient and forgiving strategies to the
original set of candidate strategies used by Dal Bo
and Frechette (2011). The augmented set of strategies is available
as list object strategies.FRD2012
. The choices of the
strategies are d
(defect), and c
(cooperate).
The four inputs reflect the four different combinations of the own
choice, and the choice of the other player in the previous period.
The data frame FRD2012
contains the raw data of the
experiment. It contains two variables that indicate own choice and the
choice of the other player in the last period. These two variables are
passed to the argument inputs
of the data generation
function:
data.FRD2012 <- stratEst.data(data = FRD2012, choice = "choice",
input =c("last.choice","last.other"))
The following code replicates the strategy shares reported by Fudenberg et al. (2011) in Table 3 on page 733 of the paper.
model.FRD2012 <- stratEst.model(data = data.FRD2012,
strategies = strategies.FRD2012,
sample.id = "bc")
print(round(do.call(rbind, model.FRD2012$shares), 2))
## ALLC TFT TF2T TF3T T2FT T2F2T GRIM GRIM2 GRIM3 ALLD DTFT
## bc.1.5 0.00 0.19 0.05 0.01 0.06 0.00 0.14 0.06 0.06 0.29 0.14
## bc.2 0.03 0.06 0.00 0.03 0.07 0.11 0.07 0.18 0.28 0.17 0.00
## bc.2.5 0.00 0.09 0.17 0.05 0.02 0.11 0.11 0.02 0.24 0.14 0.05
## bc.4 0.07 0.09 0.18 0.13 0.05 0.09 0.06 0.07 0.10 0.14 0.03
For the data the treatment \(b/c\) = 4, the estimation function finds a better solution with a larger log likelihood than the solution reported by Fudenberg et al. (2011).
Dvorak, Fischbacher and Schmelz (2020) study conformity and anticonformity in a binary choice experiment. Participants are matched in groups of three and compete for a monetary reward with the other two group members. In some choices, one group member is informed about the choices of two other group members before making the own choice. For these choices, the experimental design allows to predict the prefered alternative of the participant.
Dvorak et al. (2020) find that two-thirds of the participants follow a conformist strategy. The conformist strategy generally follows the own preference if the choices of the other group members are in line with the own preference. It frequently deviates from the own preference and chooses the other alternative if the choices of the other group members are not in line with the own preference.
The remaining one-third of the participants follows an anticonformist strategy. The anticonformist strategy generally follows the own preference if the choices of the other group members are not in line with the own preference. It frequently deviates from the own preference the choices of the other group members are in line with the own preference.
The fitted choice parameters of the strategies are:
print(strategies.DFS2020)
## $anticonformist
## prob.follow prob.deviate tr(not in line) tr(in line)
## 1 0.823 0.177 1 2
## 2 0.404 0.596 1 2
##
## $conformist
## prob.follow prob.deviate tr(not in line) tr(in line)
## 1 0.425 0.575 1 2
## 2 0.860 0.140 1 2
The data set DFS2020
contains the experimental data of
Dvorak et al. (2020). The variables "choice"
indicates if
the choice of the participant follows the own preference or deviates
from the own preference. The variable "others.choices"
indicates if the choices of the two other two group members are in line
with the preference of the participant or not.
The data set additionally contains two the variables which are used as covariates of the strategy estimation model by Dvorak et al. (2020). The first is an intercept, which is one for every observation. The second is the score of the participant in a post-experimental conformity questionnaire (Mehrabian and Stefl, 1995). The mean conformity score is -0.078 with a standard deviation of 1.02.
The following command creates a stratEst.data
object
with the variable ```others.choices} as input:
data.DFS2020 <- stratEst.data(data = DFS2020,
input = c("others.choices"))
The model with covariates is estimated with the command:
model.DFS2020 <- stratEst.model(data = data.DFS2020 ,
strategies = strategies.DFS2020,
covariates = c("intercept",
"conformity.score"))
The estimated coefficients are:
print(model.DFS2020$coefficients)
## anticonformist conformist
## intercept 0 0.8273618
## conformity.score 0 0.8697285
The first strategy is the reference category of the structural model.
The coefficients for the reference category are always zero. The second
column contains the estimated coefficients for the conformist strategy.
The estimated coefficients indicate that prior probability to use the
conformist strategy increases with the score in the conformity
questionnaire. The individual prior probabilities of the participants
are returned as object model.DFS2020$prior.assignment
.
The estimated coefficient of the intercept can be used to calculate the estimated prior probability to use the conformist for a participant with a conformity score of zero. The prior probability is exp(0.83)/(1 + exp(0.83)) = 0.69. A participant who scores on standard deviation higher than average in the conformity questionnaire has a prior probability of exp(0.83 + 0.87)/(1 + exp(0.83 + 0.87)) = 0.85 to use the conformist strategy.
The function stratEst.test()
can be used to test whether
the estimated coefficients differ from zero.
test.coefficients <- stratEst.test(model.DFS2020, par = "coefficients", plot = FALSE)
print(test.coefficients)
## estimate diff std.error t.value df p.value
## coefficients.par.1 0.8274 0.8274 0.3065 2.6997 103 0.0081
## coefficients.par.2 0.8697 0.8697 0.3184 2.7319 103 0.0074
The function stratEst.check()
can be used to assess the
global and local model fit based on the Pearson \(\chi^{2}\) test statistic.
check.DFS2020 <- stratEst.check(model.DFS2020, chi.tests = TRUE,
bs.samples = 100)
print(check.DFS2020$chi.global)
## chi^2 min mean max p.value
## model.DFS2020 0.08554165 0.1041894 2.041561 7.13527 1
print(check.DFS2020$chi.local)
## chi^2 min mean max p.value
## anticonformist 52.29308 23.08893 47.44783 86.94558 0.34
## conformist 117.70654 63.90004 108.58108 151.07597 0.34
The distribution of the test statistics is approximated by drawing 100 bootstrap samples to limit computation time. The p value of the global test indicates the probability of the data given that the estimated model is the true model. The p value of the local test for the anticonformist strategy indicates the probability of the data of the subset of participants classified as anticonformist given that the fitted strategy is the true strategy. The p value of the test for the conformist strategy can be interpreted in the same way. Hence, both tests address the null hypothesis that the model is the true data generating model.
Dal Bó P, Fréchette GR (2011). “The Evolution of Cooperation in Infinitely Repeated Games: Experimental Evidence.” American Economic Review, 101(1), 411–429.
Dvorak F, Fischbacher U, Schmelz K (2020). “Incentives for Conformity and Anticonformity.” TWI Working Paper Series.
Fudenberg D, Rand DG, Dreber A (2012). “Slow to Anger and Fast to Forgive: Cooperation in an Uncertain World.” American Economic Review, 102(2), 720–749.
Mehrabian A, Stefl CA (1995). “Basic Temperament Components of Loneliness, Shyness, and Conformity.” Social Behavior and Personality, 23(3), 253–263.
R Core Team (2020). “R: A Language and Environment for Statistical Computing.” R Foundation for Statistical Computing, Vienna, Austria.
Wang Z, Xu B, Zhou HJ (2014). “Social Cycling and Conditional Responses in the Rock-Paper-Scissors Game.” Scientific Reports, 4(1), 2045–2322.
Wickham H, Hester J, Chang W (2020b). “devtools: Tools to Make Developing R Packages Easier.” R package version 2.3.0.