diff --git a/NAMESPACE b/NAMESPACE index 73ae628..d4539c8 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,8 +6,10 @@ export(extract_behavioral_data) export(extract_eyetracker_data) export(extract_recordings_data) export(false_alarm_by_response_time_model) -export(get_all_hits_with_reaction_times) +export(get_behavioral_metadata) +export(get_false_alarms_given_responses) export(get_hit_times) +export(get_hits_given_signals) export(hit_by_signal_time_model) export(reaction_time_by_signal_time_model) importFrom(magrittr,"%>%") diff --git a/R/behavioral_data_models.R b/R/behavioral_data_models.R index ec09fea..d93aba4 100644 --- a/R/behavioral_data_models.R +++ b/R/behavioral_data_models.R @@ -4,13 +4,13 @@ hit_by_signal_time_model <- function(df, random_effects = FALSE) { if (random_effects) { glmer( - is_hit ~ 1 + signal_time + (1 + signal_time | id), + is_hit_given_signal ~ 1 + signal_time + (1 + signal_time | id), data = df, family = "binomial" ) } else { glmer( - is_hit ~ 1 + signal_time + (1 | id), + is_hit_given_signal ~ 1 + signal_time + (1 | id), data = df, family = "binomial" ) @@ -40,13 +40,13 @@ reaction_time_by_signal_time_model <- function(df, random_effects = FALSE) { false_alarm_by_response_time_model <- function(df, random_effects = FALSE) { if (random_effects) { glmer( - is_false_alarm ~ 1 + resp_time + (1 + resp_time | id), + is_false_alarm_given_response ~ 1 + resp_time + (1 + resp_time | id), data = df, family = "binomial" ) } else { glmer( - is_false_alarm ~ 1 + resp_time + (1 | id), + is_false_alarm_given_response ~ 1 + resp_time + (1 | id), data = df, family = "binomial" ) diff --git a/R/behavioral_data_preprocessing.R b/R/behavioral_data_preprocessing.R index f86dcb7..0bd4cc6 100644 --- a/R/behavioral_data_preprocessing.R +++ b/R/behavioral_data_preprocessing.R @@ -1,3 +1,13 @@ +#' @title Get behavioral metadata for each participant +#' @description Creates a dataframe composed of each participant's id, signal +#' probability, clock side, task begin and end. +#' @export +get_behavioral_metadata <- function(behavioral_data) { + behavioral_data %>% + dplyr::select(id, p_signal, clock_side, task_begin, task_end) %>% + unique() +} + #' @title Get hit times vector from signals and responses per participant #' @description This function uses input of both signal times and response times #' from a single participant's extracted behavioral data to determine the hit @@ -11,12 +21,12 @@ get_hit_times <- function(signal_times, response_times, .interval = 8.0) { hit_indices <- c() signal_times %>% - map_dbl(function(signal_time) { + purrr::map_dbl(function(signal_time) { # Find indices for potential hits within the signal interval potential_hit_indices <- which( response_times %>% - map_lgl(~ between(.x, signal_time, signal_time + .interval)), + purrr::map_lgl(~ between(.x, signal_time, signal_time + .interval)), arr.ind = TRUE ) @@ -41,43 +51,59 @@ get_hit_times <- function(signal_times, response_times, .interval = 8.0) { }) } -#' @title Get all participants' hits with reaction times +#' @title Get all participants' hits given signal presence #' @description Creates a dataframe composed of each participant's hit times and #' reaction times for those hits, row-by-row with signal times. #' @export -get_all_hits_with_reaction_times <- function(combined_df) { +get_hits_given_signals <- function(behavioral_data) { - participants <- combined_df %>% - pull(id) %>% + participants <- behavioral_data %>% + dplyr::pull(id) %>% unique() # Extract only rows where a signal is present - all_signals_df <- combined_df %>% - filter(is_signal == 1) %>% - mutate( + only_signals_df <- behavioral_data %>% + dplyr::filter(is_signal == 1) %>% + dplyr::mutate( signal_time = step_time ) %>% - select(trial, id, image_index, signal_time) + dplyr::select(trial, id, image_index, signal_time) # Extract only rows where a response attempt is present - all_responses_df <- combined_df %>% - filter(is_response == 1) %>% - select(trial, id, image_index, resp_time) + only_responses_df <- behavioral_data %>% + dplyr::filter(is_response == 1) %>% + dplyr::select(trial, id, image_index, resp_time) # Map over the unlisted participants' ids to get the per-participant # signals and responses, then return a combined dataframe of all participant # including trial rows for signals, and if it exists, hit time and reaction time map_dfr(participants, function(participant) { - signals <- all_signals_df %>% - filter(id == participant) + signals <- only_signals_df %>% + dplyr::filter(id == participant) - responses <- all_responses_df %>% - filter(id == participant) + responses <- only_responses_df %>% + dplyr::filter(id == participant) - signals %>% mutate( + signals %>% dplyr::mutate( hit_time = get_hit_times(signals$signal_time, responses$resp_time), reaction_time = hit_time - signal_time, - is_hit = as.integer(!is.na(hit_time)) + is_hit_given_signal = as.integer(!is.na(hit_time)) ) }) } + +#' +#' +#' + +#' @title Get false alarms given responses for all participants +#' @description TODO +#' @export +get_false_alarms_given_responses <- function(behavioral_data, hits_with_reaction_times) { + behavioral_data %>% + dplyr::filter(is_response == 1) %>% + dplyr::left_join(hits_with_reaction_times, by = c('trial', 'id', 'image_index')) %>% + tidyr::replace_na(list(is_hit_given_signal = 0)) %>% + dplyr::mutate(is_false_alarm_given_response = as.integer(!is_hit_given_signal)) %>% + dplyr::select(trial, id, image_index, resp_time, is_false_alarm_given_response) +} diff --git a/_targets.R b/_targets.R index 696b98c..15055ec 100644 --- a/_targets.R +++ b/_targets.R @@ -34,7 +34,7 @@ tar_option_set( # Config config <- config::get() -mapped_extraction <- tar_map( +extract_raw_data <- tar_map( unlist = FALSE, # Return a nested list from tar_map() # Create a dataframe of participants' meta information using raw behavioral data response file names values = tibble( @@ -67,9 +67,9 @@ mapped_extraction <- tar_map( ) ) -combined_behavioral <- tar_combine( - extracted_behavioral_data_combined, - mapped_extraction$extracted_behavioral_data, +combine_extracted_behavioral_data <- tar_combine( + combined_behavioral_data, + extract_raw_data$extracted_behavioral_data, command = dplyr::bind_rows(!!!.x) %>% dplyr::mutate( # Transform step and response types to 0 or 1 integer values to simulate boolean behavior. @@ -79,6 +79,27 @@ combined_behavioral <- tar_combine( dplyr::select(-c(resp_type, step_type)) ) +preprocess_behavioral_data <- list ( + combine_extracted_behavioral_data, + tar_target( + behavioral_metadata, + get_behavioral_metadata(combined_behavioral_data) + ), + tar_target( + hits_given_signals, + get_hits_given_signals(combined_behavioral_data) + ), + tar_target( + false_alarms_given_responses, + get_false_alarms_given_responses(combined_behavioral_data, hits_given_signals) + ), + tar_render( + behavioral_data_preprocessing_notebook, + "notebooks/behavioral_data_preprocessing.Rmd", + output_dir = "output" + ) +) + summary_reports <- list( tar_render( incompletes, @@ -93,31 +114,7 @@ summary_reports <- list( ) list( - mapped_extraction, - combined_behavioral, - tar_target( #TODO: need to migrate to function in 'R/' - metadata_behavioral, - extracted_behavioral_data_combined %>% - dplyr::select(id, p_signal, clock_side, task_begin, task_end) %>% - unique() - ), - tar_target( - all_hits_with_reaction_times, - get_all_hits_with_reaction_times(extracted_behavioral_data_combined) - ), - tar_target( - false_alarms, - extracted_behavioral_data_combined %>% - dplyr::filter(is_response == 1) %>% - dplyr::left_join(all_hits_with_reaction_times, by = c('trial', 'id', 'image_index')) %>% - tidyr::replace_na(list(is_hit = 0)) %>% - dplyr::mutate(is_false_alarm = as.integer(!is_hit)) %>% - dplyr::select(trial, id, image_index, resp_time, is_false_alarm) - ), - tar_render( - behavioral_data_preprocessing_notebook, - "notebooks/behavioral_data_preprocessing.Rmd", - output_dir = "output" - ), + extract_raw_data, + preprocess_behavioral_data, summary_reports ) diff --git a/man/get_behavioral_metadata.Rd b/man/get_behavioral_metadata.Rd new file mode 100644 index 0000000..c31c1ad --- /dev/null +++ b/man/get_behavioral_metadata.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/behavioral_data_preprocessing.R +\name{get_behavioral_metadata} +\alias{get_behavioral_metadata} +\title{Get behavioral metadata for each participant} +\usage{ +get_behavioral_metadata(behavioral_data) +} +\description{ +Creates a dataframe composed of each participant's id, signal +probability, clock side, task begin and end. +} diff --git a/man/get_false_alarms_given_responses.Rd b/man/get_false_alarms_given_responses.Rd new file mode 100644 index 0000000..5591785 --- /dev/null +++ b/man/get_false_alarms_given_responses.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/behavioral_data_preprocessing.R +\name{get_false_alarms_given_responses} +\alias{get_false_alarms_given_responses} +\title{Get false alarms given responses for all participants} +\usage{ +get_false_alarms_given_responses(behavioral_data, hits_with_reaction_times) +} +\description{ +TODO +} diff --git a/man/get_all_hits_with_reaction_times.Rd b/man/get_hits_given_signals.Rd similarity index 59% rename from man/get_all_hits_with_reaction_times.Rd rename to man/get_hits_given_signals.Rd index a6a396f..491c602 100644 --- a/man/get_all_hits_with_reaction_times.Rd +++ b/man/get_hits_given_signals.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/behavioral_data_preprocessing.R -\name{get_all_hits_with_reaction_times} -\alias{get_all_hits_with_reaction_times} -\title{Get all participants' hits with reaction times} +\name{get_hits_given_signals} +\alias{get_hits_given_signals} +\title{Get all participants' hits given signal presence} \usage{ -get_all_hits_with_reaction_times(combined_df) +get_hits_given_signals(behavioral_data) } \description{ Creates a dataframe composed of each participant's hit times and diff --git a/notebooks/behavioral_data_preprocessing.Rmd b/notebooks/behavioral_data_preprocessing.Rmd index 6abdd5b..c720d17 100644 --- a/notebooks/behavioral_data_preprocessing.Rmd +++ b/notebooks/behavioral_data_preprocessing.Rmd @@ -42,7 +42,7 @@ Use `tar_read` to get the target object `extracted_behavioral_data_combined` and ```{r load-data} withr::with_dir(here::here(), { - combined_df <- tar_read(extracted_behavioral_data_combined) + combined_df <- tar_read(combined_behavioral_data) }) ``` @@ -66,7 +66,7 @@ Read targets object `all_hits_with_reaction_times` and assign to the combined hi ```{r read-combined-hits} withr::with_dir(here::here(), { - combined_hits_df <- tar_read(all_hits_with_reaction_times) + combined_hits_df <- tar_read(hits_given_signals) }) ``` @@ -132,7 +132,7 @@ combined_hits_df %>% ```{r read-false-alarms} withr::with_dir(here::here(), { - false_alarms_df <- tar_read(false_alarms) + false_alarms_df <- tar_read(false_alarms_given_responses) }) ``` @@ -221,3 +221,20 @@ model_FA_resp_time_rfx = false_alarm_by_response_time_model( summary(model_FA_resp_time_rfx) ``` +```{r} +scaled_false_alarms_df$pred <- predict(model_FA_resp_time_rfx, type = "response") +ggplot(scaled_false_alarms_df, aes(x = resp_time)) + + geom_line(aes(x = resp_time, y = pred)) +``` + +```{r} +scaled_false_alarms_df$pred <- predict(model_FA_resp_time_rfx, type = "response") +scaled_false_alarms_df +``` + +## Playground (in progress) + +```{r} +combined_hits_df %>% + mutate(first_half_of_task = as.integer(signal_time < 1800)) +``` diff --git a/output/behavioral_data_preprocessing.html b/output/behavioral_data_preprocessing.html index 7fedead..99bf346 100644 --- a/output/behavioral_data_preprocessing.html +++ b/output/behavioral_data_preprocessing.html @@ -620,11 +620,12 @@
Use tar_read
to get the target object extracted_behavioral_data_combined
and assign it to combined_df
.
withr::with_dir(here::here(), {
- combined_df <- tar_read(extracted_behavioral_data_combined)
+ combined_df <- tar_read(combined_behavioral_data)
})
Look at a few rows of data to verify output format.
@@ -733,7 +734,7 @@Read targets object all_hits_with_reaction_times
and assign to the combined hits dataframe combined_hits_df
.
withr::with_dir(here::here(), {
- combined_hits_df <- tar_read(all_hits_with_reaction_times)
+ combined_hits_df <- tar_read(hits_given_signals)
})
Check out a quick preview of the table of hits
@@ -746,7 +747,7 @@withr::with_dir(here::here(), {
- false_alarms_df <- tar_read(false_alarms)
+ false_alarms_df <- tar_read(false_alarms_given_responses)
})
false_alarms_df %>%
head() %>%
@@ -917,7 +918,7 @@ Read false alarms target
id
image_index
resp_time
-is_false_alarm
+is_false_alarm_given_response
@@ -984,7 +985,7 @@ Predict the probability
## Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) [glmerMod
## ]
## Family: binomial ( logit )
-## Formula: is_hit ~ 1 + signal_time + (1 | id)
+## Formula: is_hit_given_signal ~ 1 + signal_time + (1 | id)
## Data: df
##
## AIC BIC logLik deviance df.resid
@@ -1020,7 +1021,7 @@ Pre
## Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) [glmerMod
## ]
## Family: binomial ( logit )
-## Formula: is_hit ~ 1 + signal_time + (1 + signal_time | id)
+## Formula: is_hit_given_signal ~ 1 + signal_time + (1 + signal_time | id)
## Data: df
##
## AIC BIC logLik deviance df.resid
@@ -1125,7 +1126,7 @@ Predict the p
## Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) [glmerMod
## ]
## Family: binomial ( logit )
-## Formula: is_false_alarm ~ 1 + resp_time + (1 | id)
+## Formula: is_false_alarm_given_response ~ 1 + resp_time + (1 | id)
## Data: df
##
## AIC BIC logLik deviance df.resid
@@ -1161,7 +1162,7 @@
+
+
+scaled_false_alarms_df$pred <- predict(model_FA_resp_time_rfx, type = "response")
+scaled_false_alarms_df
+## # A tibble: 1,865 x 6
+## trial id image_index resp_time is_false_alarm_given_response pred
+## <int> <chr> <dbl> <dbl> <int> <dbl>
+## 1 117 CSN001 941 0.0325 0 0.632
+## 2 357 CSN001 3505 0.0991 1 0.650
+## 3 426 CSN001 2139 0.118 1 0.655
+## 4 523 CSN001 2880 0.145 1 0.662
+## 5 739 CSN001 2932 0.205 1 0.678
+## 6 823 CSN001 929 0.229 0 0.684
+## 7 846 CSN001 2799 0.235 1 0.685
+## 8 1029 CSN001 551 0.286 0 0.698
+## 9 1225 CSN001 436 0.340 1 0.711
+## 10 1630 CSN001 2639 0.453 0 0.738
+## # … with 1,855 more rows
+
+Playground (in progress)
+
+## # A tibble: 1,800 x 8
+## trial id image_index signal_time hit_time reaction_time is_hit_given_signal
+## <int> <chr> <dbl> <dbl> <dbl> <dbl> <int>
+## 1 81 CSN001 801 80.1 NA NA 0
+## 2 117 CSN001 941 116. 117. 0.918 1
+## 3 119 CSN001 3131 118. NA NA 0
+## 4 211 CSN001 1325 210. NA NA 0
+## 5 235 CSN001 752 234. NA NA 0
+## 6 361 CSN001 103 360. NA NA 0
+## 7 461 CSN001 2804 460. NA NA 0
+## 8 591 CSN001 28 590. NA NA 0
+## 9 823 CSN001 929 822. 823. 0.710 1
+## 10 845 CSN001 517 844. 846. 1.86 1
+## # … with 1,790 more rows, and 1 more variable: first_half_of_task <int>
+