Collective Resource Tracking Statistical Analysis
2026-04-20
Load Packages & Data
Subject-level Data
subj_data_raw <- read.csv(file = paste0(data_path, "subject_data.csv"))
subj_data <- subj_data_raw %>%
filter(is_valid == "True") %>%
filter(duplicates_percentage < 25) %>%
filter(valid_group_size >= 4 | condition_signaling == 'A') %>%
mutate(
Participant = as.factor(player_id),
Group = as.factor(group),
SignalingType = as.factor(condition_signaling),
SignalingType = factor(SignalingType, levels = c('A', 'NP', 'VP', 'FP')),
ResourceSpeed = as.factor(condition_resource),
ResourceSpeed = relevel(ResourceSpeed, ref = "fast"),
Score = as.numeric(final_score),
ScoreFirstHalf = as.numeric(score_first_half),
ScoreSecondHalf = Score - ScoreFirstHalf,
PCS = as.numeric(points_collection_speed) / 60, # convert to seconds
PCR = PCS,
TrackingTime = as.numeric(time_on_resource),
SignalingPercentageOthers = as.numeric(others_signaling_percentage),
SignalingPercentageOwn = as.numeric(own_signaling_percentage),
ResourceEncounters = as.numeric(resource_encounters),
IsInFullGroup = (SignalingType == 'A') | (valid_group_size == 5)
)
head(subj_data)subj_data %>%
group_by(condition_signaling, condition_resource, group) %>%
summarise(n_participants = n(), .groups = "drop") %>%
group_by(condition_signaling, condition_resource) %>%
summarise(
N_participants = sum(n_participants),
N_groups = n(),
N_groups_5 = sum(n_participants == 5),
N_groups_4 = sum(n_participants == 4),
.groups = "drop"
)[1] “player_id” “condition_signaling” “condition_resource” “starting_time_in_condition_minutes”
[5] “group” “time_in_experiment” “nan_percentage” “duplicates”
[9] “duplicates_percentage” “duplicates_resource_percentage” “is_valid” “average_distance_from_resource”
[13] “final_score” “score_first_half” “resource_encounters” “average_tracking_length”
[17] “time_on_resource” “points_collection_speed” “others_signaling_count” “others_signaling_percentage”
[21] “own_signaling_count” “own_signaling_percentage” “others_on_resource_signaling_count” “others_on_resource_signaling_percentage”
[25] “mean_visible_participants” “mean_visible_participants_tracking” “mean_visible_participants_not_tracking” “Total.approvals”
[29] “Age” “Sex” “Ethnicity.simplified” “Nationality”
[33] “Student.status” “Employment.status” “valid_group_size” “Participant”
[37] “Group” “SignalingType” “ResourceSpeed” “Score”
[41] “ScoreFirstHalf” “ScoreSecondHalf” “PCS” “PCR”
[45] “TrackingTime” “SignalingPercentageOthers” “SignalingPercentageOwn” “ResourceEncounters”
[49] “IsInFullGroup”
Time Series Data
time_series_data_raw <- read.csv(file = paste0(data_path, "time_series_data.csv"))
time_series_data <- time_series_data_raw %>%
mutate(
Participant = as.factor(participant),
SignalingType = as.factor(signaling),
ResourceSpeed = as.factor(resource),
State = as.factor(state),
DetectorChange = as.numeric(distance_change_lag1_cat2),
SocInfoQualityRaw = round(as.numeric(soc_info_quality_raw), 2),
SocInfoQuality = factor(ifelse(SocInfoQualityRaw < 0, "1", "-1"), levels = c("-1", "1")),
SocInfoQualityRawBest = round(as.numeric(soc_info_quality_raw_best), 2),
VisPlayersDistFromResource = round(as.numeric(best_distance_from_resource_visible_players), 2),
AllPlayersDistFromResource = round(as.numeric(best_distance_from_resource_all_players), 2),
OwnDistFromResource = round(as.numeric(first_distance_from_resource), 2),
OutDegree = as.numeric(out_degree),
InDegree = as.numeric(in_degree),
NoMovementTimes = as.numeric(no_movement_times),
SocialMovementDirection = round(as.numeric(social_movement_direction), 4),
SocialMovementDirectionBest = round(as.numeric(social_movement_direction_best), 4),
Rotation = round(as.numeric(rotation_change_mean_raw), 4),
AlignmentResourceChange = round(as.numeric(res_rotation_change), 4),
VisPlayersDirection = round(as.numeric(mean_degree_visible_players_first), 4),
PlayerRank = as.factor(rank_of_player_by_distance_from_resource_first),
IsSignaling = as.numeric(is_signaling),
Time = as.numeric(step),
SocialMovementDirectionCohesion = round(as.numeric(social_movement_direction_cohesion), 4),
MeanVisibleGroupSpread = round(as.numeric(mean_visible_group_spread), 2),
MeanDistToVisibleNeighbors = round(as.numeric(mean_distance_to_visible_neighbors), 2)
) %>%
mutate(ResourceSpeed = relevel(ResourceSpeed, ref = "fast")) %>%
mutate(SignalingType = factor(SignalingType, levels = c('A', 'NP', 'VP', 'FP'))) %>%
mutate(SocInfoQualityBin = factor(case_when(
(State == 'tracking') & (SocInfoQualityRawBest < 0) ~ 1,
(State == 'tracking') & (SocInfoQualityRawBest > 0) ~ 0,
(State == 'searching') & (VisPlayersDistFromResource < 40) ~ 1,
(State == 'searching') & (VisPlayersDistFromResource > 40) ~ 0,
.default = 0
), levels = c(0, 1))) %>%
mutate(IsGoodSocialInfoAvailable = factor(case_when(
(State == 'tracking') & (OwnDistFromResource > AllPlayersDistFromResource) ~ 1,
(State == 'tracking') & (OwnDistFromResource <= AllPlayersDistFromResource) ~ 0,
(State == 'searching') & (AllPlayersDistFromResource < 40) ~ 1,
(State == 'searching') & (AllPlayersDistFromResource > 40) ~ 0,
.default = 0
), levels = c(0, 1))) %>%
mutate(RotationDirCorrect = ifelse(AlignmentResourceChange > 0, 1, 0)) %>%
# mutate(MeanVisibleGroupSpreadStd = as.numeric(scale(log1p(MeanVisibleGroupSpread)))) %>%
mutate(MeanVisibleGroupSpreadStd = as.numeric(scale(MeanVisibleGroupSpread))) %>%
group_by(Participant) %>%
mutate(RotationLag1 = lag(Rotation, order_by=Participant)) %>%
mutate(DetectorChangeLag1 = lag(DetectorChange, order_by=Participant)) %>%
ungroup() %>%
select(Participant, SignalingType, ResourceSpeed, Time, State,
DetectorChange, DetectorChangeLag1, SocInfoQuality, InDegree, OutDegree,
SocInfoQualityRaw, SocInfoQualityBin,
IsGoodSocialInfoAvailable,SocialMovementDirection, Rotation, RotationLag1,
SocInfoQualityRawBest, VisPlayersDistFromResource, NoMovementTimes,
SocialMovementDirectionBest, OwnDistFromResource, RotationDirCorrect,
VisPlayersDirection, PlayerRank, IsSignaling,
SocialMovementDirectionCohesion, MeanVisibleGroupSpread, MeanVisibleGroupSpreadStd,
MeanDistToVisibleNeighbors)
head(time_series_data)[1] “Participant” “SignalingType” “ResourceSpeed” “Time” “State”
[6] “DetectorChange” “DetectorChangeLag1” “SocInfoQuality” “InDegree” “OutDegree”
[11] “SocInfoQualityRaw” “SocInfoQualityBin” “IsGoodSocialInfoAvailable” “SocialMovementDirection” “Rotation”
[16] “RotationLag1” “SocInfoQualityRawBest” “VisPlayersDistFromResource” “NoMovementTimes” “SocialMovementDirectionBest”
[21] “OwnDistFromResource” “RotationDirCorrect” “VisPlayersDirection” “PlayerRank” “IsSignaling”
[26] “SocialMovementDirectionCohesion” “MeanVisibleGroupSpread” “MeanVisibleGroupSpreadStd” “MeanDistToVisibleNeighbors”
Resource Discoveries Data
resource_discoveries_data_raw <- read.csv(file = paste0(data_path, "resource_discoveries_data.csv"))
resource_discoveries_data_all <- resource_discoveries_data_raw %>%
mutate(
Participant = as.factor(player_id),
Timepoint = as.numeric(timepoint) - 2,
Event = as.factor(events),
PlayerOrder = as.numeric(player_order),
PlayerOrderCat = as.factor(ifelse(player_order == 1, 'first', 'others')),
Distance = as.numeric(distance_from_resource),
IsOnResource = ifelse(Distance <= 40, 1, 0),
InDegree = as.numeric(in_degree),
OutDegree = as.numeric(out_degree),
SignalingType = as.factor(condition_signaling),
ResourceSpeed = as.factor(condition_resource),
IsSignaling = as.numeric(signaling)
) %>%
filter(Timepoint >= 0) %>% # remove 2-seconds offset
select(Participant, Event, SignalingType, ResourceSpeed, PlayerOrder, PlayerOrderCat, Timepoint, InDegree, OutDegree, Distance, IsOnResource, IsSignaling) %>%
mutate(SignalingType = factor(SignalingType, levels = c('A', 'NP', 'VP', 'FP')),)
resource_discoveries_data <- resource_discoveries_data_all %>%
filter(Timepoint >= 0) # remove 2-seconds offset
head(resource_discoveries_data)[1] “Participant” “Event” “SignalingType” “ResourceSpeed” “PlayerOrder” “PlayerOrderCat” “Timepoint” “InDegree” “OutDegree” “Distance” “IsOnResource”
[12] “IsSignaling”
Session Information
## R version 4.5.3 (2026-03-11)
## Platform: x86_64-pc-linux-gnu
## Running under: Debian GNU/Linux 13 (trixie)
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.29.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8
## [8] LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Europe/Berlin
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] Hmisc_5.2-5 scales_1.4.0 cowplot_1.1.3 ggthemes_5.1.0 extrafont_0.19 marginaleffects_0.25.1 gtools_3.9.5 gtExtras_0.5.0
## [9] gt_1.0.0 viridis_0.6.5 viridisLite_0.4.2 NISTunits_1.0.1 units_0.8-7 svglite_2.2.1 ggpubr_0.6.0 metR_0.18.1
## [17] cmdstanr_0.9.0 invgamma_1.1 kableExtra_1.4.0 jtools_2.3.0 hrbrthemes_0.8.7 interactions_1.2.0 bayesplot_1.12.0 brms_2.22.0
## [25] Rcpp_1.0.14 emmeans_1.11.1 coda_0.19-4.1 modelr_0.1.11 tidybayes_3.0.7 lubridate_1.9.4 forcats_1.0.0 stringr_1.5.1
## [33] dplyr_1.1.4 purrr_1.0.4 readr_2.1.5 tidyr_1.3.1 tibble_3.2.1 ggplot2_3.5.2 tidyverse_2.0.0 pacman_0.5.1
##
## loaded via a namespace (and not attached):
## [1] RColorBrewer_1.1-3 tensorA_0.36.2.1 rstudioapi_0.17.1 jsonlite_2.0.0 magrittr_2.0.3 estimability_1.5.1 farver_2.1.2 rmarkdown_2.29
## [9] vctrs_0.6.5 memoise_2.0.1 paletteer_1.6.0 base64enc_0.1-3 rstatix_0.7.2 htmltools_0.5.8.1 distributional_0.5.0 broom_1.0.8
## [17] Formula_1.2-5 sass_0.4.10 parallelly_1.44.0 bslib_0.9.0 htmlwidgets_1.6.4 fontawesome_0.5.3 cachem_1.1.0 lifecycle_1.0.4
## [25] pkgconfig_2.0.3 Matrix_1.7-4 R6_2.6.1 fastmap_1.2.0 future_1.49.0 digest_0.6.37 colorspace_2.1-2 furrr_0.3.1
## [33] rematch2_2.1.2 ps_1.9.1 textshaping_1.0.1 timechange_0.3.0 abind_1.4-8 compiler_4.5.3 fontquiver_0.2.1 withr_3.0.2
## [41] pander_0.6.6 htmlTable_2.4.3 backports_1.5.0 carData_3.0-5 Rttf2pt1_1.3.12 broom.mixed_0.2.9.6 ggsignif_0.6.4 loo_2.8.0
## [49] tools_4.5.3 foreign_0.8-91 extrafontdb_1.0 nnet_7.3-20 glue_1.8.0 nlme_3.1-168 grid_4.5.3 checkmate_2.3.2
## [57] cluster_2.1.8.2 generics_0.1.4 gtable_0.3.6 tzdb_0.5.0 data.table_1.17.2 hms_1.1.3 xml2_1.3.8 car_3.1-3
## [65] pillar_1.10.2 ggdist_3.3.3 posterior_1.6.1 splines_4.5.3 lattice_0.22-9 tidyselect_1.2.1 fontLiberation_0.1.0 knitr_1.50
## [73] fontBitstreamVera_0.1.1 arrayhelpers_1.1-0 gridExtra_2.3 bookdown_0.44 xfun_0.52 bridgesampling_1.1-2 matrixStats_1.5.0 stringi_1.8.7
## [81] yaml_2.3.10 evaluate_1.0.3 codetools_0.2-20 gdtools_0.4.2 cli_3.6.5 rpart_4.1.24 RcppParallel_5.1.10 xtable_1.8-4
## [89] systemfonts_1.2.3 processx_3.8.6 jquerylib_0.1.4 globals_0.18.0 svUnit_1.0.6 parallel_4.5.3 rstantools_2.4.0 Brobdingnag_1.2-9
## [97] listenv_0.9.1 mvtnorm_1.3-3 rlang_1.1.6