This markdown provides the R Code for the analyses of the three experiments from the Information Search in Everyday Decisions: The Generalizability of the Attraction Search Effect paper and allows the reproduction of all reported results and plots. The code has been written by me, Sophie Scharf - if you see any errors or have any questions, please email me directly to so.scharf@gmail.com.
The reported analyses and the reported code will have the following structure:
In this project, the goal was to test the generalizability of the Attraction Search Effect, the core prediction for information search from the new integrated coherence-based decision and search model (iCodes, Jekel, Glöckner, & Bröder, 2018). This effect states that people have a tendency to search for information on the more attractive option based on the already available evidence.
As the available evidence for the Attraction Search Effect is all based on the same semantic content of the decision task and the same cue value patterns, we try to dispose of the inherent restrictions from the original experiments and to replicate the Attraction Search Effect in this new contexts. For this purpose three online experiments were run that vary the semantic context of the decision task (Experiment 1, 2, and 3), the cue value patterns (Experiment 2), and the way of presenting the decision task (Experiment 3). The main hypothesis for all three experiments was that we find an overall positive Attraction Search Score, an index that represents the difference between search behavior consistent with the Attraction Search Effect and search behavior inconsistent with the Attraction Search Effect. This score, therefore, is positive if subjects tend to search for the attractive option and is zero if subjects’ information search is unaffected by the options’ attractiveness.
These packages were used for the following analyses:
# Packages for data manipulation
library(tidyr)
library(dplyr)
library(knitr)
library(kableExtra)
library(tibble)
# Packages for plotting
library(ggplot2)
library(Cairo)
library(cowplot)
library(gridExtra)
library(viridis)
# Packages for multi-level analyses
library(lme4)
library(lmerTest)
# Packages for calculating effect sizes
library(effsize)
For each of the three experiments, there is one data set with demographic data and one with the behavioral data of the experiment:
# Experiment 1
demo.Exp1 <- read.csv("demo_data_Exp1.csv") # demographic data
data.Exp1 <- read.csv("clean_data_Exp1.csv") # behavioral data
# Experiment 2
demo.Exp2 <- read.csv("demo_data_Exp2.csv") # demographic data
data.Exp2 <- read.csv("clean_data_Exp2.csv") # behavioral data
# Experiment 3
demo.Exp3 <- read.csv("demo_data_Exp3.csv") # demographic data
data.Exp3 <- read.csv("clean_data_Exp3.csv") # behavioral data
I only used one custom function which allows me to identify whether an instance x is not part of an vector y. This function returns TRUE if a value x is not in the vector y.
"%w/o%" <- function(x, y)!('%in%'(x,y))
As a first step, we will take a look at the demographic characteristics of the sample in Experiment 1.
# Age of subjects
demo.Exp1 %>%
summarise(mean.age = mean(age),
sd.age = sd(age),
min.age = min(age),
max.age = max(age))
# Gender of subjects
demo.Exp1 %>%
group_by(sex) %>%
summarise(n.sex = n()) %>%
ungroup() %>%
mutate(percent.sex = n.sex/sum(n.sex))
# Job of subjects
demo.Exp1 %>%
group_by(job) %>%
summarise(n.job = n()) %>%
ungroup() %>%
mutate(percent.job = n.job/sum(n.job))
The first analysis concerns the subjective importance ratings by subjects given for the cues used in the decision task. In the following analysis, we calculated the means and the standard deviations for the importance ratings for every cue in every scenario.
# Create data fram with importance ratings data
importanceRatings.Exp1 <- data.Exp1 %>%
# keep only importance rating data and relevant variables
filter(data == "importance.data") %>%
select(ID, scenario, cue, importance.rating) %>%
group_by(scenario, cue) %>%
# Calculate mean & sd per scenario & cue
summarise(mean.rating = mean(importance.rating),
sd.rating = sd(importance.rating))
# Create table of means and standard deviations of importance ratings
kable(importanceRatings.Exp1, format = "html", padding = 2) %>%
kable_styling(bootstrap_options = "striped", font_size = 10) %>%
group_rows("City", 1, 4) %>%
group_rows("Hair Salon", 5, 8) %>%
group_rows("Hotel", 9, 12) %>%
group_rows("Job", 13, 16) %>%
group_rows("Pizza", 17, 20) %>%
group_rows("Weather", 21, 24)
scenario | cue | mean.rating | sd.rating |
---|---|---|---|
City | |||
city | capital | 57.465347 | 32.65946 |
city | international.airport | 68.052805 | 29.81184 |
city | opera | 36.993399 | 29.94730 |
city | university | 47.363036 | 28.23753 |
Hair Salon | |||
hair | appointment | 36.310231 | 26.67693 |
hair | competency | 85.161716 | 22.04324 |
hair | price | 58.016502 | 26.02374 |
hair | proximity.home | 37.587459 | 26.62030 |
Hotel | |||
hotel | clean | 76.333333 | 27.14868 |
hotel | price | 64.699670 | 24.83986 |
hotel | proximity.beach | 59.069307 | 29.51167 |
hotel | proximity.citycenter | 37.669967 | 26.00898 |
Job | |||
job | colleagues | 64.640264 | 28.43371 |
job | pay | 72.409241 | 23.32049 |
job | proximity.home | 44.947195 | 27.34893 |
job | work.conditions | 73.521452 | 27.33067 |
Pizza | |||
pizza | friendly | 33.330033 | 27.03977 |
pizza | on.time | 47.250825 | 28.03905 |
pizza | price | 55.122112 | 26.31662 |
pizza | quality | 89.155115 | 18.21448 |
Weather | |||
weather | bild.private.news | 23.689769 | 24.08517 |
weather | GWS | 82.679868 | 24.88583 |
weather | horoscope | 5.171617 | 12.53988 |
weather | zdf.public.news | 63.224422 | 30.12396 |
For testing our hypothesis, the first relevant analysis step is to calculate the Attraction Search Score. In general the Attraction Search Score is the difference of the probability of searching for one option, given that this option is attractive, minus the probability of searching for the same option, given that this option is not attractive. Thus, a key experimental manipulation is the attractiveness of the options. The attractiveness of the options is manipulated in this experiment via the version of the patterns: in Version a of a pattern Option A is attractive, in Version b Option B is attractive (and, thus, Option A is unattractive). Therefore, the Attraction Search Score is calculated as the probability of searching for information on Option A in Version a minus the probability of searching for Option A in Version b, \(AS\ Score= p(Searching\ for\ Option\ A\ |\ Version\ a) - p(Searching\ for\ Option\ A\ |\ Version\ b)\). As a first step, we created a data frame which contains the individual Attraction Search Scores.
# Calculating the AS-Score for every participant
ASScore.Exp1 <- data.Exp1 %>%
# keep only information search data in decision task
filter(data == "choice.data" & answer.type == "search") %>%
select(ID, version, option.answer) %>%
group_by(ID, version, option.answer) %>%
# calculate number of searches per version and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID,version,option.answer,fill = list(n.searches=0)) %>%
group_by(ID, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(option.answer == "OptionA") %>%
select(-option.answer, -n.searches) %>%
spread(version, percent.searches) %>%
select(ID, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching Option A given Version a from probability of searching Option A given Version b
mutate(ASScore = VersionA - VersionB)
To test the hypothesis, that subjects show behavior consistent with the Attraction Search Effect, we run a one-sided, one-sample t-test against zero with the Attraction Search Score as dependent variable, as a positive Attraction Search Score indicates behavior consistent with the Attraction Search Effect.
# One-sided, one-sample t test against zero
t.test(ASScore.Exp1$ASScore, mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.Exp1$ASScore
## t = 14.549, df = 302, p-value < 2.2e-16
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.2877284 Inf
## sample estimates:
## mean of x
## 0.3245325
# Calculate Cohen's d
ES.ASScore.Exp1 <- mean(ASScore.Exp1$ASScore)/sd(ASScore.Exp1$ASScore)
print(ES.ASScore.Exp1)
## [1] 0.8358009
The next analysis step is to test whether the Attraction Search Score is significant for the separate cue value patterns. In order to test this hypothesis, we need to calculate the Attraction Search Score on the level of patterns. It is important to note, that the three used cue patterns are described in the data by the number they had in the Jekel et al. (2018) paper - in the manuscript, we gave new numbers to the used cue value patterns. Therefore, Pattern 4 in this Markdown is Pattern 1 in the manuscript, Pattern 5 is Pattern 2, and Pattern 7 is Pattern 3 in the manuscript.
# Calculate Attraction Search Score per pattern
ASScore.pattern.Exp1 <- data.Exp1 %>%
# keep only information search data in decision task
filter(data == "choice.data" & answer.type == "search") %>%
select(ID, pattern, version, option.answer) %>%
group_by(ID, pattern, version, option.answer) %>%
# calculate number of searches per pattern, version, and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID, pattern, version, option.answer, fill = list(n.searches=0)) %>%
group_by(ID, pattern, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(option.answer == "OptionA") %>%
select(-option.answer, -n.searches) %>%
spread(version, percent.searches) %>%
select(ID, pattern, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching Option A given Version a from probability of searching Option A given Version b
mutate(ASScore = VersionA - VersionB)
To test the hypothesis, that subjects show behavior consistent with the Attraction Search Effect in each cue value pattern, we run a one-sided, one-sample t-test against zero with the Attraction Search Score as dependent variable for each pattern, as a positive Attraction Search Score indicates behavior consistent with the Attraction Search Effect.
# One-sided, one-sample t test against zero for Pattern 4
t.test(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 4], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 4]
## t = 6.0646, df = 302, p-value = 1.974e-09
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.1801837 Inf
## sample estimates:
## mean of x
## 0.2475248
# Cohen's d for Pattern 4
ES.ASScore.pattern4.Exp1 <- mean(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 4])/sd(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 4])
print(ES.ASScore.pattern4.Exp1)
## [1] 0.3484006
# One-sided, one-sample t test against zero for Pattern 5
t.test(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 5], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 5]
## t = 8.2874, df = 302, p-value = 1.917e-15
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.2114619 Inf
## sample estimates:
## mean of x
## 0.2640264
# Cohen's d for Pattern 5
ES.ASScore.pattern5.Exp1 <- mean(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 5])/sd(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 5])
print(ES.ASScore.pattern5.Exp1)
## [1] 0.4760961
# One-sided, one-sample t test against zero for Pattern 7
t.test(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 7], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 7]
## t = 13.62, df = 302, p-value < 2.2e-16
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.4060732 Inf
## sample estimates:
## mean of x
## 0.4620462
# Cohen's d for Pattern 7
ES.ASScore.pattern7.Exp1 <- mean(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 7])/sd(ASScore.pattern.Exp1$ASScore[ASScore.pattern.Exp1$pattern == 7])
print(ES.ASScore.pattern7.Exp1)
## [1] 0.7824323
Lastly, we want to test whether the Attraction Search Effect also exists in every content scenario. For this purpose, we calculate the Attraction Search Score across individuals and cue patterns for each decision context. As there are no repetitions of scenarios, this analysis results in only one Attraction Search Score per scenario and, thus, does not allow statistical significance tests. We will take a closer look at the between-decision context heterogeneity with a mixed logistic regression analysis with crossed-random effects for subjects and scenarios.
ASScore.Scenarios.Exp1 <- data.Exp1 %>%
# keep only information search data in decision task
filter(data == "choice.data" & answer.type == "search") %>%
select(scenario, pattern, version, option.answer) %>%
group_by(scenario, version, option.answer) %>%
# calculate number of searches per pattern, version, and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(scenario, version, option.answer, fill = list(n.searches=0)) %>%
group_by(scenario, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(option.answer == "OptionA") %>%
select(-option.answer, -n.searches) %>%
spread(version, percent.searches) %>%
select(scenario, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching Option A given Version a from probability of searching Option A given Version b
mutate(ASScore = VersionA - VersionB)
# Create table of means and standard deviations of importance ratings
kable(ASScore.Scenarios.Exp1, format = "html", padding = 2) %>%
kable_styling(bootstrap_options = "striped", font_size = 10)
scenario | VersionA | VersionB | ASScore |
---|---|---|---|
city | 0.4466667 | 0.2418301 | 0.2048366 |
hair | 0.6405229 | 0.1800000 | 0.4605229 |
hotel | 0.4400000 | 0.1307190 | 0.3092810 |
job | 0.5751634 | 0.2400000 | 0.3351634 |
pizza | 0.6862745 | 0.2266667 | 0.4596078 |
weather | 0.5266667 | 0.3529412 | 0.1737255 |
Due to the fact that the Attraction Search Score is range restricted ([-1,1]) and can only take on distinct values, a t test might not be the most adequate analysis. Therefore, in order to test the main hypothesis more adequately as well as account for several sources of heterogeneity, we also ran a trial-level generalized linear mixed model, with searching for Option A vs. searching for Option B as the dependent variable, random intercepts and slopes for subjects and scenarios, and pattern version as a Level 1 predictor.
# Create dataframe for generalized linear mixed model analysis
GLMER.data.Exp1 <- data.Exp1 %>%
# select only search data
filter(data == "choice.data" & answer.type == "search") %>%
select(ID, scenario:version, option.answer) %>%
mutate(# recode DV for logistic multilevel regression
option.answer.av = recode(option.answer, OptionA = 1, OptionB = 0)) %>%
mutate(scenario = as.factor(scenario),
ID = as.factor(ID))
# Assign effect-coding contrast to version predictor
contrasts(GLMER.data.Exp1$version) <- contr.sum(2)
contrasts(GLMER.data.Exp1$version)
## [,1]
## a 1
## b -1
# Run generalized linear mixes model - full model
glmer.ASScore.Exp1.full <- glmer(option.answer.av ~ version+(1 + version|ID)+(1 + version|scenario),
data = GLMER.data.Exp1, family = binomial)
summary(glmer.ASScore.Exp1.full)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: option.answer.av ~ version + (1 + version | ID) + (1 + version |
## scenario)
## Data: GLMER.data.Exp1
##
## AIC BIC logLik deviance df.resid
## 2217.5 2261.6 -1100.8 2201.5 1810
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.4106 -0.6641 -0.4721 0.8574 2.3424
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.03756 0.1938
## version1 0.05629 0.2373 -0.42
## scenario (Intercept) 0.06634 0.2576
## version1 0.05241 0.2289 0.00
## Number of obs: 1818, groups: ID, 303; scenario, 6
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.5306 0.1207 -4.396 1.10e-05 ***
## version1 0.7515 0.1109 6.773 1.26e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## version1 -0.085
# Final model for plots
glmer.ASScore.Exp1.final <- glmer.ASScore.Exp1.full
Version has a significant, positive effect on searched-for option, indicating that subjects were more likely to search for Option A when presented with a pattern in Version a. Nonetheless, there is variability in the effect between subjects, patterns, and scenarios. In an attempt to explain this variability, we ran two mixed logistic regressions with additional predictors. The first predictor is which cue pattern was presented in a trial and was helmert-coded. The second predictor is the individual rank correlation of our assumed cue ordering and the ordering based on subjects’ subjective importance ratings for each content scenario.
# Individual rank correlations of importance ratings
rankCor_importance <- data.Exp1 %>%
filter(data == "importance.data") %>%
select(ID, scenario, cue, importance.rating) %>%
arrange(ID, scenario, desc(importance.rating))
# Add intended ranking of cues
rankCor_importance$actualRanking <- rep(c("a.capital", "b.international.airport", "c.university", "d.opera", "a.competency", "b.price", "c.proximity.home", "d.appointment", "a.proximity.beach", "b.price", "c.proximity.citycenter", "d.clean", "a.pay", "b.work.conditions", "c.colleagues", "d.proximity.home", "a.quality", "b.price", "c.on.time", "d.friendly", "a.GWS", "b.zdf.public.news", "c.bild.private.news", "d.horoscope"), length.out = nrow(rankCor_importance))
# Add subjects order of cues as a,b,c,d
rankCor_importance$orderCues <- recode(rankCor_importance$cue,
capital = "a", international.airport = "b", university = "c", opera = "d",
competency = "a", price = "b", proximity.home = "c", appointment = "d",
proximity.beach = "a", proximity.citycenter = "c", clean = "d",
pay = "a", work.conditions = "b", colleagues = "d",
quality = "a", on.time = "c", friendly = "d",
GWS = "a", zdf.public.news = "b", bild.private.news = "c", horoscope = "d")
# Final calculation of cue ordering correlations
rankCor_importanceFinal <- rankCor_importance %>%
mutate(orderCues = ifelse(as.character(orderCues) == "proximity.home" & as.character(scenario) == "job", "d",
as.character(orderCues))) %>%
unite(., "original.ranking", actualRanking, scenario, sep = ".", remove = FALSE) %>%
unite(., "participant.ranking", orderCues, cue, scenario, sep = ".", remove = FALSE) %>%
group_by(ID, scenario) %>%
# transform ranking into numerical variables
mutate(original.ranking.num = as.numeric(as.factor(original.ranking)),
participant.ranking.num = as.numeric(as.factor(participant.ranking))) %>%
# calculate rank correlation per scenario
summarise(cor.Ranking = cor(original.ranking.num, participant.ranking.num, method = "spearman")) %>%
mutate(c.corRanking = cor.Ranking - mean(cor.Ranking))
# Create dataframe for generalized linear mixed model analysis
GLMER.data.predictors.Exp1 <- GLMER.data.Exp1 %>%
mutate(ID = as.numeric(as.character(ID))) %>%
left_join(rankCor_importanceFinal, by = c("ID", "scenario")) %>%
mutate(pattern = as.factor(pattern),
ID = as.factor(ID))
# Assign helmert-coding contrast to pattern predictor
contrasts(GLMER.data.predictors.Exp1$version) <- contr.sum(2)
contrasts(GLMER.data.predictors.Exp1$pattern) <- contr.helmert(3)
contrasts(GLMER.data.predictors.Exp1$pattern)
## [,1] [,2]
## 4 -1 -1
## 5 1 -1
## 7 0 2
# Predict random slopes with difference in cue patterns
glmer.ASScore.Exp1.Pattern <- glmer(option.answer.av ~ version*pattern+(1 + version|ID)+(1+version|scenario),
data = GLMER.data.predictors.Exp1, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
summary(glmer.ASScore.Exp1.Pattern)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: option.answer.av ~ version * pattern + (1 + version | ID) + (1 +
## version | scenario)
## Data: GLMER.data.predictors.Exp1
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 2067.9 2134.0 -1022.0 2043.9 1806
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.8441 -0.6813 -0.3329 0.7156 3.8766
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.16004 0.4000
## version1 0.17578 0.4193 -0.35
## scenario (Intercept) 0.08184 0.2861
## version1 0.06844 0.2616 -0.02
## Number of obs: 1818, groups: ID, 303; scenario, 6
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.63648 0.13622 -4.673 2.97e-06 ***
## version1 0.87511 0.12796 6.839 7.98e-12 ***
## pattern1 -0.80441 0.07483 -10.750 < 2e-16 ***
## pattern2 0.02387 0.04127 0.578 0.563040
## version1:pattern1 0.16045 0.07484 2.144 0.032032 *
## version1:pattern2 0.15374 0.04127 3.725 0.000195 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) versn1 pttrn1 pttrn2 vrs1:1
## version1 -0.127
## pattern1 0.128 -0.153
## pattern2 0.024 -0.022 -0.114
## vrsn1:pttr1 -0.144 0.136 -0.246 0.093
## vrsn1:pttr2 -0.020 0.025 0.093 -0.232 -0.114
# Predict random slopes with difference in importance rating
glmer.ASScore.Exp1.Importance <- glmer(option.answer.av ~ version*pattern*cor.Ranking+(1+version|ID)+(1+version|scenario),
data = GLMER.data.predictors.Exp1, family = binomial,
control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
summary(glmer.ASScore.Exp1.Importance)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula:
## option.answer.av ~ version * pattern * cor.Ranking + (1 + version |
## ID) + (1 + version | scenario)
## Data: GLMER.data.predictors.Exp1
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 1959.6 2058.7 -961.8 1923.6 1800
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.6724 -0.5651 -0.3116 0.6577 4.3367
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.16119 0.4015
## version1 0.14669 0.3830 -0.23
## scenario (Intercept) 0.04197 0.2049
## version1 0.08137 0.2853 -0.10
## Number of obs: 1818, groups: ID, 303; scenario, 6
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.687208 0.131804 -5.214 1.85e-07 ***
## version1 0.772342 0.152986 5.048 4.45e-07 ***
## pattern1 -0.074936 0.102451 -0.731 0.46452
## pattern2 0.009387 0.057419 0.163 0.87014
## cor.Ranking 0.131818 0.143702 0.917 0.35898
## version1:pattern1 0.264560 0.102501 2.581 0.00985 **
## version1:pattern2 0.120033 0.057478 2.088 0.03677 *
## version1:cor.Ranking 0.263594 0.137731 1.914 0.05564 .
## pattern1:cor.Ranking -1.416393 0.145103 -9.761 < 2e-16 ***
## pattern2:cor.Ranking 0.021112 0.076740 0.275 0.78323
## version1:pattern1:cor.Ranking -0.203217 0.145258 -1.399 0.16181
## version1:pattern2:cor.Ranking 0.013611 0.076920 0.177 0.85954
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) versn1 pttrn1 pttrn2 cr.Rnk vrs1:1 vrs1:2 vr1:.R pt1:.R
## version1 -0.140
## pattern1 0.041 -0.024
## pattern2 -0.015 -0.034 -0.009
## cor.Ranking -0.538 0.029 0.040 0.050
## vrsn1:pttr1 -0.027 0.031 -0.108 0.003 -0.057
## vrsn1:pttr2 -0.037 -0.010 0.003 -0.174 0.021 -0.007
## vrsn1:cr.Rn 0.039 -0.441 -0.058 0.027 -0.146 0.051 0.047
## pttrn1:cr.R 0.054 -0.058 -0.628 -0.038 0.002 0.001 0.014 -0.068
## pttrn2:cr.R 0.019 0.033 -0.036 -0.674 -0.078 0.042 0.101 -0.033 -0.013
## vrsn1:p1:.R -0.066 0.049 0.001 0.013 -0.066 -0.629 -0.040 -0.003 -0.063
## vrsn1:p2:.R 0.035 0.013 0.042 0.100 -0.025 -0.038 -0.675 -0.077 0.063
## pt2:.R v1:1:.
## version1
## pattern1
## pattern2
## cor.Ranking
## vrsn1:pttr1
## vrsn1:pttr2
## vrsn1:cr.Rn
## pttrn1:cr.R
## pttrn2:cr.R
## vrsn1:p1:.R 0.063
## vrsn1:p2:.R -0.181 -0.010
# Comparison of the two models
anova(glmer.ASScore.Exp1.Pattern, glmer.ASScore.Exp1.Importance)
Both, cue pattern and the match between intended and rated cue ordering explain some of the variability between subjects and scenarios.
As a first step, we will take a look at the demographic characteristics of the sample in Experiment 2.
# Age of subjects
demo.Exp2 %>%
summarise(mean.age = mean(age),
sd.age = sd(age),
min.age = min(age),
max.age = max(age))
# Gender of subjects
demo.Exp2 %>%
group_by(sex) %>%
summarise(n.sex = n()) %>%
ungroup() %>%
mutate(percent.sex = n.sex/sum(n.sex))
# Job of subjects
demo.Exp2 %>%
group_by(job) %>%
summarise(n.job = n()) %>%
ungroup() %>%
mutate(percent.job = n.job/sum(n.job))
We pre-registered an exclusion criterion based on a recognition test, in which subjects had to recognize six of the semantic scenarios and identify six distractor scenarios. We pre-registered that all subjects that answered more than two questions in this recognition test incorrectly, will be excluded from further analyses.
# Create data frame for recognition test data
recognitionTest.Exp2 <- data.Exp2 %>%
# select only recognition test data
filter(data == "recognition.data") %>%
select(ID, list.position:correctness) %>%
group_by(ID, item.type, correctness) %>%
# summarise number of (in)correct answers per person and per tragets/distractors
summarise(n.answers = n())
Looking at the recognition test data, it is apparent that a programming mistake occured, such that sometimes seven targets and five distractors were displayed instead of six of each group.
# Identify subjects that 7 targets instead of 6
recognition7targets.Exp2 <- recognitionTest.Exp2 %>%
group_by(ID, item.type) %>%
# calculate number of items per targets and distractors
summarise(n.items = sum(n.answers)) %>%
ungroup() %>%
# identify subjects that saw too many targets
mutate(tooManyTargets = ifelse(n.items == 7 | n.items == 5, "yes", "no")) %>%
select(-item.type, -n.items) %>%
distinct(ID, tooManyTargets) %>%
# keep only subjects that saw too many targets
filter(tooManyTargets == "yes") %>%
droplevels() %>%
# create a vector of IDs of subjects that saw too many targets
.$ID
# Number of subjects with 7 targets
length(recognition7targets.Exp2)
## [1] 138
138 of 297 subjects saw too many targets. Next up, we test whether this influenced their performance in the recognition test.
# Performance of subjects that saw 7 vs. 6 targets
performanceRecognitionExp2 <- recognitionTest.Exp2 %>%
# create identifying variable
mutate(sevenTargets = ifelse(ID %in% recognition7targets.Exp2, "yes", "no")) %>%
group_by(sevenTargets, ID, correctness) %>%
# calculate number of correct and incorrect answers
summarise(n.correct = sum(n.answers)) %>%
filter(correctness == "correct") %>%
# calculate performance per participant in percent
mutate(percent.correct = n.correct/12)
# Performance difference between 7 vs. 6 targets?
t.test(percent.correct ~ sevenTargets, data = performanceRecognitionExp2)
##
## Welch Two Sample t-test
##
## data: percent.correct by sevenTargets
## t = 0.73322, df = 284.41, p-value = 0.464
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.01535437 0.03358425
## sample estimates:
## mean in group no mean in group yes
## 0.9559748 0.9468599
As there is no difference in performance, we will still exclude subjects based on their recognition test answers.
# Create vector of IDs that will be excluded based on the recognition test performance
excludedIDs.Exp2 <- data.Exp2 %>%
# filter recognition test data
filter(data == "recognition.data") %>%
select(ID, list.position:correctness) %>%
group_by(ID, correctness) %>%
# calculate number of correct/incorrect answers per ID
summarise(n.answers = n()) %>%
# filter subjects with more than 2 incorrect answers
filter(correctness == "incorrect" & n.answers > 2) %>%
# create vector of to be excluded IDs
.$ID
# Exclude IDs from demographic data
demo.final.Exp2 <- demo.Exp2 %>%
filter(ID %w/o% excludedIDs.Exp2) %>%
droplevels()
# Exclude IDs from task data
data.final.Exp2 <- data.Exp2 %>%
filter(ID %w/o% excludedIDs.Exp2) %>%
droplevels()
Now, we will take a look at the demographic data without the excluded subjects.
# Age of subjects
demo.final.Exp2 %>%
summarise(mean.age = mean(age),
sd.age = sd(age),
min.age = min(age),
max.age = max(age))
# Gender of subjects
demo.final.Exp2 %>%
group_by(sex) %>%
summarise(n.sex = n()) %>%
ungroup() %>%
mutate(percent.sex = n.sex/sum(n.sex))
# Job of subjects
demo.final.Exp2 %>%
group_by(job) %>%
summarise(n.job = n()) %>%
ungroup() %>%
mutate(percent.job = n.job/sum(n.job))
For testing our hypothesis, the first relevant analysis step is to calculate the Attraction Search Score. In general the Attraction Search Score is the difference of the probability of searching for one option, given that this option is attractive, minus the probability of searching for the same option, given that this option is not attractive. Thus, a key experimental manipulation is the attractiveness of the options.
The attractiveness of the options in this experiment was manipulated by the valence of the first opened cue: if it is positive, then this option is attractive, if it is negative, then this option is unattractive. Thus, the Attraction Search Score is calculated as the probability of switching the direction of information search to the other option than the option of the first search, given the first search yielded negative evidence, minus the probability of switching the direction of information search to the other option, given the first search yielded positive evidence, \(AS\ Score= p(Switching\ options\ |\ negative\ initial\ evidence) - p(Switching\ options\ |\ positive\ initial\ evidence)\). As a first step, we created a data frame which contains the Attraction Search Score.
# Calculating the AS-Score for every participant
ASScore.Exp2 <- data.final.Exp2 %>%
# filter only data from choice task
filter(data == "choice.data") %>%
select(ID, opened.cue.1, opened.cue.2, first.search.valence) %>%
# create vectors for calculating AS-Score
mutate(first.search.option = ifelse(grepl("A",opened.cue.1), "OptionA", "OptionB"),
second.search.option = ifelse(grepl("A",opened.cue.2), "OptionA", "OptionB"),
first.search.valence = recode(first.search.valence, `1`= "positive", `-1` = "negative")) %>%
# create variable that codes whether the searched for option was switched in the second search
mutate(switching = ifelse((first.search.option == "OptionA" & second.search.option == "OptionA") |
(first.search.option == "OptionB" & second.search.option == "OptionB"),
"no.switch", "switch")) %>%
group_by(ID, switching, first.search.valence) %>%
# calculate number of switches per participant and per positive/negative initial evidence
summarise(n.switches = n()) %>%
ungroup() %>%
# fill in 0 if searched option was not switched for negative/positive inital evidence
complete(ID, switching, first.search.valence, fill = list(n.switches = 0)) %>%
group_by(ID, first.search.valence) %>%
# calculate percentage of trials in which options were switched
mutate(percent.switches = n.switches/sum(n.switches)) %>%
# keep only probabilities for switching
filter(switching == "switch") %>%
select(ID, first.search.valence, percent.switches) %>%
spread(first.search.valence, percent.switches) %>%
# substract probability for switching given negative evidence from probability for switching given positive evidence
mutate(ASScore = negative - positive)
To test the hypothesis, that subjects show behavior consistent with the Attraction Search Effect, we run a one-sided, one-sample t-test against zero with the Attraction Search Score as dependent variable, as a positive Attraction Search Score indicates behavior consistent with the Attraction Search Effect.
# One-sided, one-sample t test against zero
t.test(ASScore.Exp2$ASScore, mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.Exp2$ASScore
## t = 6.8231, df = 279, p-value = 2.766e-11
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.09070444 Inf
## sample estimates:
## mean of x
## 0.1196429
# Cohen's d
ES.ASScore.Exp2 <- mean(ASScore.Exp2$ASScore)/sd(ASScore.Exp2$ASScore)
print(ES.ASScore.Exp2)
## [1] 0.4077601
As in Experiment 1, we want to test whether the Attraction Search Effect also exists in every content scenario. For this purpose, we calculate the Attraction Search Score across individuals and cue patterns for each decision context. As there are no repetitions of scenarios, this analysis results in only one Attraction Search Score per scenario and, thus, does not allow statistical significance tests. We will take a closer look at the between-decision context heterogeneity with a mixed logistic regression analysis with crossed-random effects for subjects and scenarios.
# Calculating the AS-Score for every participant
ASScore.Scenarios.Exp2 <- data.final.Exp2 %>%
# filter only data from choice task
filter(data == "choice.data") %>%
select(OptionA, opened.cue.1, opened.cue.2, first.search.valence) %>%
# create vectors for calculating AS-Score
mutate(first.search.option = ifelse(grepl("A",opened.cue.1), "OptionA", "OptionB"),
second.search.option = ifelse(grepl("A",opened.cue.2), "OptionA", "OptionB"),
first.search.valence = recode(first.search.valence, `1`= "positive", `-1` = "negative")) %>%
# create variable that codes whether the searched for option was switched in the second search
mutate(switching = ifelse((first.search.option == "OptionA" & second.search.option == "OptionA") |
(first.search.option == "OptionB" & second.search.option == "OptionB"),
"no.switch", "switch")) %>%
group_by(OptionA, switching, first.search.valence) %>%
# calculate number of switches per participant and per positive/negative initial evidence
summarise(n.switches = n()) %>%
ungroup() %>%
# fill in 0 if searched option was not switched for negative/positive inital evidence
complete(OptionA, switching, first.search.valence, fill = list(n.switches = 0)) %>%
group_by(OptionA, first.search.valence) %>%
# calculate percentage of trials in which options were switched
mutate(percent.switches = n.switches/sum(n.switches)) %>%
# keep only probabilities for switching
filter(switching == "switch") %>%
select(OptionA, first.search.valence, percent.switches) %>%
spread(first.search.valence, percent.switches) %>%
# substract probability for switching given negative evidence from probability for switching given positive evidence
mutate(ASScore = negative - positive)
# Create table of means and standard deviations of importance ratings
kable(ASScore.Scenarios.Exp2, format = "html", padding = 2) %>%
kable_styling(bootstrap_options = "striped", font_size = 10)
OptionA | negative | positive | ASScore |
---|---|---|---|
appartment_A | 0.8424242 | 0.7304348 | 0.1119895 |
cellcontract_A | 0.8611111 | 0.8014706 | 0.0596405 |
city_A | 0.8359375 | 0.7434211 | 0.0925164 |
computer_A | 0.8484848 | 0.7837838 | 0.0647011 |
granola_A | 0.8275862 | 0.7111111 | 0.1164751 |
gym_A | 0.9347826 | 0.7183099 | 0.2164727 |
hairsalon_A | 0.8992248 | 0.7350993 | 0.1641255 |
hotel_A | 0.8671329 | 0.6861314 | 0.1810015 |
insurance_A | 0.8698630 | 0.7537313 | 0.1161317 |
job_A | 0.8617886 | 0.6751592 | 0.1866294 |
pizza_A | 0.8630137 | 0.7985075 | 0.0645062 |
weather_A | 0.8865248 | 0.8273381 | 0.0591867 |
Closer inspection of the individual Attraction Search Scores revealed that quite a large number of subjects have an Attraction Search Score of zero.
# Median of Attraction Search Score
median(ASScore.Exp2$ASScore)
## [1] 0
# Number of subjects with an Attraction Search Score of zero
length(which(ASScore.Exp2$ASScore==0))
## [1] 124
First of, we will take a look at differences between subjects with an Attraction Search Score of zero and subjects with a non-zero Attraction Search Score.
### Data frame for reaction time differences
reactionTime.Exp2 <- data.final.Exp2 %>%
# keep only choice data
filter(data == "choice.data") %>%
select(ID, first.search.time, second.search.time, time.in.trial) %>%
group_by(ID) %>%
# calculate means and SDs for second searchtime and time in trial
summarise(median.first.searchtime = median(first.search.time),
sd.first.searchtime = sd(first.search.time),
median.second.searchtime = median(second.search.time),
sd.second.searchtime = sd(second.search.time),
median.trialtime = median(time.in.trial),
sd.trialtime = sd(time.in.trial)) %>%
# combine with AS-Score data
left_join(., ASScore.Exp2, by="ID") %>%
# create variable that indicates AS-Scores of zero
mutate(ASScoreZero = ifelse(ASScore == 0, "zero", "non-zero"))
# Difference in first search time?
t.test(median.first.searchtime ~ ASScoreZero, data = reactionTime.Exp2)
##
## Welch Two Sample t-test
##
## data: median.first.searchtime by ASScoreZero
## t = 5.2937, df = 274.49, p-value = 2.457e-07
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 288.5735 630.2770
## sample estimates:
## mean in group non-zero mean in group zero
## 1485.712 1026.286
# Difference in second search time?
t.test(median.second.searchtime ~ ASScoreZero, data = reactionTime.Exp2)
##
## Welch Two Sample t-test
##
## data: median.second.searchtime by ASScoreZero
## t = -1.3312, df = 211.31, p-value = 0.1846
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -474.73636 92.01014
## sample estimates:
## mean in group non-zero mean in group zero
## 2567.782 2759.145
# Difference in time in trial?
t.test(median.trialtime ~ ASScoreZero, data = reactionTime.Exp2)
##
## Welch Two Sample t-test
##
## data: median.trialtime by ASScoreZero
## t = -0.68517, df = 245.65, p-value = 0.4939
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -4323.068 2091.648
## sample estimates:
## mean in group non-zero mean in group zero
## 30641.80 31757.51
## Correlation of Attraction Search Score with search times
# First search time
cor.test(reactionTime.Exp2$median.first.searchtime, reactionTime.Exp2$ASScore)
##
## Pearson's product-moment correlation
##
## data: reactionTime.Exp2$median.first.searchtime and reactionTime.Exp2$ASScore
## t = 6.0432, df = 278, p-value = 4.844e-09
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.2328317 0.4403839
## sample estimates:
## cor
## 0.340753
# Second search time
cor.test(reactionTime.Exp2$median.second.searchtime, reactionTime.Exp2$ASScore)
##
## Pearson's product-moment correlation
##
## data: reactionTime.Exp2$median.second.searchtime and reactionTime.Exp2$ASScore
## t = -0.38828, df = 278, p-value = 0.6981
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.14012044 0.09419712
## sample estimates:
## cor
## -0.02328139
# Time in trial
cor.test(reactionTime.Exp2$median.trialtime, reactionTime.Exp2$ASScore)
##
## Pearson's product-moment correlation
##
## data: reactionTime.Exp2$median.trialtime and reactionTime.Exp2$ASScore
## t = 1.0938, df = 278, p-value = 0.275
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.05215926 0.18129271
## sample estimates:
## cor
## 0.06546244
### Data frame for difference in average search time
averageSearchTime.Exp2 <- data.final.Exp2 %>%
# select only choice data
filter(data == "choice.data") %>%
select(ID, first.search.time:seventh.search.time, pseudo.eigth.search.time) %>%
# create long data format for search time data
gather(number.search, search.time, -ID) %>%
arrange(ID) %>%
group_by(ID, number.search) %>%
# calculate mean and SD of all search times per participant
summarise(mean.searchtime = mean(search.time, na.rm = TRUE),
sd.searchtime = sd(search.time, na.rm = TRUE)) %>%
# combine with AS-Score data
left_join(., ASScore.Exp2, by="ID") %>%
# create variable that indicates AS-Scores of zero
mutate(ASScoreZero = ifelse(ASScore == 0, "zero", "non-zero"))
# Difference in overall average search time?
t.test(mean.searchtime ~ ASScoreZero, data = averageSearchTime.Exp2)
##
## Welch Two Sample t-test
##
## data: mean.searchtime by ASScoreZero
## t = 0.15185, df = 1811.3, p-value = 0.8793
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -244.9218 286.0295
## sample estimates:
## mean in group non-zero mean in group zero
## 3828.125 3807.571
cor.test(averageSearchTime.Exp2$mean.searchtime, averageSearchTime.Exp2$ASScore)
##
## Pearson's product-moment correlation
##
## data: averageSearchTime.Exp2$mean.searchtime and averageSearchTime.Exp2$ASScore
## t = 0.14261, df = 1896, p-value = 0.8866
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.04172455 0.04826156
## sample estimates:
## cor
## 0.003275137
### Data frame for difference in instruction check answers
instructionCheck.Exp2 <- data.final.Exp2 %>%
# select only instruction check data
filter(data == "instruction.check.data") %>%
group_by(ID) %>%
# select last repetition of instruction check for each participant
filter(row_number()==n()) %>%
# combine with AS-Score data
left_join(., ASScore.Exp2, by="ID") %>%
# create variable that indicates AS-Scores of zero
mutate(ASScoreZero = ifelse(ASScore == 0, "zero", "non-zero"))
# Difference in number of repetitions of instruction check?
t.test(attempt ~ ASScoreZero, data = instructionCheck.Exp2)
##
## Welch Two Sample t-test
##
## data: attempt by ASScoreZero
## t = -0.83465, df = 201.31, p-value = 0.4049
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.17034706 0.06902365
## sample estimates:
## mean in group non-zero mean in group zero
## 1.102564 1.153226
### Data frame for difference in recognition test performance
# combine recognition test data with AS-Score data
recognitionPerformance.Exp2<- left_join(performanceRecognitionExp2, ASScore.Exp2, by="ID") %>%
filter(!is.na(negative)) %>%
# create variable that indicates AS-Scores of zero
mutate(ASScoreZero = ifelse(ASScore == 0, "zero", "non-zero"))
## Warning: Column `ID` joining factors with different levels, coercing to
## character vector
# Difference in number of recognition test performance?
t.test(percent.correct ~ ASScoreZero, data = recognitionPerformance.Exp2)
##
## Welch Two Sample t-test
##
## data: percent.correct by ASScoreZero
## t = -0.6056, df = 266.8, p-value = 0.5453
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.013552176 0.007176384
## sample estimates:
## mean in group non-zero mean in group zero
## 0.9732906 0.9764785
### Data frame for number of searches
numberSearches.Exp2 <- data.final.Exp2 %>%
# select only choice data
filter(data == "choice.data") %>%
select(ID, opened.cue.1:cuesLeft2Search) %>%
# create trial variable
mutate(trial = rep(1:12, nrow(ASScore.Exp2))) %>%
# create long format for searched cue value data
gather(number.searched, searched.cv, -ID, -cuesLeft2Search, -trial) %>%
arrange(ID, trial) %>%
select(-number.searched)%>%
group_by(ID, trial) %>%
# calculate number of searches
summarise(cuesLeft2Search = mean(cuesLeft2Search),
n.searches = sum(!is.na(searched.cv)))
### Data frame for difference in average number of searches
avg.numberSearches.Exp2 <- numberSearches.Exp2%>%
group_by(ID) %>%
# calculate mean number of searches and sum of unsearched cues per participant
summarise(mean.n.searches = mean(n.searches),
cuesLeft = sum(cuesLeft2Search)) %>%
# combine with AS-Score data
left_join(., ASScore.Exp2, by="ID") %>%
# create variable that indicates AS-Scores of zero
mutate(ASScoreZero = ifelse(ASScore == 0, "zero", "non-zero"))
# Difference in number of searches?
t.test(mean.n.searches ~ ASScoreZero, data = avg.numberSearches.Exp2)
##
## Welch Two Sample t-test
##
## data: mean.n.searches by ASScoreZero
## t = -2.6086, df = 277.09, p-value = 0.009586
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.26184359 -0.03661243
## sample estimates:
## mean in group non-zero mean in group zero
## 4.567842 4.717070
# Calculate Hedge's g
cohen.d(mean.n.searches ~ ASScoreZero, data = avg.numberSearches.Exp2, hedges.correction=TRUE)
##
## Hedges's g
##
## g estimate: -0.30307 (small)
## 95 percent confidence interval:
## lower upper
## -0.54124470 -0.06489539
# How many subjects with an Attraction Search Score of zero searched for all possible information?
avg.numberSearches.Exp2 %>%
# create variable indicating whether all possible cue values have been searched
mutate(search.all = ifelse(cuesLeft==0, "yes", "no")) %>%
select(ID, search.all, ASScoreZero) %>%
group_by(ASScoreZero, search.all) %>%
# calculate number of subjects that searched all possible information for AS-Scores = 0/AS-Scores != 0
summarise(n = n()) %>%
group_by(ASScoreZero) %>%
# calculate percent of subjects that searched all information for AS-Scores = 0/AS-Scores != 0
mutate(percent = n/sum(n))
One possible explanation for an Attraction Search Score of zero is that subjects used predetermined, fixed search strategies. We defined three possible search strategies: cue-wise, lenient cue-wise, and option-wise. As we do not know the subjective validity ordering for each participant, cue-wise search was defined as always searching for information on the same cue consecutively and always starting search for a new cue on the same option side. Lenient cue-wise search is defined similarily to cue-wise search but allows for starting search for a new cue on both options. Option-wise search is defined as searching first all information on one option and then all information on the other option.
### Classifying trials as cue-wise (cw), lenient cue-wise (lcw), and option-wise (ow) search
# Preparation of data frame for strategy classification
strategies.Exp2 <- data.final.Exp2 %>%
# select only choice data
filter(data == "choice.data") %>%
select(ID, opened.cue.1:opened.cue.7) %>%
# create varibles with number of searches and individual trials
mutate(n.searches = numberSearches.Exp2$n.searches,
trial = rep(1:12, nrow(ASScore.Exp2))) %>%
# tranform data in long format for searched for cue values
gather(num.search, searched.cv, -ID, -n.searches, -trial) %>%
arrange(ID, trial) %>%
filter(!is.na(searched.cv)) %>%
# create variables for searched option and searched for cue value
mutate(searched.option = ifelse(grepl("A",searched.cv),"OptionA", "OptionB"),
searched.cue = substring(searched.cv, 1, 4),
strategy = NA)
# Loop classifying trials into cue-wise/lenient cue-wise/option-wise/non-classified search strategies
for(n in unique(strategies.Exp2$ID)) { # loop over subjects
for(t in 1:12) { # loop over trials
# Preparation: extract relevant trial data
n.searches <- strategies.Exp2$n.searches[strategies.Exp2$ID == n & strategies.Exp2$trial == t][1]
searched.options <- strategies.Exp2$searched.option[strategies.Exp2$ID == n & strategies.Exp2$trial == t]
searched.cues <- strategies.Exp2$searched.cue[strategies.Exp2$ID == n & strategies.Exp2$trial == t]
searched.cuevalues <- strategies.Exp2$searched.cv[strategies.Exp2$ID == n & strategies.Exp2$trial == t]
current.strategy <- 0
# cue-wise classification
if(all(duplicated(searched.cues)[seq(2,n.searches,2)])){ # always two consecutives cues are equal?
# tests whether odd options/even options are always equal
if(n_distinct(searched.options[seq(1,n.searches,2)]) == 1 & n_distinct(searched.options[seq(2,n.searches,2)]) == 1){
current.strategy <- "cw"
} else {
current.strategy <- "lcw"
}
}
# option-wise classification
if(n.searches <= 4) {
if(n_distinct(searched.options) == 1){ # less than 4 searches and only for one option?
current.strategy <- "ow"
}
} else {
# tests whether first 4 searches are all for one option and remaining searches are all for other option
if(n_distinct(searched.options[1:4]) == 1 & n_distinct(searched.options[5:n.searches])) {
current.strategy <- "ow"
}
}
# Non classified subjects
if(current.strategy == 0){ # no strategy assigned yet?
current.strategy <- "not.classified"
}
# save results in strategies.Exp2 data frame
strategies.Exp2$strategy[strategies.Exp2$ID == n & strategies.Exp2$trial == t] <- rep(current.strategy, n.searches)
}
}
To test whether pre-determined search strategies can explain the overall lower Attraction Search Scores, we correlate the individual number of trials belonging to one of the four strategies with the individual Attraction Search Scores.
# Create data frame with number of trials belonging to each strategy per person
n.strategies.Exp2 <- strategies.Exp2 %>%
# select one row per trial per participant
filter(num.search == "opened.cue.1") %>%
group_by(ID, strategy) %>%
# calculate number of trials belonging to each strategy per person
summarise(n.strategies = n()) %>%
ungroup() %>%
# fill in 0 if a strategy was not used by subjects
complete(ID, strategy, fill = list(n.strategies=0)) %>%
# calculate percent of trials following each strategy per participant
mutate(percent.strategies = n.strategies/12) %>%
# combine with AS-Score data
left_join(., ASScore.Exp2, by = "ID") %>%
# change labels of strategy vector
mutate(strategy = factor(strategy, levels=c("cw", "lcw", "ow", "not.classified"),
labels = c("cue-wise", "lenient cue-wise", "option-wise", "not classified")))
# Average number of strategies over all subjects
n.strategies.Exp2 %>%
group_by(strategy) %>%
summarise(mean.strategy = mean(percent.strategies),
sd.strategy = sd(percent.strategies))
# Correlation of AS-Score with individual number of strictly cue-wise trials
cor.test(n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy=="cue-wise"], n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy=="cue-wise"])
##
## Pearson's product-moment correlation
##
## data: n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy == and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "cue-wise"] "cue-wise"] and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "cue-wise"]
## t = -5.442, df = 278, p-value = 1.157e-07
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.4125010 -0.2003485
## sample estimates:
## cor
## -0.3102829
# Correlation of AS-Score with individual number of lenient cue-wise trials
cor.test(n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy=="lenient cue-wise"], n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy=="lenient cue-wise"])
##
## Pearson's product-moment correlation
##
## data: n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy == and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "lenient cue-wise"] "lenient cue-wise"] and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "lenient cue-wise"]
## t = -2.6881, df = 278, p-value = 0.007619
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.27132635 -0.04274332
## sample estimates:
## cor
## -0.1591673
# Correlation of AS-Score with individual number of option-wise trials
cor.test(n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy=="option-wise"], n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy=="option-wise"])
##
## Pearson's product-moment correlation
##
## data: n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy == and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "option-wise"] "option-wise"] and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "option-wise"]
## t = 4.8816, df = 278, p-value = 1.776e-06
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.1693423 0.3855097
## sample estimates:
## cor
## 0.2809861
# Correlation of AS-Score with individual number of non-classified trials
cor.test(n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy=="not classified"], n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy=="not classified"])
##
## Pearson's product-moment correlation
##
## data: n.strategies.Exp2$n.strategies[n.strategies.Exp2$strategy == and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "not classified"] "not classified"] and n.strategies.Exp2$ASScore[n.strategies.Exp2$strategy == "not classified"]
## t = 4.925, df = 278, p-value = 1.45e-06
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.1717619 0.3876294
## sample estimates:
## cor
## 0.2832798
As in Experiment 1, we also ran a trial-level generalized linear mixed model, with switching options for the second search vs. not switching options for the second search as dependent variable, a random intercepts and slopes for subjects and scenarios, and the valence of the first uncovered cue value as predictor.
# Create dataframe for generalized linear mixed model analysis
GLMER.data.Exp2 <- data.final.Exp2 %>%
# select only choice data
filter(data == "choice.data") %>%
select(ID, opened.cue.1, opened.cue.2, first.search.valence, OptionA) %>%
# create relevant variables for determining switching
mutate(first.search.option = ifelse(grepl("A",opened.cue.1), "OptionA", "OptionB"),
second.search.option = ifelse(grepl("A",opened.cue.2), "OptionA", "OptionB"),
first.search.valence = recode(first.search.valence, `1`= "positive", `-1` = "negative")) %>%
# create variable for switching
mutate(switching = ifelse((first.search.option == "OptionA" & second.search.option == "OptionA") |
(first.search.option == "OptionB" & second.search.option == "OptionB"),
"no.switch", "switch")) %>%
select(ID, first.search.valence, switching, OptionA) %>%
# create "decisions" variable
mutate(decision.context = as.factor(paste(first.search.valence, OptionA, sep = "."))) %>%
# create variables for logistic multilevel regression
mutate(switching.av = ifelse(switching == "switch", 0, 1),
valence = factor(first.search.valence, levels=c("positive", "negative")),
trial = rep(1:12, n_distinct(ASScore.Exp2$ID)),
scenario = as.factor(OptionA))
# Assign effect-coded contrast to valence predictor
contrasts(GLMER.data.Exp2$valence) <- contr.sum(2)
contrasts(GLMER.data.Exp2$valence)
## [,1]
## positive 1
## negative -1
# Full model
glmer.ASScore.Exp2.full <- glmer(switching.av ~ valence+(1 + valence|ID) + (1 + valence|scenario),
data = GLMER.data.Exp2, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
## singular fit
summary(glmer.ASScore.Exp2.full)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence + (1 + valence | ID) + (1 + valence |
## scenario)
## Data: GLMER.data.Exp2
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 2723.1 2772.1 -1353.6 2707.1 3352
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.3021 -0.3806 -0.2024 -0.1639 3.3610
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 3.13935 1.7718
## valence1 0.60804 0.7798 0.41
## scenario (Intercept) 0.01607 0.1268
## valence1 0.01105 0.1051 1.00
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.2909 0.1489 -15.381 < 2e-16 ***
## valence1 0.3704 0.1105 3.352 0.000802 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## valence1 0.107
## convergence code: 0
## singular fit
# Modelfit is singular: reduce random effects structure
### 1st: remove correlations of random slopes and random intercepts
glmer.ASScore.Exp2.noCorrID <- glmer(switching.av ~ valence+(1 + valence||ID) + (1 + valence|scenario),
data = GLMER.data.Exp2, family = binomial)
## singular fit
summary(glmer.ASScore.Exp2.noCorrID)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence + (1 + valence || ID) + (1 + valence |
## scenario)
## Data: GLMER.data.Exp2
##
## AIC BIC logLik deviance df.resid
## 2725.1 2780.2 -1353.6 2707.1 3351
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.3021 -0.3806 -0.2024 -0.1639 3.3610
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 1.10363 1.0505
## ID.1 valencepositive 3.76327 1.9399
## valencenegative 1.52425 1.2346 0.60
## scenario (Intercept) 0.01607 0.1268
## valence1 0.01105 0.1051 1.00
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.2909 0.1489 -15.381 < 2e-16 ***
## valence1 0.3704 0.1105 3.352 0.000802 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## valence1 0.107
## convergence code: 0
## singular fit
# singular fit
glmer.ASScore.Exp2.noCorrScenario <- glmer(switching.av ~ valence+(1 + valence|ID) + (1 + valence||scenario),
data = GLMER.data.Exp2, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
## singular fit
summary(glmer.ASScore.Exp2.noCorrScenario)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence + (1 + valence | ID) + (1 + valence ||
## scenario)
## Data: GLMER.data.Exp2
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 2725.1 2780.2 -1353.6 2707.1 3351
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.3021 -0.3806 -0.2024 -0.1639 3.3610
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 3.1393495 1.77182
## valence1 0.6080411 0.77977 0.41
## scenario (Intercept) 0.0000000 0.00000
## scenario.1 valencepositive 0.0537835 0.23191
## valencenegative 0.0004686 0.02165 1.00
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.2909 0.1489 -15.381 < 2e-16 ***
## valence1 0.3704 0.1105 3.352 0.000802 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## valence1 0.107
## convergence code: 0
## singular fit
# singular fit
glmer.ASScore.Exp2.noCorr <- glmer(switching.av ~ valence+(1 + valence||ID) + (1 + valence||scenario),
data = GLMER.data.Exp2, family = binomial)
## singular fit
summary(glmer.ASScore.Exp2.noCorr)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence + (1 + valence || ID) + (1 + valence ||
## scenario)
## Data: GLMER.data.Exp2
##
## AIC BIC logLik deviance df.resid
## 2727.1 2788.3 -1353.6 2707.1 3350
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.3021 -0.3806 -0.2024 -0.1639 3.3610
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.8943618 0.94571
## ID.1 valencepositive 3.9725387 1.99312
## valencenegative 1.7335193 1.31663 0.62
## scenario (Intercept) 0.0000000 0.00000
## scenario.1 valencepositive 0.0537835 0.23191
## valencenegative 0.0004686 0.02165 1.00
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.2909 0.1489 -15.381 < 2e-16 ***
## valence1 0.3704 0.1105 3.352 0.000802 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## valence1 0.107
## convergence code: 0
## singular fit
# singular fit
### 2nd: remove highest order effects with least variance (random slope for decision context)
glmer.ASScore.Exp2.rSID <- glmer(switching.av ~ valence+(1 + valence|ID) + (1|scenario),
data = GLMER.data.Exp2, family = binomial)
summary(glmer.ASScore.Exp2.rSID)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence + (1 + valence | ID) + (1 | scenario)
## Data: GLMER.data.Exp2
##
## AIC BIC logLik deviance df.resid
## 2720.7 2757.4 -1354.4 2708.7 3354
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.2860 -0.3876 -0.1991 -0.1622 3.5075
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 3.12372 1.7674
## valence1 0.59755 0.7730 0.40
## scenario (Intercept) 0.01484 0.1218
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.2865 0.1483 -15.42 < 2e-16 ***
## valence1 0.3793 0.1059 3.58 0.000344 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## valence1 0.029
# Final model for plots
glmer.ASScore.Exp2.final <- glmer.ASScore.Exp2.rSID
The significant, positive effect of valence on switching options, indicates that subjects are more likely to not switch options when the first piece of information they uncover is positive compared to negative. Nonetheless, there is quite some variance due to subjects. We try to explain this variance by adding the centered number of trials belonging to any strategy as predictor to the model.
# Data frame with count of trials with strategies
count.strategies.Exp2 <- n.strategies.Exp2 %>%
mutate(used.strategy = ifelse(strategy == "not classified", "no", "yes")) %>%
group_by(ID, used.strategy) %>%
summarise(count.strategies = sum(n.strategies)) %>%
filter(used.strategy == "yes") %>%
select(-used.strategy) %>%
ungroup() %>%
mutate(c.count.strategies = count.strategies - mean(count.strategies))
# Combine data frames
GLMER.strategy.data.Exp2 <- left_join(GLMER.data.Exp2, count.strategies.Exp2, by = c("ID"))
# Assign effect-coded contrast to valence predictor
contrasts(GLMER.strategy.data.Exp2$valence) <- contr.sum(2)
contrasts(GLMER.strategy.data.Exp2$valence)
## [,1]
## positive 1
## negative -1
### Mixed model with count data of used strategies
glmer.ASScore.Exp2.strategy <- glmer(switching.av ~ valence*c.count.strategies+(1 + valence|ID) + (1|scenario),
data = GLMER.strategy.data.Exp2, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
summary(glmer.ASScore.Exp2.strategy)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: switching.av ~ valence * c.count.strategies + (1 + valence |
## ID) + (1 | scenario)
## Data: GLMER.strategy.data.Exp2
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 2615.0 2664.0 -1299.5 2599.0 3352
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0509 -0.3775 -0.1954 -0.1239 4.0261
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 1.95542 1.3984
## valence1 0.58657 0.7659 0.26
## scenario (Intercept) 0.01374 0.1172
## Number of obs: 3360, groups: ID, 280; scenario, 12
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.32432 0.13266 -17.521 < 2e-16 ***
## valence1 0.38405 0.10573 3.632 0.000281 ***
## c.count.strategies -0.41312 0.04136 -9.989 < 2e-16 ***
## valence1:c.count.strategies -0.08565 0.03164 -2.707 0.006787 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) valnc1 c.cnt.
## valence1 -0.052
## c.cnt.strtg 0.327 -0.003
## vlnc1:c.cn. -0.010 0.483 0.122
The results of this model show that there is an interaction of the number of trials classified as belonging to a strategy with the valence of the first piece of opened information such that the less trials follow a strategy the stronger is the effect of the initial valence.
As a first step, we will take a look at the demographic characteristics of the sample in Experiment 3.
# Age of subjects
demo.Exp3 %>%
summarise(mean.age = mean(age),
sd.age = sd(age),
min.age = min(age),
max.age = max(age))
# Gender of subjects
demo.Exp3 %>%
group_by(sex) %>%
summarise(n.sex = n()) %>%
ungroup() %>%
mutate(percent.sex = n.sex/sum(n.sex))
We pre-registered an exclusion criterion based on the instruction check, in which subjects had to answer questions about the upcoming task correctly before continuing with the task. We pre-registered that all subjects, that had to repeat the instruction check 2 or more times, will be excluded from further analyses.
# Exclusion Criterion: 2 or more repetitions of instructions
excludedIDs.Exp3 <- data.Exp3 %>%
filter(!is.na(instrCheck.attempt)) %>%
# select subjects that hat to repeat instruction check 2 or more times
filter(instrCheck.attempt >= 2) %>%
# create vector with IDs
.$ID
# Exclude IDs from demographic data
demo.final.Exp3 <- demo.Exp3 %>%
filter(ID %w/o% excludedIDs.Exp3) %>%
droplevels()
# Exclude IDs from task data
data.final.Exp3 <- data.Exp3 %>%
filter(ID %w/o% excludedIDs.Exp3) %>%
droplevels()
Now, we will take a look at the demographic data information without the excluded subjects.
# Age of subjects
demo.final.Exp3 %>%
summarise(mean.age = mean(age),
sd.age = sd(age),
min.age = min(age),
max.age = max(age))
# Gender of subjects
demo.final.Exp3 %>%
group_by(sex) %>%
summarise(n.sex = n()) %>%
ungroup() %>%
mutate(percent.sex = n.sex/sum(n.sex))
# Language of subjects
demo.final.Exp3 %>%
group_by(english.level) %>%
summarise(n.language = n()) %>%
ungroup() %>%
mutate(percent.language = n.language/sum(n.language))
# Job of subjects
demo.final.Exp3 %>%
group_by(employment.status) %>%
summarise(n.job = n()) %>%
ungroup() %>%
mutate(percent.job = n.job/sum(n.job))
In Experiment 3, the attractiveness of the options is again manipulated via the version of the patterns: in Version a Option A is attractive, in Version b Option B is attractive (and, thus, Option A is unattractive). Thus, the Attraction Search Score is calculated as the probability of searching for information on Option A in Version a minus the probability of searching for Option A in Version b, \(AS\ Score= p(Searching\ for\ Option\ A\ |\ Version\ a) - p(Searching\ for\ Option\ A\ |\ Version\ b)\). As a first step, we create a data frame which contains the Attraction Search Score.
# Calculating the AS-Score for every participant
ASScore.Exp3 <- data.final.Exp3 %>%
# select data from choice task
filter(data == "choice.data" & phase == "task") %>%
select(ID, version, opened.cue) %>%
mutate(searched.option = ifelse(grepl("A",opened.cue),"OptionA", "OptionB"))%>%
select(-opened.cue) %>%
group_by(ID, version, searched.option) %>%
# calculate number of searches per version and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID,version,searched.option,fill = list(n.searches=0)) %>%
group_by(ID, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(searched.option == "OptionA") %>%
select(-searched.option, -n.searches) %>%
spread(version, percent.searches) %>%
select(ID, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching for Option A depending on Version
mutate(ASScore = VersionA - VersionB)
To test the hypothesis, that subjects show behavior consistent with the Attraction Search Effect, we run a one-sided, one-sample t-test against zero with the Attraction Search Score as dependent variable, as a positive Attraction Search Score indicates behavior consistent with the Attraction Search Effect.
# One-sided, one-sample t test against zero
t.test(ASScore.Exp3$ASScore, mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.Exp3$ASScore
## t = 7.9163, df = 88, p-value = 3.434e-12
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.2376926 Inf
## sample estimates:
## mean of x
## 0.3008739
# Cohen's d
ES.ASScore.Exp3 <- mean(ASScore.Exp3$ASScore)/sd(ASScore.Exp3$ASScore)
print(ES.ASScore.Exp3)
## [1] 0.8391213
The next analysis step is to test whether the Attraction Search Score is significant for the separate cue value patterns. In order to test this hypothesis, we need to calculate the Attraction Search Score on the level of patterns. It is important to note, that the three used cue patterns are described in the data by the number they had in the Jekel et al. (2018) paper - in the manuscript, we gave new numbers to the used cue value patterns. Pattern 5 in the Markdown is Pattern 1 in the manuscript, Pattern 6 is Pattern 2, and Pattern 7 is Pattern 3 in the Manuscript.
# Calculate Attraction Search Score per pattern
ASScore.pattern.Exp3 <- data.final.Exp3 %>%
# select choice task data
filter(data == "choice.data" & phase == "task") %>%
select(ID, pattern, version, opened.cue) %>%
mutate(searched.option = ifelse(grepl("A",opened.cue),"OptionA", "OptionB"))%>%
group_by(ID, pattern, version, searched.option) %>%
# calculate number of searches per pattern, version, and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID, pattern, version, searched.option, fill = list(n.searches=0)) %>%
group_by(ID, pattern, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(searched.option == "OptionA") %>%
select(-searched.option, -n.searches) %>%
spread(version, percent.searches) %>%
select(ID, pattern, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching for Option A depending on Version
mutate(ASScore = VersionA - VersionB)
To test the hypothesis, that subjects show behavior consistent with the Attraction Search Effect in each cue value pattern, we run a one-sided, one-sample t-test against zero with the Attraction Search Score as dependent variable for each pattern, as a positive Attraction Search Score indicates behavior consistent with the Attraction Search Effect.
# One-sided, one-sample t test against zero for Pattern 5
t.test(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 5], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 5]
## t = 5.4709, df = 88, p-value = 2.078e-07
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.12515 Inf
## sample estimates:
## mean of x
## 0.1797753
# Cohen's d for Pattern 5
ES.ASScore.pattern5.Exp3 <- mean(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 5])/sd(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 5])
print(ES.ASScore.pattern5.Exp3)
## [1] 0.5799158
# One-sided, one-sample t test against zero for Pattern 6
t.test(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 6], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 6]
## t = 6.8718, df = 88, p-value = 4.35e-10
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.2952866 Inf
## sample estimates:
## mean of x
## 0.3895131
# Cohen's d for Pattern 6
ES.ASScore.pattern6.Exp3 <- mean(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 6])/sd(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 6])
print(ES.ASScore.pattern6.Exp3)
## [1] 0.7284127
# One-sided, one-sample t test against zero for Pattern 7
t.test(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 7], mu = 0, alternative = "greater")
##
## One Sample t-test
##
## data: ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 7]
## t = 6.2267, df = 88, p-value = 7.916e-09
## alternative hypothesis: true mean is greater than 0
## 95 percent confidence interval:
## 0.2443433 Inf
## sample estimates:
## mean of x
## 0.3333333
# Cohen's d for Pattern 7
ES.ASScore.pattern7.Exp3 <- mean(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 7])/sd(ASScore.pattern.Exp3$ASScore[ASScore.pattern.Exp3$pattern == 7])
print(ES.ASScore.pattern7.Exp3)
## [1] 0.660033
Lastly, we want to test whether the Attraction Search Effect also exists in every content scenario. For this purpose, we calculate the Attraction Search Score across individuals and cue patterns for each decision context. As there are no repetitions of scenarios, this analysis results in only one Attraction Search Score per scenario and, thus, does not allow statistical significance tests. We will take a closer look at the between-decision context heterogeneity with a mixed logistic regression analysis with crossed-random effects for subjects and scenarios.
# Calculating the AS-Score for every participant
ASScore.Scenarios.Exp3 <- data.final.Exp3 %>%
# select data from choice task
filter(data == "choice.data" & phase == "task") %>%
select(shop.item, version, opened.cue) %>%
mutate(searched.option = ifelse(grepl("A",opened.cue),"OptionA", "OptionB"))%>%
select(-opened.cue) %>%
group_by(shop.item, version, searched.option) %>%
# calculate number of searches per version and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(shop.item,version,searched.option,fill = list(n.searches=0)) %>%
group_by(shop.item, version) %>%
# calculate probability of search given version
mutate(percent.searches = n.searches/sum(n.searches)) %>%
# select only probabilities of searching for Option A
filter(searched.option == "OptionA") %>%
select(-searched.option, -n.searches) %>%
spread(version, percent.searches) %>%
select(shop.item, VersionA = a, VersionB = b) %>%
# Substract probabilities of searching for Option A depending on Version
mutate(ASScore = VersionA - VersionB)
# Create table of means and standard deviations of importance ratings
kable(ASScore.Scenarios.Exp3, format = "html", padding = 2) %>%
kable_styling(bootstrap_options = "striped", font_size = 10)
shop.item | VersionA | VersionB | ASScore |
---|---|---|---|
blazer_blue | 0.6111111 | 0.2285714 | 0.3825397 |
dress_black | 0.5581395 | 0.2173913 | 0.3407482 |
dress_floral | 0.4255319 | 0.2142857 | 0.2112462 |
dress_grey | 0.4761905 | 0.1276596 | 0.3485309 |
jacket_floral | 0.4468085 | 0.2142857 | 0.2325228 |
jacket_fur | 0.4285714 | 0.1702128 | 0.2583587 |
jacket_green | 0.5200000 | 0.2051282 | 0.3148718 |
jacket_grey | 0.5348837 | 0.1521739 | 0.3827098 |
jacket_jeans | 0.5853659 | 0.1875000 | 0.3978659 |
pullover_blue | 0.5952381 | 0.4468085 | 0.1484296 |
pullover_grey | 0.5348837 | 0.1956522 | 0.3392315 |
pullover_white | 0.4893617 | 0.1190476 | 0.3703141 |
shirt_red | 0.4090909 | 0.2000000 | 0.2090909 |
shirt_stripes | 0.6250000 | 0.2244898 | 0.4005102 |
shorts_jeans | 0.4042553 | 0.1428571 | 0.2613982 |
shorts_pink | 0.5000000 | 0.2325581 | 0.2674419 |
top_black | 0.4800000 | 0.1025641 | 0.3774359 |
top_white | 0.4848485 | 0.2678571 | 0.2169913 |
As in Experiments 1 and 2, we also ran a trial-level generalized linear mixed model, with searching for Option A vs. searching for Option B as the dependent variable, a random intercepts and slopes for subjects and scenarios, and pattern version as a Level 1 predictor.
# Create dataframe for generalized linear mixed model analysis
GLMER.data.Exp3 <- data.final.Exp3 %>%
# select only search data
filter(data == "choice.data" & phase == "task") %>%
select(ID, version, pattern, opened.cue, shop.item) %>%
mutate(searched.option = ifelse(grepl("A",opened.cue),"OptionA", "OptionB")) %>%
mutate(version = as.factor(version),
# recode DV for logistic multilevel regression
searched.option.av = recode(searched.option, OptionA = 1, OptionB = 0),
shop.item = as.factor(shop.item),
ID = as.factor(ID))
# Assign effect-coding contrast to version predictor
contrasts(GLMER.data.Exp3$version) <- contr.sum(2)
contrasts(GLMER.data.Exp3$version)
## [,1]
## a 1
## b -1
# Run generalized linear mixes model
glmer.ASScore.Exp3.full <- glmer(searched.option.av ~ version+(1 + version|ID)+(1 + version|shop.item),
data = GLMER.data.Exp3, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
## singular fit
summary(glmer.ASScore.Exp3.full)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula:
## searched.option.av ~ version + (1 + version | ID) + (1 + version |
## shop.item)
## Data: GLMER.data.Exp3
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 1850.8 1893.8 -917.4 1834.8 1594
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0588 -0.6001 -0.4207 0.7222 3.2438
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.104978 0.32400
## version1 0.625835 0.79110 0.66
## shop.item (Intercept) 0.048945 0.22123
## version1 0.003691 0.06076 -1.00
## Number of obs: 1602, groups: ID, 89; shop.item, 18
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.72768 0.09007 -8.079 6.52e-16 ***
## version1 0.76790 0.10723 7.161 8.01e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## version1 0.006
## convergence code: 0
## singular fit
# boundary (singular) fit
#
# due to singular fit, compare different random effect structures
### 1st: remove correlations
glmer.ASScore.Exp3.noCorrID <- glmer(searched.option.av ~ version+(1 + version||ID)+(1 + version|shop.item),
data = GLMER.data.Exp3, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
## singular fit
summary(glmer.ASScore.Exp3.noCorrID)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula:
## searched.option.av ~ version + (1 + version || ID) + (1 + version |
## shop.item)
## Data: GLMER.data.Exp3
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 1852.8 1901.2 -917.4 1834.8 1593
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0588 -0.6001 -0.4207 0.7222 3.2438
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.009460 0.09726
## ID.1 versiona 1.060749 1.02993
## versionb 0.381960 0.61803 -0.83
## shop.item (Intercept) 0.048945 0.22123
## version1 0.003691 0.06076 -1.00
## Number of obs: 1602, groups: ID, 89; shop.item, 18
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.72768 0.09007 -8.079 6.52e-16 ***
## version1 0.76790 0.10723 7.161 8.01e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## version1 0.006
## convergence code: 0
## singular fit
# singular fit
glmer.ASScore.Exp3.noCorrShopitem <- glmer(searched.option.av ~ version+(1 + version|ID)+(1 + version||shop.item),
data = GLMER.data.Exp3, family = binomial)
summary(glmer.ASScore.Exp3.noCorrShopitem)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula:
## searched.option.av ~ version + (1 + version | ID) + (1 + version ||
## shop.item)
## Data: GLMER.data.Exp3
##
## AIC BIC logLik deviance df.resid
## 1852.8 1901.2 -917.4 1834.8 1593
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0588 -0.6001 -0.4207 0.7222 3.2438
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 1.050e-01 0.3239990
## version1 6.258e-01 0.7910679 0.66
## shop.item (Intercept) 5.537e-08 0.0002353
## shop.item.1 versiona 2.576e-02 0.1604932
## versionb 7.950e-02 0.2819601 1.00
## Number of obs: 1602, groups: ID, 89; shop.item, 18
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.72768 0.09007 -8.079 6.52e-16 ***
## version1 0.76788 0.10723 7.161 8.01e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## version1 0.006
# fits, but due to perfect correlation between between random slope predictors for shop item compare with model without random slope for shop item
### 2nd: remove highest order effects with least variance (random slope for shop items)
glmer.ASScore.Exp3.rSID <- glmer(searched.option.av ~ version+(1 + version|ID)+(1|shop.item),
data = GLMER.data.Exp3, family = binomial)
summary(glmer.ASScore.Exp3.rSID)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula:
## searched.option.av ~ version + (1 + version | ID) + (1 | shop.item)
## Data: GLMER.data.Exp3
##
## AIC BIC logLik deviance df.resid
## 1847.4 1879.7 -917.7 1835.4 1596
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.0908 -0.6002 -0.4222 0.7195 3.2277
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.10849 0.3294
## version1 0.62965 0.7935 0.67
## shop.item (Intercept) 0.04672 0.2162
## Number of obs: 1602, groups: ID, 89; shop.item, 18
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.72151 0.08917 -8.091 5.91e-16 ***
## version1 0.76289 0.10622 7.183 6.84e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## version1 0.099
# Final model for plots
glmer.ASScore.Exp3.final <- glmer.ASScore.Exp3.rSID
The significant, positive effect of the predictor pattern version shows that subjects were more likely to search for Option A when presented with Version a as compared to Version b. To explain some of the variability, we ran a mixed logistic regression with the cue patterns as predictors.
# Create dataframe for generalized linear mixed model analysis
GLMER.data.predictor.Exp3 <- GLMER.data.Exp3 %>%
mutate(pattern = as.factor(pattern))
# Assign helmert-coding contrast to pattern predictor
contrasts(GLMER.data.predictor.Exp3$version) <- contr.sum(2)
contrasts(GLMER.data.predictor.Exp3$pattern) <- contr.helmert(3)
contrasts(GLMER.data.predictor.Exp3$pattern)
## [,1] [,2]
## 5 -1 -1
## 6 1 -1
## 7 0 2
# Does pattern interact with version?
glmer.ASScore.Exp3.rSIDPattern <- glmer(searched.option.av ~ version*pattern+(1 + version|ID)+(1|shop.item),
data = GLMER.data.predictor.Exp3, family = binomial, control=glmerControl(optimizer="bobyqa",optCtrl=list(maxfun=2e5)))
summary(glmer.ASScore.Exp3.rSIDPattern)
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: binomial ( logit )
## Formula: searched.option.av ~ version * pattern + (1 + version | ID) +
## (1 | shop.item)
## Data: GLMER.data.predictor.Exp3
## Control:
## glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
##
## AIC BIC logLik deviance df.resid
## 1591.7 1645.4 -785.8 1571.7 1592
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -3.6710 -0.5293 -0.2511 0.4963 7.5932
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID (Intercept) 0.31385 0.5602
## version1 1.10773 1.0525 0.71
## shop.item (Intercept) 0.07374 0.2715
## Number of obs: 1602, groups: ID, 89; shop.item, 18
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.87750 0.11885 -7.383 1.55e-13 ***
## version1 0.91071 0.13794 6.602 4.05e-11 ***
## pattern1 1.36108 0.10504 12.957 < 2e-16 ***
## pattern2 0.18479 0.04852 3.808 0.00014 ***
## version1:pattern1 0.17155 0.10444 1.643 0.10047
## version1:pattern2 -0.01055 0.04857 -0.217 0.82805
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) versn1 pttrn1 pttrn2 vrs1:1
## version1 0.159
## pattern1 -0.241 0.201
## pattern2 -0.146 0.088 0.289
## vrsn1:pttr1 0.227 -0.202 -0.151 -0.196
## vrsn1:pttr2 0.104 -0.125 -0.195 -0.134 0.291
Cue patterns in Experiment 3 do not interact with the pattern version - however they do influence search behavior such that subjects are more likely to search for Option A in Pattern 2 than in Pattern 1 as well as in Pattern 3 compared to Patterns 1 and 2.
### Prepare data for plotting
# Individuals with significant Attraction Search Score:
# Experiment 1: 6 trials - how many trials searched for consistently with ASE for significance?
binom.test(6,6)
##
## Exact binomial test
##
## data: 6 and 6
## number of successes = 6, number of trials = 6, p-value = 0.03125
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
## 0.5407419 1.0000000
## sample estimates:
## probability of success
## 1
ASScore.ind.Exp1 <- data.Exp1 %>%
# keep only information search data in decision task
filter(data == "choice.data" & answer.type == "search") %>%
select(ID, version, option.answer) %>%
group_by(ID, version, option.answer) %>%
# calculate number of searches per version and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID,version,option.answer,fill = list(n.searches=0)) %>%
filter((version == "a" & option.answer == "OptionA")|(version == "b" & option.answer == "OptionB")) %>%
group_by(ID) %>%
summarise(consistent.searches = sum(n.searches)) %>%
ungroup() %>%
mutate(Significance = ifelse(consistent.searches == 6, "significant", "non significant")) %>%
select(-consistent.searches)
plot.ASScore.Exp1 <- left_join(ASScore.Exp1, ASScore.ind.Exp1, by = "ID")
# Experiment 2: 12 trials - how many trials searched for consistently with ASE for significance?
binom.test(10,12)
##
## Exact binomial test
##
## data: 10 and 12
## number of successes = 10, number of trials = 12, p-value = 0.03857
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
## 0.5158623 0.9791375
## sample estimates:
## probability of success
## 0.8333333
ASScore.ind.Exp2 <- data.final.Exp2 %>%
# filter only data from choice task
filter(data == "choice.data") %>%
select(ID, opened.cue.1, opened.cue.2, first.search.valence) %>%
# create vectors for calculating AS-Score
mutate(first.search.option = ifelse(grepl("A",opened.cue.1), "OptionA", "OptionB"),
second.search.option = ifelse(grepl("A",opened.cue.2), "OptionA", "OptionB"),
first.search.valence = recode(first.search.valence, `1`= "positive", `-1` = "negative")) %>%
# create variable that codes whether the searched for option was switched in the second search
mutate(switching = ifelse((first.search.option == "OptionA" & second.search.option == "OptionA") |
(first.search.option == "OptionB" & second.search.option == "OptionB"),
"no.switch", "switch")) %>%
group_by(ID, switching, first.search.valence) %>%
# calculate number of switches per participant and per positive/negative initial evidence
summarise(n.switches = n()) %>%
ungroup() %>%
# fill in 0 if searched option was not switched for negative/positive inital evidence
complete(ID, switching, first.search.valence, fill = list(n.switches = 0)) %>%
filter((switching == "no.switch" & first.search.valence == "positive")|(switching == "switch" & first.search.valence == "negative")) %>%
group_by(ID) %>%
summarise(consistent.searches = sum(n.switches)) %>%
ungroup() %>%
mutate(Significance = ifelse(consistent.searches >= 10, "significant", "non significant")) %>%
select(-consistent.searches)
plot.ASScore.Exp2 <- left_join(ASScore.Exp2, ASScore.ind.Exp2, by = "ID")
# Experiment 3: 18 trials - how many trials searched for consistently with ASE for significance?
binom.test(14,18)
##
## Exact binomial test
##
## data: 14 and 18
## number of successes = 14, number of trials = 18, p-value = 0.03088
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
## 0.5236272 0.9359080
## sample estimates:
## probability of success
## 0.7777778
ASScore.ind.Exp3 <- data.final.Exp3 %>%
# select data from choice task
filter(data == "choice.data" & phase == "task") %>%
select(ID, version, opened.cue) %>%
mutate(searched.option = ifelse(grepl("A",opened.cue),"OptionA", "OptionB"))%>%
select(-opened.cue) %>%
group_by(ID, version, searched.option) %>%
# calculate number of searches per version and option
summarise(n.searches = n()) %>%
ungroup()%>%
# fill in 0 if option A/B was not searched for in one of the versions
complete(ID,version,searched.option,fill = list(n.searches=0)) %>%
filter((version == "a" & searched.option == "OptionA")|(version == "b" & searched.option == "OptionB")) %>%
group_by(ID) %>%
summarise(consistent.searches = sum(n.searches)) %>%
ungroup() %>%
mutate(Significance = ifelse(consistent.searches >= 14, "significant", "non significant")) %>%
select(-consistent.searches)
plot.ASScore.Exp3 <- left_join(ASScore.Exp3, ASScore.ind.Exp3, by = "ID")
# Plotting data 1
ASScore.overall <- data.frame(ID = c(plot.ASScore.Exp1$ID, plot.ASScore.Exp2$ID, plot.ASScore.Exp3$ID),
Experiment = c(rep("Experiment 1", nrow(plot.ASScore.Exp1)),
rep("Experiment 2", nrow(plot.ASScore.Exp2)),
rep("Experiment 3", nrow(plot.ASScore.Exp3))),
ASScore = c(plot.ASScore.Exp1$ASScore, plot.ASScore.Exp2$ASScore, plot.ASScore.Exp3$ASScore),
Significance = c(plot.ASScore.Exp1$Significance, plot.ASScore.Exp2$Significance, plot.ASScore.Exp3$Significance))
# Plotting data 2
ASScore.overall.mean <- ASScore.overall %>%
group_by(Experiment) %>%
summarise(ASScore.mean = mean(ASScore),
ASScore.sd = sd(ASScore),
ASScore.n = n()) %>%
mutate(ASScore.se = ASScore.sd/sqrt(ASScore.n),
ASScore = ASScore.mean,
Significance = "Mean Score Mean")
# Plot
ASScore.plot <- ggplot(ASScore.overall,aes(x = Experiment, y = ASScore))+
geom_violin(alpha=0.5, adjust = 1.7)+
geom_jitter(aes(x = Experiment, y = ASScore, color = Significance),width = 0.1, height = 0.02, alpha=0.5, size = 2)+
theme_bw()+
geom_point(data=ASScore.overall.mean, aes(color=Significance), size = 3)+
geom_errorbar(data=ASScore.overall.mean, aes(ymax = ASScore + ASScore.se, ymin = ASScore - ASScore.se, color = Significance), width=0.09)+
geom_hline(yintercept = 0, linetype = "dotted")+
scale_color_viridis_d("Type of Score", labels = c("overall mean score", "individual, non-significant score", "individual, significant score"))+#,h = c(120, 200)
scale_y_continuous(breaks = seq(-1,1,0.2), minor_breaks = seq(-1,1,0.2))+
ylab("Attraction Search Score")+
theme(text = element_text(size = 12),
strip.text.x = element_text(size = 10),
strip.text.y = element_text(size = 10),
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 8),
legend.justification=c(1,0),
legend.position=c(1,0),
legend.background = element_rect(linetype = "solid", color = "black"),
legend.title.align=0.5,
legend.text = element_text(size=8),
legend.title = element_text(size=8))+
xlab("")
print(ASScore.plot)
ggsave("ASScores_Experiments.eps", plot = ASScore.plot, device=cairo_ps, width = 6, units = "in", height = 5, dpi = 900)
# ggsave("ASScores_Experiments.pdf", plot = ASScore.plot, device=cairo_pdf, width = 6, units = "in", height = 5, dpi = 900)
# Combine dataframes with AS-Score results per Scenario
ASScore.Scenarios.overall <- data.frame(Scenario = c(as.character(ASScore.Scenarios.Exp1$scenario),
as.character(ASScore.Scenarios.Exp2$OptionA),
as.character(ASScore.Scenarios.Exp3$shop.item)),
Experiment = c(rep("Experiment 1", nrow(ASScore.Scenarios.Exp1)),
rep("Experiment 2", nrow(ASScore.Scenarios.Exp2)),
rep("Experiment 3", nrow(ASScore.Scenarios.Exp3))),
ASScore = c(ASScore.Scenarios.Exp1$ASScore, ASScore.Scenarios.Exp2$ASScore,
ASScore.Scenarios.Exp3$ASScore)) %>%
mutate(Scenario = recode(Scenario, city = "City", hair = "Hair Salon", hotel = "Hotel", job = "Job", pizza = "Pizza Service",
weather = "Weather Forecast", appartment_A = "Appartment", cellcontract_A = "Cell Contract",
city_A = "City", computer_A = "Computer", granola_A = "Granola", gym_A = "Gym",
hairsalon_A = "Hair Salon", hotel_A = "Hotel", insurance_A = "Insurance Policy", job_A = "Job",
pizza_A = "Pizza Service", weather_A = "Weather Forecast", blazer_blue = "Blue Blazer",
dress_black = "Black Dress", dress_floral = "Floral Dress", dress_grey = "Grey Dress",
jacket_floral = "Floral Jacket", jacket_fur = "Fur Jacket", jacket_green = "Green Jacket",
jacket_grey = "Grey Jacket", jacket_jeans = "Jeans Jacket", pullover_blue = "Blue Sweater",
pullover_grey = "Grey Sweater", pullover_white = "White Sweater", shirt_red = "Red Shirt",
shirt_stripes = "Striped Shirt", shorts_jeans = "Jeans Shorts", shorts_pink = "Pink Shorts",
top_black = "Black Top", top_white = "White Top")) %>%
mutate(Scenario = factor(Scenario, levels = c("City", "Hair Salon", "Hotel", "Job", "Pizza Service", "Weather Forecast",
"Appartment", "Cell Contract","Computer","Granola","Gym","Insurance Policy",
"Blue Blazer","Black Dress", "Floral Dress","Grey Dress","Floral Jacket",
"Fur Jacket","Green Jacket","Grey Jacket", "Jeans Jacket","Blue Sweater",
"Grey Sweater","White Sweater","Red Shirt","Striped Shirt", "Jeans Shorts",
"Pink Shorts","Black Top","White Top")))
# Plot
ASScore.Scenario.plot <- ggplot(ASScore.Scenarios.overall, aes(x = ASScore, y = Scenario, shape = Experiment, color = Experiment))+
geom_point(size=2)+
scale_y_discrete(limits=levels(ASScore.Scenarios.overall$Scenario)[30:1])+
theme_bw()+
scale_x_continuous(limits = c(-0.1,0.7), breaks = seq(-1,1,0.1), minor_breaks = seq(-1,1,0.1))+
geom_vline(data = ASScore.overall.mean, aes(xintercept = ASScore, color = Experiment))+
scale_color_viridis_d("Experiment")+#,h = c(50, 200)
ylab("Decision Context")+
xlab("Attraction Search Score")+
theme(text = element_text(size = 10),
strip.text.x = element_text(size = 8),
strip.text.y = element_text(size = 8),
axis.text.x = element_text(size = 8),
axis.text.y = element_text(size = 8),
legend.justification=c(1,0),
legend.position=c(1,0),
legend.background = element_rect(linetype = "solid", color = "black"),
legend.title.align=0.5,
legend.text = element_text(size=8),
legend.title = element_text(size=8))
print(ASScore.Scenario.plot)
ggsave("ASScores_Scenarios.eps", plot = ASScore.Scenario.plot, device=cairo_ps, width = 6, units = "in", height = 4, dpi = 900)
# ggsave("ASScores_Scenarios.pdf", plot = ASScore.Scenario.plot, device=cairo_pdf, width = 6, units = "in", height = 4, dpi = 900)
# Combine AS-Score results per pattern
ASScore.overall.pattern <- bind_rows(ASScore.pattern.Exp1, ASScore.pattern.Exp3, .id = "Experiment") %>%
group_by(Experiment, pattern) %>%
summarise(ASScore.mean = mean(ASScore),
ASScore.sd = sd(ASScore),
ASScore.n = n()) %>%
ungroup() %>%
mutate(Experiment = recode(Experiment, `1`= "Experiment 1", `2`= "Experiment 3"),
ASScore.se = ASScore.sd/sqrt(ASScore.n),
ASScore = ASScore.mean,
Significance = NA,
pattern = as.character(pattern)) %>%
select(-Significance)
# Update overall AS-Score results dataframe
ASScore.overall.mean <- ASScore.overall.mean %>%
select(-Significance) %>%
mutate(pattern = "overall")
# Create dataframe for AS-Score results based on Jekel et al. (2018)
ASScore.original <- data.frame(Experiment = rep(c("Jekel et al. (2018) - Experiment 1 (restricted search)",
"Jekel et al. (2018) - Experiment 2 (costly search)",
"Jekel et al. (2018) - Experiment 2 (free search)"), each = 5),
pattern = rep(c("4", "5", "6", "7", "overall"), 3),
ASScore = c(0.2689, 0.2652, 0.6515, 0.6326, 0.3021,
0.3638, 0.3170, 0.6317, 0.5848, 0.3231,
0.0500, 0.1523, 0.2705, 0.2614, 0.1193),
ASScore.mean = c(0.2689, 0.2652, 0.6515, 0.6326, 0.3021,
0.3638, 0.3170, 0.6317, 0.5848, 0.3231,
0.0500, 0.1523, 0.2705, 0.2614, 0.1193),
ASScore.sd = c(0.2560, 0.3198, 0.3168, 0.2379, 0.1403,
0.3165, 0.3429, 0.3941, 0.4184, 0.2155,
0.2277, 0.2508, 0.3558, 0.3239, 0.1387),
ASScore.n = rep(c(33, 56, 55), eqach = 5), stringsAsFactors = FALSE)
# Add standard errors
ASScore.original$ASScore.se <- ASScore.original$ASScore.sd/sqrt(ASScore.original$ASScore.n)
# Create final plotting dataframe
ASScore.comparisons <- bind_rows(ASScore.overall.pattern, ASScore.overall.mean, ASScore.original) %>%
mutate(Original = ifelse(grepl("Jekel", Experiment), "yes", "no"))
## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector
# Plot
ASScore.Comparison.plot <- ggplot(ASScore.comparisons, aes(y = ASScore, x = pattern, shape = Experiment, color = Experiment, group = Experiment))+
geom_point(position=position_dodge(width=0.2), size = 3)+
theme_bw()+
scale_shape_manual(name = "Experiment",
labels = c("Experiment 1", "Experiment 2", "Experiment 3",
"Jekel et al. (2018) - Experiment 1 (restricted search)",
"Jekel et al. (2018) - Experiment 2 (costly search)",
"Jekel et al. (2018) - Experiment 2 (free search)"),
values = c(19, 19, 19, 17, 17, 17))+
scale_y_continuous("Attraction Search Score", limits=c(-0.1, 1), breaks = seq(-1,1,0.1), minor_breaks = seq(-1,1,0.1)) +
scale_color_viridis_d(name="Experiment", labels=c("Experiment 1", "Experiment 2", "Experiment 3",
"Jekel et al. (2018) - Experiment 1 (restricted search)",
"Jekel et al. (2018) - Experiment 2 (costly search)",
"Jekel et al. (2018) - Experiment 2 (free search)"))+
guides(color=guide_legend(ncol=2), shape=guide_legend(ncol=2))+
theme(text = element_text(size = 12),
strip.text.x = element_text(size = 10),
strip.text.y = element_text(size = 10),
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 8),
legend.justification=c(0.0,1),
legend.position=c(0.0,1),
legend.background = element_rect(linetype = "solid", color = "black"),
legend.title.align=0.5)+
geom_errorbar(aes(ymax = ASScore + ASScore.se, ymin = ASScore - ASScore.se), width=0.3, position=position_dodge(width=0.2))+
geom_hline(yintercept = 0, linetype = "dotted")+
xlab("Cue Pattern")
print(ASScore.Comparison.plot)
ggsave("ASScores_Comparisons.eps", plot = ASScore.Comparison.plot, device=cairo_ps, width = 6, units = "in", height = 4.5,
dpi = 900)
# ggsave("ASScores_Comparisons.pdf", plot = ASScore.Comparison.plot, device=cairo_pdf, width = 6, units = "in", height = 4.5,
# dpi = 900)
# Dataframe for predicted probabilities for Experiment 1
coefficients.Exp1 <- coef(glmer.ASScore.Exp1.final)
coEff.Exp1.ID <- coefficients.Exp1$ID %>%
rownames_to_column("ID") %>%
mutate(oddsV_a = `(Intercept)`+ version1,
oddsV_b = `(Intercept)`- version1) %>%
mutate(probV_a = plogis(oddsV_a),
probV_b = plogis(oddsV_b)) %>%
mutate(probDiff = probV_a-probV_b) %>%
select(ID, probV_a, probV_b, probDiff) %>%
gather(Version, Probability, -ID, -probDiff) %>%
mutate(Version = recode(Version, probV_a = "a", probV_b = "b"),
ID = as.factor(ID))
coEff.Exp1.Scenario <- coefficients.Exp1$scenario %>%
rownames_to_column("Scenario") %>%
mutate(oddsV_a = `(Intercept)`+ version1,
oddsV_b = `(Intercept)`- version1) %>%
mutate(probV_a = plogis(oddsV_a),
probV_b = plogis(oddsV_b)) %>%
mutate(probDiff = probV_a-probV_b) %>%
select(Scenario, probV_a, probV_b, probDiff) %>%
gather(Version, Probability, -Scenario, -probDiff) %>%
mutate(Version = recode(Version, probV_a = "a", probV_b = "b"),
Scenario = as.factor(recode(Scenario,city = "City", hair = "Hair Salon", hotel = "Hotel", job = "Job",
pizza = "Pizza Service", weather = "Weather Forecast")))
### Dataframe for Predicted Probabilities for Experiment 2
coefficients.Exp2 <- coef(glmer.ASScore.Exp2.final)
coEff.Exp2.ID <- coefficients.Exp2$ID %>%
rownames_to_column("ID") %>%
mutate(oddsVal_pos = `(Intercept)`+ valence1,
oddsVal_neg = `(Intercept)`- valence1) %>%
mutate(probVal_pos = plogis(oddsVal_pos),
probVal_neg = plogis(oddsVal_neg)) %>%
mutate(probDiff = probVal_pos-probVal_neg) %>%
select(ID, probVal_pos, probVal_neg, probDiff) %>%
gather(Valence, Probability, -ID, -probDiff) %>%
mutate(Valence = recode(Valence, probVal_pos = "positive", probVal_neg = "negative"),
ID = as.factor(ID)) %>%
mutate(Valence = factor(Valence, levels = c("positive", "negative")))
### Dataframe for Predicted Probabilities for Experiment 3
coefficients.Exp3 <- coef(glmer.ASScore.Exp3.final)
coEff.Exp3.ID <- coefficients.Exp3$ID %>%
rownames_to_column("ID") %>%
mutate(oddsV_a = `(Intercept)`+ version1,
oddsV_b = `(Intercept)`- version1) %>%
mutate(probV_a = plogis(oddsV_a),
probV_b = plogis(oddsV_b)) %>%
mutate(probDiff = probV_a-probV_b) %>%
select(ID, probV_a, probV_b, probDiff) %>%
gather(Version, Probability, -ID, -probDiff) %>%
mutate(Version = recode(Version, probV_a = "a", probV_b = "b"),
ID = as.factor(ID))
### Plot predicted probabilities
Plot.Scenario.Exp1 <- ggplot(coEff.Exp1.Scenario, aes(x = Version, y = Probability, group = Scenario, shape = Scenario))+
geom_point(alpha = 0.6, size = 3)+
geom_line(alpha = 0.2)+
theme_bw()+
scale_y_continuous(limits = c(0,1), breaks = seq(0,1,0.1), minor_breaks = seq(0,1,0.1))+
theme(text = element_text(size = 8),
strip.text.x = element_text(size = 8),
strip.text.y = element_text(size = 8),
axis.text.x = element_text(size = 8),
axis.text.y = element_text(size = 8),
# legend.justification=c(1,1),
# legend.position=c(1,1),
# legend.background = element_rect(linetype = "solid", color = "black"),
# legend.title.align=0.5,
title = element_text(size = 8),
# legend.text = element_text(size=6),
# legend.title = element_text(size=8),
# legend.key.size=unit(0.1,'mm'),
plot.margin = unit(c(2, 2, 2, 2), "mm"))+
scale_x_discrete(expand = c(0, .2))+
labs(title = "Experiment 1", tag = "A", y = "Predicted Probability")
Plot.ID.Exp1 <- ggplot(coEff.Exp1.ID, aes(x = Version, y = Probability, group = ID))+
geom_point(size=2, alpha = 0.2)+
geom_line(alpha = 0.2)+
theme_bw()+
scale_y_continuous(limits = c(0,1), breaks = seq(0,1,0.1), minor_breaks = seq(0,1,0.1))+
scale_x_discrete(expand = c(0, .2))+
labs(title = "Experiment 1", tag = "B", y = "Predicted Probability")+
theme(text = element_text(size = 8),
strip.text.x = element_text(size = 8),
title = element_text(size = 8),
strip.text.y = element_text(size = 8),
axis.text.x = element_text(size = 8),
axis.text.y = element_text(size = 8),
plot.margin = unit(c(1, 1, 1, 1), "mm"))
Plot.ID.Exp2 <- ggplot(coEff.Exp2.ID, aes(x = Valence, y = Probability, group = ID))+
geom_point(size=2, alpha = 0.2)+
geom_line(alpha = 0.2)+
theme_bw()+
scale_y_continuous(limits = c(0,1), breaks = seq(0,1,0.1), minor_breaks = seq(0,1,0.1))+
scale_x_discrete(expand = c(0, .2))+
labs(title = "Experiment 2", tag = "", y = "")+
theme(text = element_text(size = 8),
title = element_text(size = 8),
strip.text.x = element_text(size = 8),
axis.text.x = element_text(size = 8),
axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
plot.margin = unit(c(1, 1, 1, 1), "mm"))
Plot.ID.Exp3 <- ggplot(coEff.Exp3.ID, aes(x = Version, y = Probability, group = ID))+
geom_point(size=2, alpha = 0.2)+
geom_line(alpha = 0.2)+
theme_bw()+
scale_y_continuous(limits = c(0,1), breaks = seq(0,1,0.1), minor_breaks = seq(0,1,0.1))+
scale_x_discrete(expand = c(0, .2))+
labs(title = "Experiment 3", tag = "", y = "")+
theme(text = element_text(size = 8),
title = element_text(size = 8),
strip.text.x = element_text(size = 8),
axis.text.x = element_text(size = 8),
axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
plot.margin = unit(c(1, 1, 1, 1), "mm"))
Plot.IDs <- plot_grid(Plot.ID.Exp1, Plot.ID.Exp2, Plot.ID.Exp3, align = "v", ncol = 3)
Plot.Slopes<- grid.arrange(grobs = list(Plot.Scenario.Exp1, Plot.IDs),
layout_matrix = rbind(c(1,1,1,NA,NA),
c(2,2,2,2,2)))
ggsave("RandomSlopes.eps", plot = Plot.Slopes, device=cairo_ps, width = 6, units = "in", height = 6, dpi = 900)
# ggsave("RandomSlopes.pdf", plot = Plot.Slopes, device=cairo_pdf, width = 6, units = "in", height = 6, dpi = 900)