├── man ├── .Rapp.history ├── exampleData.Rd ├── simulateSSP.Rd ├── simulateDSTP.Rd ├── caf.Rd ├── cdf.Rd ├── fitSSP.Rd ├── fitDSTP.Rd ├── plotFitSSP.Rd ├── plotFitDSTP.Rd ├── fitSSP_fixed.Rd ├── fitDSTP_fixed.Rd ├── fitMultipleSSP.Rd ├── fitMultipleSSP_fixed.Rd ├── fitMultipleDSTP.Rd └── fitMultipleDSTP_fixed.Rd ├── src ├── .gitignore ├── .DS_Store ├── simulateSSP_new.cpp ├── RcppExports.cpp ├── simulateDSTP_new.cpp └── legacy │ ├── simulateSSP.cpp │ └── simulateDSTP.cpp ├── .gitignore ├── .DS_Store ├── R ├── .DS_Store ├── zzz_imports.R ├── RcppExports.R ├── zzz.R ├── datasets.R ├── miscFunctions.R ├── zzz_aliases.R ├── cdfFunctions.R ├── modelPrep.R ├── optimisation.R ├── cafFunctions.R ├── plotting.R ├── sspFunctions.R └── dstpFunctions.R ├── images └── logo.png ├── data └── exampleData.rda ├── .Rbuildignore ├── flankr.Rproj ├── NEWS.md ├── DESCRIPTION ├── NAMESPACE ├── cran-comments.md ├── README.md └── README.Rmd /man/.Rapp.history: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JimGrange/flankr/HEAD/.DS_Store -------------------------------------------------------------------------------- /R/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JimGrange/flankr/HEAD/R/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JimGrange/flankr/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JimGrange/flankr/HEAD/images/logo.png -------------------------------------------------------------------------------- /data/exampleData.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JimGrange/flankr/HEAD/data/exampleData.rda -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README\.Rmd$ 4 | ^legacy(/|$) 5 | ^src-legacy(/|$) 6 | ^images$ 7 | ^cran-comments\.md$ 8 | ^CRAN-SUBMISSION$ 9 | -------------------------------------------------------------------------------- /R/zzz_imports.R: -------------------------------------------------------------------------------- 1 | #' @importFrom stats optim quantile rnorm 2 | #' @importFrom graphics legend lines par points 3 | #' @importFrom utils read.csv 4 | 5 | #' @useDynLib flankr, .registration = TRUE 6 | #' @importFrom Rcpp sourceCpp 7 | NULL 8 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | getDSTP_new <- function(parms, trialType, nTrials, dt, var) { 5 | .Call(`_flankr_getDSTP_new`, parms, trialType, nTrials, dt, var) 6 | } 7 | 8 | getSSP_new <- function(parms, trialType, nTrials, dt, var) { 9 | .Call(`_flankr_getSSP_new`, parms, trialType, nTrials, dt, var) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /flankr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(libname, pkgname) { 2 | local_ver <- utils::packageVersion(pkgname) 3 | cran_ver <- "9.2.0" # latest CRAN release 4 | 5 | if (local_ver < cran_ver) { 6 | packageStartupMessage( 7 | sprintf("%s %s: \n", pkgname, local_ver), 8 | "Please note this version differs slightly from that published in ", 9 | "Behavior Research Methods. Please install the new version from CRAN. ", 10 | "See the README for how to update: https://github.com/JimGrange/flankr" 11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # flankr v1.2.0 2 | * 50% further efficiency in DSTP simulation speed 3 | * 24% further efficiency in SSP simulation speed 4 | * Note that the way random seeds are handled in both $\textt{simulateDSTP}$ and 5 | $\textt{simulateSSP}$ is slightly different to that in version 1.0.0 (initial 6 | release). Therefore, there may be very slight differences between simulation 7 | data (and therefore potentially very slight differences in best-fitting 8 | parameter values) between versions. 9 | 10 | # flankr v1.1.0 11 | * More efficient simulation---and therefore fitting---of both the DSTP and 12 | SSP models. (But more to be done on this!) 13 | * Refactored some code & examples in preparation for CRAN submission. 14 | (But more to be done on this!) 15 | * Added function name aliases to allow for snake_case. 16 | 17 | # flankr v1.0.0 18 | * Initial release (Github only) 19 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: flankr 2 | Title: Implementing Computational Models of Attentional Selectivity 3 | Version: 1.2.0.9999 4 | Authors@R: 5 | c( 6 | person("Jim", "Grange", role = c("aut", "cre"), 7 | email = "grange.jim@gmail.com", 8 | comment = c(ORCID = "0000-0002-8352-8390")) 9 | ) 10 | Description: A set of methods to simulate from and fit computational models of 11 | attentional selectivity. The package implements the dual-stage two-phase 12 | (DSTP) model of Hübner et al. (2010) , and the 13 | shrinking spotlight (SSP) model of White et al. (2011) 14 | . 15 | Depends: R (>= 4.0) 16 | Imports: 17 | Rcpp 18 | LinkingTo: 19 | Rcpp 20 | Suggests: 21 | knitr, rmarkdown 22 | License: GPL-3 23 | LazyData: true 24 | Encoding: UTF-8 25 | RoxygenNote: 7.3.2 26 | URL: https://github.com/JimGrange/flankr 27 | BugReports: https://github.com/JimGrange/flankr/issues 28 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(caf) 4 | export(cdf) 5 | export(fitDSTP) 6 | export(fitDSTP_fixed) 7 | export(fitMultipleDSTP) 8 | export(fitMultipleDSTP_fixed) 9 | export(fitMultipleSSP) 10 | export(fitMultipleSSP_fixed) 11 | export(fitSSP) 12 | export(fitSSP_fixed) 13 | export(fit_dstp) 14 | export(fit_dstp_fixed) 15 | export(fit_multiple_dstp) 16 | export(fit_multiple_dstp_fixed) 17 | export(fit_multiple_ssp) 18 | export(fit_multiple_ssp_fixed) 19 | export(fit_ssp) 20 | export(fit_ssp_fixed) 21 | export(plotFitDSTP) 22 | export(plotFitSSP) 23 | export(plot_fit_dstp) 24 | export(plot_fit_ssp) 25 | export(simulateDSTP) 26 | export(simulateSSP) 27 | export(simulate_dstp) 28 | export(simulate_ssp) 29 | importFrom(Rcpp,sourceCpp) 30 | importFrom(graphics,legend) 31 | importFrom(graphics,lines) 32 | importFrom(graphics,par) 33 | importFrom(graphics,points) 34 | importFrom(stats,optim) 35 | importFrom(stats,quantile) 36 | importFrom(stats,rnorm) 37 | importFrom(utils,read.csv) 38 | useDynLib(flankr) 39 | useDynLib(flankr, .registration = TRUE) 40 | -------------------------------------------------------------------------------- /R/datasets.R: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | #' Example response time data set for multiple subjects. 3 | #' 4 | #' An example data set containing multiple participants' data for a response 5 | #' time study involving two experimental conditions, as well as the congruency 6 | #' manipulation. The data includes response time and accuracy. 7 | #' 8 | #' This data is taken from Grange, J.A. (in preparation). The effect of 9 | #' accessory stimuli on choice response time in the flanker task. 10 | #' 11 | #' @format A data frame with 12524 rows and 5 variables: 12 | #' \describe{ 13 | #' \item{subject}{The subject identification number. Note that some 14 | #' participants were removed due to poor accuracy.} 15 | #' \item{condition}{The experimental condition (2 in this example). It 16 | #' logs the presence/absence of an auditory tone before stimulus 17 | #' onset.} 18 | #' \item{congruency}{The congruency of the flanker stimulus.} 19 | #' \item{accuracy}{Accuracy of the response; 1 = correct, 0 = error} 20 | #' \item{rt}{Response time, coded in seconds.} 21 | #' 22 | #' } 23 | "exampleData" 24 | # ------------------------------------------------------------------------------ 25 | -------------------------------------------------------------------------------- /man/exampleData.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/datasets.R 3 | \docType{data} 4 | \name{exampleData} 5 | \alias{exampleData} 6 | \title{Example response time data set for multiple subjects.} 7 | \format{ 8 | A data frame with 12524 rows and 5 variables: 9 | \describe{ 10 | \item{subject}{The subject identification number. Note that some 11 | participants were removed due to poor accuracy.} 12 | \item{condition}{The experimental condition (2 in this example). It 13 | logs the presence/absence of an auditory tone before stimulus 14 | onset.} 15 | \item{congruency}{The congruency of the flanker stimulus.} 16 | \item{accuracy}{Accuracy of the response; 1 = correct, 0 = error} 17 | \item{rt}{Response time, coded in seconds.} 18 | 19 | } 20 | } 21 | \usage{ 22 | exampleData 23 | } 24 | \description{ 25 | An example data set containing multiple participants' data for a response 26 | time study involving two experimental conditions, as well as the congruency 27 | manipulation. The data includes response time and accuracy. 28 | } 29 | \details{ 30 | This data is taken from Grange, J.A. (in preparation). The effect of 31 | accessory stimuli on choice response time in the flanker task. 32 | } 33 | \keyword{datasets} 34 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Resubmission 2 | This is a resubmission. In this version I have addressed all comments from CRAN 3 | review as follows: 4 | 5 | * Removed "This package", "Functions for", package name, title or similar" from 6 | DESCRIPTION 7 | * Added doi describing the methods in DESCRIPTION 8 | * Added missing \value to .Rd files regarding exported methods 9 | * Replaced all dontrun{} with donttest{}. In addition, I've provided toy 10 | examples that run under 5 seconds, and kept donttest{} for the rest 11 | * Changed all messages printed to console from print() to message() 12 | * When par changed in function I've added an immediate call of on.exit() 13 | * Removed setting of seed to specific number within functions 14 | 15 | 16 | ## Test environments 17 | * local OS Sonoma v.14.3.1, R 4.5.1 18 | * local Windows 10 Home, R 4.3.1 19 | * win-builder (devel and release) 20 | 21 | ## R CMD check results 22 | There were no ERRORs, WARNINGs, or NOTEs. 23 | 24 | 25 | ## Win-builder test (devel and release) 26 | There were no ERRORs or WARNINGS. 27 | 28 | There was 1 NOTE: 29 | 30 | ### Checking CRAN incoming feasibility 31 | 32 | * New submission 33 | * This is a new release to CRAN 34 | * Possibly misspelled words in DESCRIPTION: Attentional (2:45), DSTP (11:6), 35 | SSP (11:37), attentional (11:52) 36 | * These have all been checked and are correct. 37 | -------------------------------------------------------------------------------- /R/miscFunctions.R: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # function so the user can get their data from a dialog box rather than code 3 | getData <- function(){ 4 | 5 | data <- file.choose() 6 | data <- read.csv(data, header = TRUE) 7 | 8 | return(data) 9 | 10 | } 11 | # ------------------------------------------------------------------------------ 12 | 13 | 14 | # ------------------------------------------------------------------------------ 15 | # get matrix of random starting parameters for DSTP model around fixed means 16 | getRandomParms <- function(startParms, varParms, maxParms, n){ 17 | 18 | # initialise matrix 19 | finalParms <- matrix(0, n, length(startParms)) 20 | 21 | 22 | # for each row 23 | for(i in 1:n){ 24 | currParms <- startParms + rnorm(length(startParms), 0, varParms) 25 | 26 | # make sure no parameter is negative and not above maximum allowed value 27 | while(((min(currParms) < 0) | (min(maxParms - currParms) < 0))){ 28 | currParms <- startParms + rnorm(length(startParms), 0, varParms) 29 | } 30 | 31 | # store the current vector 32 | finalParms[i, ] <- currParms 33 | } 34 | 35 | # change the first entry to match the starting parameters 36 | finalParms[1, ] <- startParms 37 | 38 | finalParms <- round(finalParms, 3) 39 | 40 | # return the matrix 41 | return(finalParms) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /R/zzz_aliases.R: -------------------------------------------------------------------------------- 1 | # snake case DSTP --------------------------------------------------------- 2 | #' @rdname simulateDSTP 3 | #' @export 4 | simulate_dstp <- simulateDSTP 5 | 6 | #' @rdname fitDSTP 7 | #' @export 8 | fit_dstp <- fitDSTP 9 | 10 | #' @rdname fitMultipleDSTP 11 | #' @export 12 | fit_multiple_dstp <- fitMultipleDSTP 13 | 14 | #' @rdname fitMultipleDSTP 15 | #' @export 16 | fit_multiple_dstp <- fitMultipleDSTP 17 | 18 | #' @rdname fitDSTP_fixed 19 | #' @export 20 | fit_dstp_fixed <- fitDSTP_fixed 21 | 22 | #' @rdname fitMultipleDSTP_fixed 23 | #' @export 24 | fit_multiple_dstp_fixed <- fitMultipleDSTP_fixed 25 | 26 | 27 | 28 | 29 | # snake case SSP ---------------------------------------------------------- 30 | #' @rdname simulateSSP 31 | #' @export 32 | simulate_ssp <- simulateSSP 33 | 34 | #' @rdname fitSSP 35 | #' @export 36 | fit_ssp <- fitSSP 37 | 38 | #' @rdname fitMultipleSSP 39 | #' @export 40 | fit_multiple_ssp <- fitMultipleSSP 41 | 42 | #' @rdname fitMultipleSSP 43 | #' @export 44 | fit_multiple_ssp <- fitMultipleSSP 45 | 46 | #' @rdname fitSSP_fixed 47 | 48 | #' @export 49 | fit_ssp_fixed <- fitSSP_fixed 50 | 51 | #' @rdname fitMultipleSSP_fixed 52 | #' @export 53 | fit_multiple_ssp_fixed <- fitMultipleSSP_fixed 54 | 55 | 56 | 57 | 58 | # snake case plotting ----------------------------------------------------- 59 | 60 | #' @rdname plotFitDSTP 61 | #' @export 62 | plot_fit_dstp <- plotFitDSTP 63 | 64 | #' @rdname plotFitSSP 65 | #' @export 66 | plot_fit_ssp <- plotFitSSP 67 | 68 | -------------------------------------------------------------------------------- /man/simulateSSP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sspFunctions.R, R/zzz_aliases.R 3 | \name{simulateSSP} 4 | \alias{simulateSSP} 5 | \alias{simulate_ssp} 6 | \title{Obtain simulated response times and accuracy from the SSP model} 7 | \usage{ 8 | simulateSSP(parms, nTrials, var = 0.01, dt = 1/1000, seed = NULL) 9 | 10 | simulate_ssp(parms, nTrials, var = 0.01, dt = 1/1000, seed = NULL) 11 | } 12 | \arguments{ 13 | \item{parms}{The set of parameters to use to simulate the data. Must be 14 | contained in a vector in the order: \code{A}, \code{ter}, 15 | \code{p}, \code{rd}, \code{sda}.} 16 | 17 | \item{nTrials}{How many trials to simulate per congruency condition.} 18 | 19 | \item{var}{The variance of the diffusion process. By default this is set to 20 | 0.01.} 21 | 22 | \item{dt}{The diffusion scaling parameter (i.e., time steps). By default, 23 | this is set to 0.001.} 24 | 25 | \item{seed}{The value for the \code{set.seed} function to set random 26 | generation state.} 27 | } 28 | \value{ 29 | Returns a data frame with three columns: rt (response time) in 30 | seconds, accuracy of the model's response (1 for correct, 0 for error), and 31 | congruency condition. 32 | } 33 | \description{ 34 | \code{simulateSSP} generates synthetic data from the DSTP model in the 35 | form of response time (RT) in seconds and accuracy for both congruent and 36 | incongruent trials. 37 | } 38 | \details{ 39 | This function can be employed by the user to generate synthetic data, but 40 | its main purpose is to be used by the fitting procedure to generate model 41 | predictions for a set of parameter values when trying to find the best- 42 | fitting values. 43 | } 44 | \examples{ 45 | 46 | # declare the parameters 47 | parms <- c(0.050, 0.300, 0.400, 0.040, 1.500) 48 | 49 | # simulate the data 50 | # (Note this is a toy example with very low trial numbers to speed up the 51 | # example. For proper use, increase nTrials.) 52 | modelData <- simulateSSP(parms, nTrials = 100) 53 | 54 | } 55 | -------------------------------------------------------------------------------- /man/simulateDSTP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dstpFunctions.R, R/zzz_aliases.R 3 | \name{simulateDSTP} 4 | \alias{simulateDSTP} 5 | \alias{simulate_dstp} 6 | \title{Obtain simulated response times and accuracy from the DSTP model} 7 | \usage{ 8 | simulateDSTP(parms, nTrials, var = 0.01, dt = 1/1000, seed = NULL) 9 | 10 | simulate_dstp(parms, nTrials, var = 0.01, dt = 1/1000, seed = NULL) 11 | } 12 | \arguments{ 13 | \item{parms}{The set of parameters to use to simulate the data. Must be 14 | contained in a vector in the order: \code{A}, \code{C}, \code{driftTarget}, 15 | \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}.} 16 | 17 | \item{nTrials}{How many trials to simulate per congruency condition.} 18 | 19 | \item{var}{The variance of the diffusion process. By default this is set to 20 | 0.01.} 21 | 22 | \item{dt}{The diffusion scaling parameter (i.e., time steps). By default, 23 | this is set to 0.001.} 24 | 25 | \item{seed}{The value for the \code{set.seed} function to set random 26 | generation state.} 27 | } 28 | \value{ 29 | Returns a data frame with three columns: rt (response time) in 30 | seconds, accuracy of the model's response (1 for correct, 0 for error), and 31 | congruency condition. 32 | } 33 | \description{ 34 | \code{simulateDSTP} generates synthetic data from the DSTP model in the 35 | form of response time (RT) in seconds and accuracy for both congruent and 36 | incongruent trials. 37 | } 38 | \details{ 39 | This function can be employed by the user to generate synthetic data, but 40 | its main purpose is to be used by the fitting procedure to generate model 41 | predictions for a set of parameter values when trying to find the best- 42 | fitting values.d 43 | } 44 | \examples{ 45 | # declare the parameters 46 | parms <- c(0.070, 0.086, 0.045, 0.065, 0.368, 1.575, 0.225) 47 | 48 | # simulate the data. (Note this is a toy example with very low trial numbers 49 | # to speed up the example. For proper use, increase nTrials.) 50 | modelData <- simulateDSTP(parms, nTrials = 100) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/simulateSSP_new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace Rcpp; 4 | 5 | // [[Rcpp::export]] 6 | NumericMatrix getSSP_new(NumericVector parms, 7 | int trialType, 8 | int nTrials, 9 | double dt, 10 | double var) { 11 | 12 | // fixed parameters 13 | const double sdRand = std::sqrt(dt * var); 14 | 15 | // unpack parameters 16 | const double A = parms[0], B = -parms[0]; 17 | const double tEr = parms[1]; 18 | const double p = parms[2]; 19 | const double rd = parms[3]; 20 | const double sda = parms[4]; 21 | 22 | const double p_target = p; 23 | const double p_flanker = (trialType == 2) ? -p : p; 24 | 25 | const int m = 20000; 26 | NumericVector mu_target_vec(m), mu_flanker_vec(m); 27 | double* mu_target = REAL(mu_target_vec); 28 | double* mu_flanker = REAL(mu_flanker_vec); 29 | 30 | // precompute drift vectors 31 | for (int t = 0; t < m; ++t) { 32 | double sd_t = sda - (rd * t); 33 | if (sd_t <= 0.001) sd_t = 0.001; 34 | 35 | // efficiency trick: instead of passing sd_t as the SD to pnorm5, we 36 | // can convert to z-scores (x/sd_t) and use SD = 1.0. This avoids 37 | // repeated division internally to pnorm5 and is mathematically identical 38 | // 39 | // in previous versions the call was: pnorm(0.5, 0, sd_t, 1, 0) 40 | const double inv_sd = 1.0 / sd_t; 41 | 42 | const double a_target = 43 | R::pnorm5(0.5 * inv_sd, 0.0, 1.0, 1, 0) - 44 | R::pnorm5(-0.5 * inv_sd, 0.0, 1.0, 1, 0); 45 | 46 | const double a_flanker = 47 | R::pnorm5(10.0 * inv_sd, 0.0, 1.0, 1, 0) - 48 | R::pnorm5(0.5 * inv_sd, 0.0, 1.0, 1, 0); 49 | 50 | mu_target[t] = p_target * a_target * dt; 51 | mu_flanker[t] = 2.0 * p_flanker * a_flanker * dt; 52 | } 53 | 54 | NumericMatrix trialData(nTrials, 2); 55 | 56 | // simulate each trial 57 | for (int i = 0; i < nTrials; ++i) { 58 | double currEvidence = 0.0; 59 | int t = 0; 60 | 61 | while (currEvidence <= A && currEvidence >= B && t < m) { 62 | const double drift = mu_target[t] + mu_flanker[t]; 63 | currEvidence += R::rnorm(drift, sdRand); 64 | ++t; 65 | } 66 | 67 | trialData(i, 0) = (t * dt) + tEr; 68 | trialData(i, 1) = (currEvidence >= A) ? 1.0 : 0.0; 69 | } 70 | 71 | return trialData; 72 | } 73 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | #ifdef RCPP_USE_GLOBAL_ROSTREAM 9 | Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); 10 | Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); 11 | #endif 12 | 13 | // getDSTP_new 14 | NumericMatrix getDSTP_new(NumericVector parms, int trialType, int nTrials, double dt, double var); 15 | RcppExport SEXP _flankr_getDSTP_new(SEXP parmsSEXP, SEXP trialTypeSEXP, SEXP nTrialsSEXP, SEXP dtSEXP, SEXP varSEXP) { 16 | BEGIN_RCPP 17 | Rcpp::RObject rcpp_result_gen; 18 | Rcpp::RNGScope rcpp_rngScope_gen; 19 | Rcpp::traits::input_parameter< NumericVector >::type parms(parmsSEXP); 20 | Rcpp::traits::input_parameter< int >::type trialType(trialTypeSEXP); 21 | Rcpp::traits::input_parameter< int >::type nTrials(nTrialsSEXP); 22 | Rcpp::traits::input_parameter< double >::type dt(dtSEXP); 23 | Rcpp::traits::input_parameter< double >::type var(varSEXP); 24 | rcpp_result_gen = Rcpp::wrap(getDSTP_new(parms, trialType, nTrials, dt, var)); 25 | return rcpp_result_gen; 26 | END_RCPP 27 | } 28 | // getSSP_new 29 | NumericMatrix getSSP_new(NumericVector parms, int trialType, int nTrials, double dt, double var); 30 | RcppExport SEXP _flankr_getSSP_new(SEXP parmsSEXP, SEXP trialTypeSEXP, SEXP nTrialsSEXP, SEXP dtSEXP, SEXP varSEXP) { 31 | BEGIN_RCPP 32 | Rcpp::RObject rcpp_result_gen; 33 | Rcpp::RNGScope rcpp_rngScope_gen; 34 | Rcpp::traits::input_parameter< NumericVector >::type parms(parmsSEXP); 35 | Rcpp::traits::input_parameter< int >::type trialType(trialTypeSEXP); 36 | Rcpp::traits::input_parameter< int >::type nTrials(nTrialsSEXP); 37 | Rcpp::traits::input_parameter< double >::type dt(dtSEXP); 38 | Rcpp::traits::input_parameter< double >::type var(varSEXP); 39 | rcpp_result_gen = Rcpp::wrap(getSSP_new(parms, trialType, nTrials, dt, var)); 40 | return rcpp_result_gen; 41 | END_RCPP 42 | } 43 | 44 | static const R_CallMethodDef CallEntries[] = { 45 | {"_flankr_getDSTP_new", (DL_FUNC) &_flankr_getDSTP_new, 5}, 46 | {"_flankr_getSSP_new", (DL_FUNC) &_flankr_getSSP_new, 5}, 47 | {NULL, NULL, 0} 48 | }; 49 | 50 | RcppExport void R_init_flankr(DllInfo *dll) { 51 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 52 | R_useDynamicSymbols(dll, FALSE); 53 | } 54 | -------------------------------------------------------------------------------- /man/caf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cafFunctions.R 3 | \name{caf} 4 | \alias{caf} 5 | \title{Find conditional accuracy function (CAF) values for a single condition} 6 | \usage{ 7 | caf(data, quantiles = c(0.25, 0.5, 0.75), multipleSubjects = TRUE) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame containing the data to be passed to the function. 11 | At the very least, the data frame must contain columns named "accuracy" 12 | logging the accuracy (1 for correct, 0 for error) and "rt" containing the 13 | response time data. If the user wishes to find the average CAFs across 14 | multiple subjects, then another column must be included ("subject") with 15 | numbers identifying unique subjects. See \code{?exampleData} for a data 16 | frame formatted correctly.} 17 | 18 | \item{quantiles}{The quantile values to be found by the function. By 19 | default, the function finds the accuracy for the .25, .5, and .75 quantiles.} 20 | 21 | \item{multipleSubjects}{Inform the function whether the data frame contains 22 | data from multiple subjects. If set to TRUE, the function returns the 23 | average CAF values across all subjects. If set to FALSE, the function 24 | assumes all data being passed is just from one subject.} 25 | } 26 | \value{ 27 | Returns a matrix with response time (row 1) and accuracy (row 2) for 28 | each quantile of CAF requested. 29 | } 30 | \description{ 31 | \code{caf} takes a data frame for a single experimental condition and 32 | returns a vector of requested conditional accuracy function (CAF) values. 33 | } 34 | \details{ 35 | The function only deals with one experimental condition. There is another 36 | function (\code{cafAll}) which will return CAFs for all experimental 37 | conditions. If there are more than one subject in the data frame being 38 | passed to this function, the function first finds the CAF values for each 39 | subject, and then takes the average for each quantile. This average is then 40 | returned to the user. 41 | } 42 | \examples{ 43 | ### example of multiple subjects and default quantile values 44 | 45 | # only select the congruent data from the example data set 46 | data <- subset(exampleData, exampleData$congruency == "congruent") 47 | 48 | # get the CDFs 49 | getCAF <- caf(data) 50 | 51 | #-- example of single subject and different quantile values 52 | 53 | # only select subject 1 from the example data. Also, select only the 54 | # "absent" condition and incongruent trials. This is an example when working 55 | # with multiple conditions (besides target congruency). 56 | data <- subset(exampleData, exampleData$subject == 1 & 57 | exampleData$condition == "absent" & 58 | exampleData$congruency == "incongruent") 59 | 60 | # set new quantile values 61 | newQuantiles <- c(.2, .4, .6, .8) 62 | 63 | # get the CAFs 64 | getCAF <- caf(data, quantiles = newQuantiles, multipleSubjects = FALSE) 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # flankr v1.2.0 5 | 6 | [![](http://www.r-pkg.org/badges/version/flankr)](https://CRAN.R-project.org/package=flankr) 7 | [![](http://cranlogs.r-pkg.org/badges/grand-total/flankr)](https://CRAN.R-project.org/package=lankr) 8 | 9 | $\texttt{flankr}$ is an R package implementing computational models of 10 | Eriksen flanker task performance. The package allows simulation of the 11 | models as well as fitting the models to participant data. Additional 12 | utility functions allow plotting of the best-fitting model parameters 13 | against observed data, as well as providing Bayesian Information 14 | Criterion values for model competition. 15 | 16 | Current models implemented in $\texttt{flankr}$ are: 17 | 18 | - The Shrinking Spotlight Model (SSP) of White et al. (2011) 19 | - The Dual-Stage Two-Phase Model (DSTP) of Hübner et al. (2010) 20 | 21 | ## Installation 22 | 23 | You can install the released version of flankr (v1.2.0) from 24 | [CRAN](https://CRAN.R-project.org/package=flankr) with: 25 | 26 | ``` r 27 | install.packages("flankr") 28 | ``` 29 | 30 | The development version (v1.2.0.9999) can be installed from 31 | [GitHub](https://github.com/) with: 32 | 33 | ``` r 34 | require(devtools) 35 | devtools::install_github("JimGrange/flankr") 36 | ``` 37 | 38 | ## User guide 39 | 40 | Full details of how to use the package is available in the following 41 | paper: 42 | 43 | Grange, J.A. (2016). flankr: An R package for implementing computational 44 | models of attentional selectivity. *Behavior Research Methods, 48,* 45 | 528–541. 46 | 47 | - PDF Link: 48 | 49 | 50 | ## Updates for version 1.2.0 51 | 52 | - 50% further efficiency in DSTP simulation speed from version 1.1.0. 53 | (Users who have only ever installed the initial release 1.0.0 will 54 | notice *significantly larger* improvements.) 55 | - 24% further efficiency in SSP simulation speed. (Users who have only 56 | ever installed the initial release 1.0.0 will notice *significantly 57 | larger* improvements.) 58 | - **Please note** that the way random seeds are now handled in both 59 | $\texttt{simulateDSTP}$ and $\texttt{simulateSSP}$ is slightly 60 | different to that in version 1.0.0 (initial release) and version 61 | 1.1.0. Therefore, there may be very slight differences between 62 | simulation data (and therefore potentially very slight differences in 63 | best-fitting parameter values) between versions. 64 | 65 | ## References 66 | 67 | - Hübner, R., Steinhauser, M., & Lehle, C. (2010). A dual-stage 68 | two-phase model of selective attention. *Psychological Review, 69 | 117(3)*, 759–784. 70 | - White, C. N., Ratcliff, R., & Starns, J. S. (2011). Diffusion models 71 | of the flanker task: Discrete versus gradual attentional selection. 72 | *Cognitive Psychology, 63(4)*, 210–238. 73 | 74 | -------------------------------------------------------------------------------- /man/cdf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cdfFunctions.R 3 | \name{cdf} 4 | \alias{cdf} 5 | \title{Find cumulative distribution function (CDF) values for a single condition} 6 | \usage{ 7 | cdf( 8 | data, 9 | quantiles = c(0.1, 0.3, 0.5, 0.7, 0.9), 10 | correctTrials = 1, 11 | multipleSubjects = TRUE 12 | ) 13 | } 14 | \arguments{ 15 | \item{data}{A data frame containing the data to be passed to the function. 16 | At the very least, the data frame must contain columns named "accuracy" 17 | logging the accuracy (1 for correct, 0 for error) and "rt" containing the 18 | response time data. If the user wishes to find the average CDFs across 19 | multiple subjects, then another column must be included ("subject") with 20 | numbers identifying unique subjects. See \code{?exampleData} for a data 21 | frame formatted correctly.} 22 | 23 | \item{quantiles}{The quantile values to be found by the function. By 24 | default, the function finds the .1, .3, .5, .7, and .9 CDF values.} 25 | 26 | \item{correctTrials}{If set to 1, the function will find the CDFs of 27 | correct trials. Set to 2 to find the CDFs of error trials. Set to 3 to find 28 | CDFs of ALL trials. Note, though, that CDFs of error trials may be less 29 | accurate due to usually-low number of error trials.} 30 | 31 | \item{multipleSubjects}{Inform the function whether the data frame contains 32 | data from multiple subjects. If set to TRUE, the function returns the 33 | average CDF values across all subjects. If set to FALSE, the function 34 | assumes all data being passed is just from one subject.} 35 | } 36 | \value{ 37 | Returns a vector of response times for each quantile of CDF 38 | requested. 39 | } 40 | \description{ 41 | \code{cdf} takes a data frame for a single experimental condition and 42 | returns a vector of requested CDF values. 43 | } 44 | \details{ 45 | The function only deals with one experimental condition. There is another 46 | function (\code{cdfAll}) which will return CDFs for all experimental 47 | conditions. If there are more than one subject in the data frame being 48 | passed to this function, the function first finds the CDF values for each 49 | subject, and then takes the average for each quantile. This average is then 50 | returned to the user. 51 | } 52 | \examples{ 53 | ### example of multiple subjects and default quantile values 54 | 55 | # only select the congruent data from the example data set 56 | data <- subset(exampleData, exampleData$congruency == "congruent") 57 | 58 | # get the CDFs 59 | getCDF <- cdf(data) 60 | 61 | ### example of single subject and different quantile values 62 | 63 | # only select subject 1 from the example data. Also, select only the 64 | # "absent" condition and incongruent trials. This is an example when working 65 | # with multiple conditions (besides target congruency). 66 | data <- subset(exampleData, exampleData$subject == 1 & 67 | exampleData$condition == "absent" & 68 | exampleData$congruency == "incongruent") 69 | 70 | # set new quantile values 71 | newQuantiles <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9) 72 | 73 | # get the CDFs 74 | getCDF <- cdf(data, quantiles = newQuantiles, multipleSubjects = FALSE) 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/simulateDSTP_new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace Rcpp; 4 | 5 | // [[Rcpp::export]] 6 | NumericMatrix getDSTP_new(NumericVector parms, 7 | int trialType, 8 | int nTrials, 9 | double dt, 10 | double var) { 11 | 12 | // initialise R's RNG (respects set.seed in R) 13 | Rcpp::RNGScope scope; 14 | 15 | double sdRand = sqrt(dt * var); 16 | double A = parms[0], B = -parms[0]; 17 | double C = parms[1], D = -parms[1]; 18 | double muTa = parms[2] * dt; 19 | double muFl = parms[3] * dt; 20 | double muSS = parms[4] * dt; 21 | double muRS2 = parms[5] * dt; 22 | double tEr = parms[6]; 23 | 24 | // pre-compute drift for first stage based on trial type 25 | double muResp = (trialType == 1) ? (muTa + muFl) : (muTa - muFl); 26 | 27 | // pre-generate all noise vectors 28 | int noiseLen = 10000; // keep original length for behaviour parity 29 | NumericVector muNoise = rnorm(noiseLen, muResp, sdRand); 30 | NumericVector rsNoise = rnorm(noiseLen, muRS2, sdRand); 31 | NumericVector ssNoise = rnorm(noiseLen, muSS, sdRand); 32 | 33 | // use raw pointers for fast access 34 | double* muNoisePtr = REAL(muNoise); 35 | double* rsNoisePtr = REAL(rsNoise); 36 | double* ssNoisePtr = REAL(ssNoise); 37 | 38 | NumericMatrix trialData(nTrials, 2); 39 | 40 | // initialise random number generator 41 | // now using R's RNG (no srand/rand; CRAN-friendly and reproducible with set.seed) 42 | 43 | // loop over trials 44 | for (int i = 0; i < nTrials; ++i) { 45 | 46 | // reset everything 47 | double currEvidenceResp = 0.0; 48 | double currEvidenceStim = 0.0; 49 | int whichStim = 0; 50 | bool stimSelected = false; 51 | int j = 0; 52 | 53 | // diffusion process starts here 54 | while (currEvidenceResp <= A && currEvidenceResp >= B) { 55 | 56 | // select random noise 57 | // uniform index in [0, noiseLen) 58 | int idx = static_cast(R::unif_rand() * noiseLen); 59 | 60 | // update the response drift rates based on 61 | // stimulus selection status 62 | if (!stimSelected) { 63 | currEvidenceResp += muNoisePtr[idx]; 64 | } else { 65 | double delta = rsNoisePtr[idx]; 66 | // apply multiplier for when flanker is selected on incongruent trials 67 | if (trialType == 2 && whichStim == 2) { 68 | delta = -delta; 69 | } 70 | currEvidenceResp += delta; 71 | } 72 | 73 | // update the stimulus selection drift rate 74 | currEvidenceStim += ssNoisePtr[idx]; 75 | 76 | // check whether stimulus selection has occurred 77 | if (!stimSelected) { 78 | if (currEvidenceStim >= C) { 79 | whichStim = 1; 80 | stimSelected = true; 81 | } else if (currEvidenceStim <= D) { 82 | whichStim = 2; 83 | stimSelected = true; 84 | } 85 | } 86 | 87 | ++j; 88 | } 89 | 90 | // collate trial level data 91 | trialData(i, 0) = (j * dt) + tEr; 92 | trialData(i, 1) = (currEvidenceResp >= A) ? 1.0 : 0.0; 93 | } 94 | 95 | return trialData; 96 | } 97 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # flankr v1.2.0 17 | 18 | [![](http://www.r-pkg.org/badges/version/flankr)](https://CRAN.R-project.org/package=flankr) 19 | [![](http://cranlogs.r-pkg.org/badges/grand-total/flankr)](https://CRAN.R-project.org/package=lankr) 20 | 21 | $\texttt{flankr}$ is an R package implementing computational models of Eriksen flanker task performance. The package allows simulation of the models as well as fitting the models to participant data. Additional utility functions allow plotting of the best-fitting model parameters against observed data, as well as providing Bayesian Information Criterion values for model competition. 22 | 23 | Current models implemented in $\texttt{flankr}$ are: 24 | 25 | * The Shrinking Spotlight Model (SSP) of White et al. (2011) 26 | * The Dual-Stage Two-Phase Model (DSTP) of Hübner et al. (2010) 27 | 28 | ## Installation 29 | 30 | You can install the released version of flankr (v1.2.0) from 31 | [CRAN](https://CRAN.R-project.org/package=flankr) with: 32 | 33 | ``` r 34 | install.packages("flankr") 35 | ``` 36 | 37 | The development version (v1.2.0.9999) can be installed from [GitHub](https://github.com/) with: 38 | 39 | ``` {r, eval = FALSE} 40 | require(devtools) 41 | devtools::install_github("JimGrange/flankr") 42 | ``` 43 | 44 | ## User guide 45 | Full details of how to use the package is available in the following paper: 46 | 47 | Grange, J.A. (2016). flankr: An R package for implementing computational models of attentional selectivity. *Behavior Research Methods, 48,* 528–541. 48 | 49 | * PDF Link: [https://link.springer.com/article/10.3758/s13428-015-0615-y](https://link.springer.com/article/10.3758/s13428-015-0615-y) 50 | 51 | ## Updates for version 1.2.0 52 | * 50% further efficiency in DSTP simulation speed from version 1.1.0. (Users who have only ever installed the initial release 1.0.0 will notice *significantly larger* improvements.) 53 | * 24% further efficiency in SSP simulation speed. (Users who have only ever installed the initial release 1.0.0 will notice *significantly larger* improvements.) 54 | * **Please note** that the way random seeds are now handled in both $\texttt{simulateDSTP}$ and $\texttt{simulateSSP}$ is slightly different to that in version 1.0.0 (initial release) and version 1.1.0. Therefore, there may be very slight differences between simulation data (and therefore potentially very slight differences in best-fitting parameter values) between versions. 55 | 56 | 57 | ## References 58 | * Hübner, R., Steinhauser, M., & Lehle, C. (2010). A dual-stage two-phase model of selective attention. *Psychological Review, 117(3)*, 759–784. https://doi.org/10.1037/a0019471 59 | * White, C. N., Ratcliff, R., & Starns, J. S. (2011). Diffusion models of the flanker task: Discrete versus gradual attentional selection. *Cognitive Psychology, 63(4)*, 210–238. https://doi.org/10.1016/j.cogpsych.2011.08.001 60 | 61 | -------------------------------------------------------------------------------- /man/fitSSP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sspFunctions.R, R/zzz_aliases.R 3 | \name{fitSSP} 4 | \alias{fitSSP} 5 | \alias{fit_ssp} 6 | \title{Fit the SSP model to human data} 7 | \usage{ 8 | fitSSP( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 12 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 13 | cafs = c(0.25, 0.5, 0.75), 14 | maxParms = c(1, 1, 1, 1, 3), 15 | nTrials = 50000, 16 | multipleSubjects = TRUE, 17 | seed = NULL 18 | ) 19 | 20 | fit_ssp( 21 | data, 22 | conditionName = NULL, 23 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 24 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 25 | cafs = c(0.25, 0.5, 0.75), 26 | maxParms = c(1, 1, 1, 1, 3), 27 | nTrials = 50000, 28 | multipleSubjects = TRUE, 29 | seed = NULL 30 | ) 31 | } 32 | \arguments{ 33 | \item{data}{A data frame containing human data. See \code{?exampleData} for 34 | data formatted correctly.} 35 | 36 | \item{conditionName}{If there is an additional experimental manipulation 37 | (i.e., other than target congruency) the model can only be fit to one at a 38 | time. Tell the function which condition is currently being fit by passing 39 | a string to the function (e.g., "present"). The function by default assumes 40 | no additional condition (e.g., conditionName is set to NULL).} 41 | 42 | \item{parms}{A vector of starting parameters to use in the minimisation 43 | routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 44 | \code{sda}.} 45 | 46 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 47 | to be estimated from the human data. The model will attempt to find the 48 | best-fitting parameters that match this distributional data.} 49 | 50 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 51 | estimated from the human data. The model will attempt to find the best- 52 | fitting parameters that match this distributional data.} 53 | 54 | \item{maxParms}{A vector containing upper limits on possible parameter 55 | values.} 56 | 57 | \item{nTrials}{An integer stating how many trials to simulate per iteration 58 | of the fitting cycle for each congruency type.} 59 | 60 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 61 | subjects (multipleSubjects = TRUE) or to a single subject 62 | (multipleSubjects = FALSE).} 63 | 64 | \item{seed}{The value for the \code{set.seed} function to set random 65 | generation state.} 66 | } 67 | \value{ 68 | \code{bestParameters} A vector of the best-fitting parameters found 69 | by the current fit run. 70 | 71 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 72 | current fit run. 73 | 74 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 75 | obtained by the current fit run. This is calculated using the BIC equation 76 | for binned data, hence bBIC (binned BIC). 77 | } 78 | \description{ 79 | \code{fitSSP} fits the SSP model to a single experimental condition of 80 | human data (besides congruency, which it accounts for simutaneously). 81 | } 82 | \details{ 83 | This function can be employed by the user to find the best-fitting 84 | parameters of the SSP model to fit the human data of a single experimental 85 | condition. The fitting procedure accounts for congruent and incongruent 86 | trials simultaneously. The fit is obtained by a gradient-descent method 87 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 88 | fit to the proportion of data contained in human CDF and CAF distributional 89 | data. 90 | } 91 | \examples{ 92 | # Load the example data the comes with the \code{flankr} package 93 | data(exampleData) 94 | 95 | # Fit the model to the condition "present" in the example data set using 96 | # the default settings in the model. 97 | # (Note this is a toy example with very low trial numbers to speed up the 98 | # example. For proper use, increase nTrials.) 99 | fit <- fitSSP(data = exampleData, conditionName = "present", nTrials = 100) 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/legacy/simulateSSP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | 6 | using namespace Rcpp; 7 | 8 | // [[Rcpp::export]] 9 | NumericMatrix getSSP(NumericVector parms, int trialType, int nTrials, 10 | double dt, double var) { 11 | 12 | //trialType: 1 = congruent, 2 = incongruent 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | ////////////////////////////////////////////////////////////////////////////// 16 | //set fixed parameters 17 | double sdRand = sqrt(dt * var); //get standard deviation from variance 18 | 19 | //get the free parameters from the numeric vector parms 20 | double A = parms[0]; 21 | double B = -parms[0]; 22 | double tEr = parms[1]; 23 | double p = parms[2]; 24 | double rd = parms[3]; 25 | double sda = parms[4]; 26 | 27 | //declare random number variable for noise 28 | double noise = 0.0; 29 | 30 | //set empty matrix to store trial data 31 | int nRow = nTrials; //first set number of rows 32 | NumericMatrix trialData(nRow, 2); //set the matrix. 2 columns (RT & accuracy) 33 | 34 | //keep track of current evidence (response selection) 35 | double currEvidenceResp = 0.0; 36 | double t = 0.0; //to log number of diffusion steps 37 | double drift = 0.0; //the drift rate for the current moment 38 | 39 | 40 | //declare trial-specific parameters 41 | double p_target = 0.0; 42 | double p_flanker = 0.0; 43 | 44 | //get perceptual input for targets and flanker 45 | p_target = p; 46 | p_flanker = p; 47 | 48 | // flip the sign if current trial is incongruent 49 | if(trialType == 2){ 50 | p_flanker = -p_flanker; 51 | } 52 | 53 | 54 | // pre-compute sd(t) vector, and from it the attentional areas 55 | // over target and flankers 56 | int m = 20000; // m needs to be larger than maximum expexted RT for the model 57 | NumericVector sd_t_vec(m); 58 | NumericVector a_target_vec(m); 59 | NumericVector a_flanker_vec(m); 60 | NumericVector mu_target_vec(m); 61 | NumericVector mu_flanker_vec(m); 62 | 63 | for(int t = 0; t < m; ++t) { 64 | sd_t_vec[t] = sda - (rd * t); 65 | if(sd_t_vec[t] <= 0.001) { 66 | sd_t_vec[t] = 0.001; 67 | } 68 | 69 | // attentional spotlights 70 | a_target_vec[t] = ::Rf_pnorm5(0.5, 0.0, sd_t_vec[t], 1, 0) - ::Rf_pnorm5(-0.5, 0.0, sd_t_vec[t], 1, 0); 71 | a_flanker_vec[t] = ::Rf_pnorm5(10.0, 0.0, sd_t_vec[t], 1, 0) - ::Rf_pnorm5(0.5, 0.0, sd_t_vec[t], 1, 0); 72 | 73 | // drift rate contributions from the target and the flankers 74 | mu_target_vec[t] = (p_target * a_target_vec[t]) * dt; 75 | mu_flanker_vec[t] = ((2 * p_flanker) * a_flanker_vec[t]) * dt; 76 | 77 | } 78 | 79 | 80 | ////////////////////////////////////////////////////////////////////////////// 81 | ////////////////////////////////////////////////////////////////////////////// 82 | 83 | 84 | ////////////////////////////////////////////////////////////////////////////// 85 | //start trial loop here 86 | for (int i=0; i<=nTrials - 1; i++){ 87 | 88 | //keep track of the current evidence (response selection) 89 | currEvidenceResp = 0.0; 90 | 91 | //reset counter to log how many steps taken in diffusion process 92 | t = 0.0; 93 | 94 | //diffusion simulation starts here 95 | while((currEvidenceResp <= A) && (currEvidenceResp >= B)){ 96 | 97 | //current drift rate 98 | drift = mu_flanker_vec[t] + mu_target_vec[t]; 99 | 100 | //get random noise 101 | noise = ::Rf_rnorm(drift, sdRand); 102 | 103 | //update the response selection random walk 104 | currEvidenceResp = currEvidenceResp + noise; 105 | 106 | //update diffusion step number 107 | t++; 108 | 109 | } // while loop ends here 110 | 111 | trialData(i, 0) = (t * dt) + tEr; 112 | 113 | 114 | if(currEvidenceResp >= A){ 115 | trialData(i, 1) = 1; 116 | } 117 | 118 | if(currEvidenceResp <= B){ 119 | trialData(i, 1) = 0; 120 | } 121 | 122 | } // trial loop ends here 123 | return trialData; 124 | } 125 | -------------------------------------------------------------------------------- /man/fitDSTP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dstpFunctions.R, R/zzz_aliases.R 3 | \name{fitDSTP} 4 | \alias{fitDSTP} 5 | \alias{fit_dstp} 6 | \title{Fit the DSTP model to human data} 7 | \usage{ 8 | fitDSTP( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 12 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 13 | cafs = c(0.25, 0.5, 0.75), 14 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 15 | nTrials = 50000, 16 | multipleSubjects = TRUE, 17 | seed = NULL 18 | ) 19 | 20 | fit_dstp( 21 | data, 22 | conditionName = NULL, 23 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 24 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 25 | cafs = c(0.25, 0.5, 0.75), 26 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 27 | nTrials = 50000, 28 | multipleSubjects = TRUE, 29 | seed = NULL 30 | ) 31 | } 32 | \arguments{ 33 | \item{data}{A data frame containing human data. See \code{?exampleData} for 34 | data formatted correctly.} 35 | 36 | \item{conditionName}{If there is an additional experimental manipulation 37 | (i.e., other than target congruency) the model can only be fit to one at a 38 | time. Tell the function which condition is currently being fit by passing 39 | a string to the function (e.g., "present"). The function by default assumes 40 | no additional condition (e.g., conditionName is set to NULL).} 41 | 42 | \item{parms}{A vector of starting parameters to use in the minimisation 43 | routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 44 | \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}.} 45 | 46 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 47 | to be estimated from the human data. The model will attempt to find the 48 | best-fitting parameters that match this distributional data.} 49 | 50 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 51 | estimated from the human data. The model will attempt to find the best- 52 | fitting parameters that match this distributional data.} 53 | 54 | \item{maxParms}{A vector containing upper limits on possible parameter 55 | values.} 56 | 57 | \item{nTrials}{An integer stating how many trials to simulate per iteration 58 | of the fitting cycle for each congruency type.} 59 | 60 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 61 | subjects (multipleSubjects = TRUE) or to a single subject 62 | (multipleSubjects = FALSE).} 63 | 64 | \item{seed}{The value for the \code{set.seed} function to set random 65 | generation state.} 66 | } 67 | \value{ 68 | \code{bestParameters} A vector of the best-fitting parameters found 69 | by the current fit run. 70 | 71 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 72 | current fit run. 73 | 74 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 75 | obtained by the current fit run. This is calculated using the BIC equation 76 | for binned data, hence bBIC (binned BIC). 77 | } 78 | \description{ 79 | \code{fitDSTP} fits the DSTP model to a single experimental condition of 80 | human data (besides congruency, which it accounts for simutaneously). 81 | } 82 | \details{ 83 | This function can be employed by the user to find the best-fitting 84 | parameters of the DSTP model to fit the human data of a single experimental 85 | condition. The fitting procedure accounts for congruent and incongruent 86 | trials simultaneously. The fit is obtained by a gradient-descent method 87 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 88 | fit to the proportion of data contained in human CDF and CAF distributional 89 | data. 90 | } 91 | \examples{ 92 | # Load the example data the comes with the \code{flankr} package 93 | data(exampleData) 94 | 95 | # Fit the model to the condition "present" in the example data set using 96 | # the default settings in the model. 97 | # (Note this is a toy example with very low trial numbers to speed up the 98 | # example. For proper use, increase nTrials.) 99 | \donttest{ 100 | fit <- fitDSTP(data = exampleData, conditionName = "present", nTrials = 100) 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /man/plotFitSSP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting.R, R/zzz_aliases.R 3 | \name{plotFitSSP} 4 | \alias{plotFitSSP} 5 | \alias{plot_fit_ssp} 6 | \title{Plot the fit of the SSP model to human data.} 7 | \usage{ 8 | plotFitSSP( 9 | modelFit, 10 | data, 11 | conditionName = NULL, 12 | nTrials = 50000, 13 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 14 | cafs = c(0.25, 0.5, 0.75), 15 | multipleSubjects = TRUE, 16 | seed = NULL 17 | ) 18 | 19 | plot_fit_ssp( 20 | modelFit, 21 | data, 22 | conditionName = NULL, 23 | nTrials = 50000, 24 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 25 | cafs = c(0.25, 0.5, 0.75), 26 | multipleSubjects = TRUE, 27 | seed = NULL 28 | ) 29 | } 30 | \arguments{ 31 | \item{modelFit}{The object obtained by the model fit.} 32 | 33 | \item{data}{The data frame of human data.} 34 | 35 | \item{conditionName}{The name of the condition that was fit. By default, 36 | it is set to conditionName = NULL.} 37 | 38 | \item{nTrials}{How many trials used to generate the model's best 39 | predictions. This should be higher than that used to fit the model.} 40 | 41 | \item{cdfs}{The cut-off points for the cumulative distribution functions.} 42 | 43 | \item{cafs}{The cut-off points for the conditional accuracy functions.} 44 | 45 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 46 | subjects (multipleSubjects = TRUE) or to a single subject 47 | (multipleSubjects = FALSE).} 48 | 49 | \item{seed}{The value for the \code{set.seed} function to set random 50 | generation state.} 51 | } 52 | \value{ 53 | \code{cdfs} The CDF values requested by the user. 54 | 55 | \code{cafs} The CAF values requested by the user. 56 | 57 | \code{humanConCDFs} The response time cut-off values for each CDF 58 | bin for congruent human data. 59 | 60 | \code{humanInconCDFs} The response time cut-off values for each CDF 61 | bin for incongruent human data. 62 | 63 | \code{humanConCAFsRT} The mean response times for each bin of the 64 | CAF functions for congruent human data. 65 | 66 | \code{humanInconCAFsRT} The mean response times for each bin of the 67 | CAF functions for incongruent human data. 68 | 69 | \code{humanConCAFsError} The percent accuracy for each bin of the 70 | CAF functions for congruent human data. 71 | 72 | \code{humanConCAFsError} The percent accuracy for each bin of the 73 | CAF functions for congruent human data. 74 | 75 | \code{modelConCDFs} The quantile cut-off points for the model 76 | predictions for congruent data. A perfect fit would match the cdfs asked 77 | for by the user (e.g., .1, .3, .5, .7, .9). 78 | 79 | \code{modelInconCDFs} The quantile cut-off points for the model 80 | predictions for incongruent data. A perfect fit would match the cdfs asked 81 | for by the user (e.g., .1, .3, .5, .7, .9). 82 | 83 | \code{modelConCAFs} The percentage accuracy predicted for each CAF 84 | bin by the model for congruent data. 85 | 86 | \code{modelInconCAFs} The percentage accuracy predicted for each CAF 87 | bin by the model for incongruent data. 88 | } 89 | \description{ 90 | \code{plotFitSSP} will plot the fit of the model to human distributional 91 | data. 92 | } 93 | \details{ 94 | This function is passed the object obtained by the model fitting procedure, 95 | as well as the human data and the condition that was fitted by the routine. 96 | The function simulates 100,000 trials (by default) using the best-fitting 97 | parameters found by the fit procedure. This synthetic data is then considered 98 | as the model's best predictions. The function then provides a plot of the 99 | model fit to cumulative distribution functions (CDFs) of correct response 100 | time, and conditional accuracy functions (CAFs) to show fit to accuracy data. 101 | The function also returns the data used to plot the fit so that the user can 102 | use their own plotting methods. 103 | } 104 | \examples{ 105 | # Assume that the model was just fit to the data contained in 106 | # \code{exampleData} (condition "present") and saved to the variable called 107 | # "fit", then we can obtain a plot of that fit by using the following: 108 | # (Note this is a toy example with very low trial numbers to speed up the 109 | # example. For proper use, increase nTrials.) 110 | fit <- fitSSP(data = exampleData, conditionName = "present", nTrials = 100) 111 | plot <- plotFitSSP(modelFit = fit, data = exampleData, 112 | conditionName = "present", nTrials = 100) 113 | 114 | } 115 | -------------------------------------------------------------------------------- /man/plotFitDSTP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotting.R, R/zzz_aliases.R 3 | \name{plotFitDSTP} 4 | \alias{plotFitDSTP} 5 | \alias{plot_fit_dstp} 6 | \title{Plot the fit of the DSTP model to human data.} 7 | \usage{ 8 | plotFitDSTP( 9 | modelFit, 10 | data, 11 | conditionName = NULL, 12 | nTrials = 50000, 13 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 14 | cafs = c(0.25, 0.5, 0.75), 15 | multipleSubjects = TRUE, 16 | seed = NULL 17 | ) 18 | 19 | plot_fit_dstp( 20 | modelFit, 21 | data, 22 | conditionName = NULL, 23 | nTrials = 50000, 24 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 25 | cafs = c(0.25, 0.5, 0.75), 26 | multipleSubjects = TRUE, 27 | seed = NULL 28 | ) 29 | } 30 | \arguments{ 31 | \item{modelFit}{The object obtained by the model fit.} 32 | 33 | \item{data}{The data frame of human data.} 34 | 35 | \item{conditionName}{The name of the condition that was fit. By default, 36 | it is set to conditionName = NULL.} 37 | 38 | \item{nTrials}{How many trials used to generate the model's best 39 | predictions. This should be higher than that used to fit the model.} 40 | 41 | \item{cdfs}{The cut-off points for the cumulative distribution functions.} 42 | 43 | \item{cafs}{The cut-off points for the conditional accuracy functions.} 44 | 45 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 46 | subjects (multipleSubjects = TRUE) or to a single subject 47 | (multipleSubjects = FALSE).} 48 | 49 | \item{seed}{The value for the \code{set.seed} function to set random 50 | generation state.} 51 | } 52 | \value{ 53 | \code{cdfs} The CDF values requested by the user. 54 | 55 | \code{cafs} The CAF values requested by the user. 56 | 57 | \code{humanConCDFs} The response time cut-off values for each CDF 58 | bin for congruent human data. 59 | 60 | \code{humanInconCDFs} The response time cut-off values for each CDF 61 | bin for incongruent human data. 62 | 63 | \code{humanConCAFsRT} The mean response times for each bin of the 64 | CAF functions for congruent human data. 65 | 66 | \code{humanInconCAFsRT} The mean response times for each bin of the 67 | CAF functions for incongruent human data. 68 | 69 | \code{humanConCAFsError} The percent accuracy for each bin of the 70 | CAF functions for congruent human data. 71 | 72 | \code{humanConCAFsError} The percent accuracy for each bin of the 73 | CAF functions for congruent human data. 74 | 75 | \code{modelConCDFs} The quantile cut-off points for the model 76 | predictions for congruent data. A perfect fit would match the cdfs asked 77 | for by the user (e.g., .1, .3, .5, .7, .9). 78 | 79 | \code{modelInconCDFs} The quantile cut-off points for the model 80 | predictions for incongruent data. A perfect fit would match the cdfs asked 81 | for by the user (e.g., .1, .3, .5, .7, .9). 82 | 83 | \code{modelConCAFs} The percentage accuracy predicted for each CAF 84 | bin by the model for congruent data. 85 | 86 | \code{modelInconCAFs} The percentage accuracy predicted for each CAF 87 | bin by the model for incongruent data. 88 | } 89 | \description{ 90 | \code{plotFitDSTP} will plot the fit of the model to human distributional 91 | data. 92 | } 93 | \details{ 94 | This function is passed the object obtained by the model fitting procedure, 95 | as well as the human data and the condition that was fitted by the routine. 96 | The function simulates 100,000 trials (by default) using the best-fitting 97 | parameters found by the fit procedure. This synthetic data is then considered 98 | as the model's best predictions. The function then provides a plot of the 99 | model fit to cumulative distribution functions (CDFs) of correct response 100 | time, and conditional accuracy functions (CAFs) to show fit to accuracy data. 101 | The function also returns the data used to plot the fit so that the user can 102 | use their own plotting methods. 103 | } 104 | \examples{ 105 | # Assume that the model was just fit to the data contained in 106 | # \code{exampleData} (condition "present") and saved to the variable called 107 | # "fit", then we can obtain a plot of that fit by using the following: 108 | # (Note this is a toy example with very low trial numbers to speed up the 109 | # example. For proper use, increase nTrials.) 110 | fit <- fitDSTP(data = exampleData, conditionName = "present", nTrials = 100) 111 | plot <- plotFitDSTP(modelFit = fit, data = exampleData, 112 | conditionName = "present", nTrials = 100) 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/legacy/simulateDSTP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Rcpp; 4 | 5 | // @export 6 | // [[Rcpp::export]] 7 | 8 | NumericMatrix getDSTP(NumericVector parms, int trialType, int nTrials, 9 | double dt, double var) { 10 | 11 | //trialType: 1 = congruent, 2 = incongruent 12 | 13 | //set fixed parameters 14 | // double dt = 0.001; //time per step of diffusion process 15 | // double var = 0.01; 16 | double sdRand = sqrt(dt * var); 17 | 18 | //get the free parameters from the numeric vector parms 19 | double A = parms[0]; // correct response selection boundary 20 | double B = -parms[0]; // error response selection boundary 21 | double C = parms[1]; // target stimulus selection boundary 22 | double D = -parms[1]; // flanker stimulus selection boundary 23 | double muTa = parms[2] * dt; // drift for target 24 | double muFl = parms[3] * dt; // drift for flanker 25 | double muSS = parms[4] * dt; // drift for stimulus selection 26 | double muRS2 = parms[5] * dt; // drift for second stage of response selection 27 | double tEr = parms[6]; // non-decision time 28 | 29 | 30 | //declare random number variables for noise 31 | NumericVector muNoise; 32 | if(trialType == 1){ 33 | muNoise = rnorm(10000, (muTa + muFl), sdRand); 34 | } else { 35 | muNoise = rnorm(10000, (muTa + -muFl), sdRand); 36 | } 37 | 38 | NumericVector rsNoise = rnorm(10000, muRS2, sdRand); 39 | NumericVector ssNoise = rnorm(10000, muSS, sdRand); 40 | 41 | int randomIndex; 42 | srand (1); 43 | 44 | //set empty matrix to store trial data 45 | int nRow = nTrials; //first set number of rows 46 | NumericMatrix trialData(nRow, 2); //set the matrix. 2 columns (RT & accuracy) 47 | 48 | //initialise trial flags etc. for whether certain processes have finished 49 | //during diffusion 50 | bool stimSelected = false; //has stimulus been selected? 51 | 52 | int whichStim; //to flag whether target (1) or flanker (2) has been selected 53 | double currEvidenceResp = 0.0; //keep track of evidence (response selection) 54 | double currEvidenceStim = 0.0; //keep track of evidence (stimulus selection) 55 | double j = 0.0; //to log number of diffusion steps 56 | 57 | 58 | 59 | //start trial loop here 60 | 61 | for (int i=0; i<=nTrials - 1; i++){ 62 | 63 | //reset stim selection to false 64 | stimSelected = false; 65 | 66 | //reset some trial parameters 67 | //which stim was selected by the stimulus drift (target [1] / flanker [2])? 68 | whichStim = 0; 69 | 70 | //keep track of the current evidence (response selection) 71 | currEvidenceResp = 0.0; 72 | 73 | //keep track of the current evidence (Stimulus selection) 74 | currEvidenceStim = 0.0; 75 | 76 | //reset counter to log how many steps taken in diffusion process 77 | j = 0.0; 78 | 79 | 80 | //## 81 | //diffusion simulation starts here 82 | while((currEvidenceResp <= A) && (currEvidenceResp >= B)){ 83 | 84 | randomIndex = rand() % muNoise.size(); 85 | 86 | //set the correct drift rate 87 | if (stimSelected == false){ 88 | currEvidenceResp = currEvidenceResp + muNoise[randomIndex]; 89 | } 90 | 91 | 92 | if((stimSelected == true) && (trialType == 2)){ 93 | if(whichStim == 1){ 94 | currEvidenceResp = currEvidenceResp + rsNoise[randomIndex]; 95 | } 96 | if(whichStim == 2){ 97 | currEvidenceResp = currEvidenceResp + -rsNoise[randomIndex]; 98 | } 99 | } 100 | 101 | if((stimSelected == true) && (trialType == 1)){ 102 | currEvidenceResp = currEvidenceResp + rsNoise[randomIndex]; 103 | } 104 | 105 | //update the stimulus selection drift rate 106 | currEvidenceStim = currEvidenceStim + ssNoise[randomIndex]; 107 | 108 | //has stimulus selection finished?? 109 | if(currEvidenceStim >= C){ 110 | whichStim = 1; 111 | stimSelected = true; 112 | } 113 | 114 | if(currEvidenceStim <= D){ 115 | whichStim = 2; 116 | stimSelected = true; 117 | } 118 | 119 | //update diffusion step number 120 | j++; 121 | 122 | } // while loop ends here 123 | 124 | trialData(i, 0) = (j * dt) + tEr; 125 | 126 | 127 | if(currEvidenceResp >= A){ 128 | trialData(i, 1) = 1; 129 | } 130 | else 131 | { 132 | trialData(i, 1) = 0; 133 | } 134 | 135 | } // trial loop ends here 136 | return trialData; 137 | } 138 | -------------------------------------------------------------------------------- /man/fitSSP_fixed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sspFunctions.R, R/zzz_aliases.R 3 | \name{fitSSP_fixed} 4 | \alias{fitSSP_fixed} 5 | \alias{fit_ssp_fixed} 6 | \title{Fit the SSP model to human data with some fixed parameters} 7 | \usage{ 8 | fitSSP_fixed( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 12 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 13 | cafs = c(0.25, 0.5, 0.75), 14 | maxParms = c(1, 1, 1, 1, 2), 15 | nTrials = 50000, 16 | multipleSubjects = TRUE, 17 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE), 18 | seed = NULL 19 | ) 20 | 21 | fit_ssp_fixed( 22 | data, 23 | conditionName = NULL, 24 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 25 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 26 | cafs = c(0.25, 0.5, 0.75), 27 | maxParms = c(1, 1, 1, 1, 2), 28 | nTrials = 50000, 29 | multipleSubjects = TRUE, 30 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE), 31 | seed = NULL 32 | ) 33 | } 34 | \arguments{ 35 | \item{data}{A data frame containing human data. See \code{?exampleData} for 36 | data formatted correctly.} 37 | 38 | \item{conditionName}{If there is an additional experimental manipulation 39 | (i.e., other than target congruency) the model can only be fit to one at a 40 | time. Tell the function which condition is currently being fit by passing 41 | a string to the function (e.g., "present"). The function by default assumes 42 | no additional condition (e.g., conditionName is set to NULL).} 43 | 44 | \item{parms}{A vector of starting parameters to use in the minimisation 45 | routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 46 | \code{sda}.} 47 | 48 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 49 | to be estimated from the human data. The model will attempt to find the 50 | best-fitting parameters that match this distributional data.} 51 | 52 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 53 | estimated from the human data. The model will attempt to find the best- 54 | fitting parameters that match this distributional data.} 55 | 56 | \item{maxParms}{A vector containing upper limits on possible parameter 57 | values.} 58 | 59 | \item{nTrials}{An integer stating how many trials to simulate per iteration 60 | of the fitting cycle for each congruency type.} 61 | 62 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 63 | subjects (multipleSubjects = TRUE) or to a single subject 64 | (multipleSubjects = FALSE).} 65 | 66 | \item{fixed}{A vector of TRUE/FALSE stating whether each parameter should be 67 | fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 68 | order: \code{A}, \code{ter}, \code{p}, \code{rd}, \code{sda}.} 69 | 70 | \item{seed}{The value for the \code{set.seed} function to set random 71 | generation state.} 72 | } 73 | \value{ 74 | \code{bestParameters} A vector of the best-fitting parameters found 75 | by the current fit run. 76 | 77 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 78 | current fit run. 79 | 80 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 81 | obtained by the current fit run. This is calculated using the BIC equation 82 | for binned data, hence bBIC (binned BIC). 83 | } 84 | \description{ 85 | \code{fitSSP_fixed} fits the SSP model to a single experimental condition of 86 | human data (besides congruency, which it accounts for simutaneously). This 87 | function allows the user to fix some parameters (using the \code{fixed} 88 | variable). 89 | } 90 | \details{ 91 | This function can be employed by the user to find the best-fitting 92 | parameters of the SSP model to fit the human data of a single experimental 93 | condition. The fitting procedure accounts for congruent and incongruent 94 | trials simultaneously. The fit is obtained by a gradient-descent method 95 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 96 | fit to the proportion of data contained in human CDF and CAF distributional 97 | data. 98 | } 99 | \examples{ 100 | # Load the example data the comes with the \code{flankr} package 101 | data(exampleData) 102 | # Fix the first parameter (A) during the fit. 103 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500) 104 | fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE) 105 | 106 | # fit the model 107 | # (Note this is a toy example with very low trial numbers to speed up the 108 | # example. For proper use, increase nTrials.) 109 | \donttest{ 110 | fit <- fitSSP_fixed(exampleData, conditionName = "present", parms = parms, 111 | fixed = fixed, nTrials = 100) 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /man/fitDSTP_fixed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dstpFunctions.R, R/zzz_aliases.R 3 | \name{fitDSTP_fixed} 4 | \alias{fitDSTP_fixed} 5 | \alias{fit_dstp_fixed} 6 | \title{Fit the DSTP model to human data with some fixed parameters} 7 | \usage{ 8 | fitDSTP_fixed( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 12 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 13 | cafs = c(0.25, 0.5, 0.75), 14 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 15 | nTrials = 50000, 16 | multipleSubjects = TRUE, 17 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE), 18 | seed = NULL 19 | ) 20 | 21 | fit_dstp_fixed( 22 | data, 23 | conditionName = NULL, 24 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 25 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 26 | cafs = c(0.25, 0.5, 0.75), 27 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 28 | nTrials = 50000, 29 | multipleSubjects = TRUE, 30 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE), 31 | seed = NULL 32 | ) 33 | } 34 | \arguments{ 35 | \item{data}{A data frame containing human data. See \code{?exampleData} for 36 | data formatted correctly.} 37 | 38 | \item{conditionName}{If there is an additional experimental manipulation 39 | (i.e., other than target congruency) the model can only be fit to one at a 40 | time. Tell the function which condition is currently being fit by passing 41 | a string to the function (e.g., "present"). The function by default assumes 42 | no additional condition (e.g., conditionName is set to NULL).} 43 | 44 | \item{parms}{A vector of starting parameters to use in the minimisation 45 | routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 46 | \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}.} 47 | 48 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 49 | to be estimated from the human data. The model will attempt to find the 50 | best-fitting parameters that match this distributional data.} 51 | 52 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 53 | estimated from the human data. The model will attempt to find the best- 54 | fitting parameters that match this distributional data.} 55 | 56 | \item{maxParms}{A vector containing upper limits on possible parameter 57 | values.} 58 | 59 | \item{nTrials}{An integer stating how many trials to simulate per iteration 60 | of the fitting cycle for each congruency type.} 61 | 62 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 63 | subjects (multipleSubjects = TRUE) or to a single subject 64 | (multipleSubjects = FALSE).} 65 | 66 | \item{fixed}{A vector of TRUE/FALSE stating whether each parameter should be 67 | fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 68 | order: \code{A}, \code{C}, \code{driftTarget}, \code{driftFlanker}, 69 | \code{diftStimSelection}, \code{driftRS2}, \code{ter}.} 70 | 71 | \item{seed}{The value for the \code{set.seed} function to set random 72 | generation state.} 73 | } 74 | \value{ 75 | \code{bestParameters} A vector of the best-fitting parameters found 76 | by the current fit run. 77 | 78 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 79 | current fit run. 80 | 81 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 82 | obtained by the current fit run. This is calculated using the BIC equation 83 | for binned data, hence bBIC (binned BIC). 84 | } 85 | \description{ 86 | \code{fitDSTP_fixed} fits the DSTP model to a single experimental condition 87 | of human data (besides congruency, which it accounts for simutaneously). 88 | This function allows the user to fix some parameters (using the \code{fixed} 89 | variable). 90 | } 91 | \details{ 92 | This function can be employed by the user to find the best-fitting 93 | parameters of the DSTP model to fit the human data of a single experimental 94 | condition. The fitting procedure accounts for congruent and incongruent 95 | trials simultaneously. The fit is obtained by a gradient-descent method 96 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 97 | fit to the proportion of data contained in human CDF and CAF distributional 98 | data. 99 | } 100 | \examples{ 101 | # Load the example data the comes with the \code{flankr} package 102 | data(exampleData) 103 | 104 | # Fix the first parameter (A) during the fit. 105 | parms <- c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24) 106 | fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 107 | 108 | # fit the model. 109 | # (Note this is a toy example with very low trial numbers to speed up the 110 | # example. For proper use, increase nTrials.) 111 | \donttest{ 112 | fit <- fitDSTP_fixed(exampleData, conditionName = "present", parms = parms, 113 | fixed = fixed, nTrials = 100) 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /man/fitMultipleSSP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sspFunctions.R, R/zzz_aliases.R 3 | \name{fitMultipleSSP} 4 | \alias{fitMultipleSSP} 5 | \alias{fit_multiple_ssp} 6 | \title{Fit the SSP model to human data with multiple starting parameters} 7 | \usage{ 8 | fitMultipleSSP( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 12 | var = 10, 13 | nParms = 20, 14 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 15 | cafs = c(0.25, 0.5, 0.75), 16 | maxParms = c(1, 1, 1, 1, 2), 17 | nTrials = 50000, 18 | multipleSubjects = TRUE, 19 | seed = NULL 20 | ) 21 | 22 | fit_multiple_ssp( 23 | data, 24 | conditionName = NULL, 25 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 26 | var = 10, 27 | nParms = 20, 28 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 29 | cafs = c(0.25, 0.5, 0.75), 30 | maxParms = c(1, 1, 1, 1, 2), 31 | nTrials = 50000, 32 | multipleSubjects = TRUE, 33 | seed = NULL 34 | ) 35 | 36 | fit_multiple_ssp( 37 | data, 38 | conditionName = NULL, 39 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 40 | var = 10, 41 | nParms = 20, 42 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 43 | cafs = c(0.25, 0.5, 0.75), 44 | maxParms = c(1, 1, 1, 1, 2), 45 | nTrials = 50000, 46 | multipleSubjects = TRUE, 47 | seed = NULL 48 | ) 49 | } 50 | \arguments{ 51 | \item{data}{A data frame containing human data. See \code{?exampleData} for 52 | data formatted correctly.} 53 | 54 | \item{conditionName}{If there is an additional experimental manipulation 55 | (i.e., other than target congruency) the model can only be fit to one at a 56 | time. Tell the function which condition is currently being fit by passing 57 | a string to the function (e.g., "present"). The function by default assumes 58 | no additional condition (e.g., conditionName is set to NULL).} 59 | 60 | \item{parms}{A vector of starting parameters to use in the minimisation 61 | routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 62 | \code{sda}. These parameters will be the starting point for the random 63 | parameters.} 64 | 65 | \item{var}{An integer stating the percentage of each parameter value that 66 | should be used for finding random parameter starting points.} 67 | 68 | \item{nParms}{An integer stating how many random starting points to explore} 69 | 70 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 71 | to be estimated from the human data. The model will attempt to find the 72 | best-fitting parameters that match this distributional data.} 73 | 74 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 75 | estimated from the human data. The model will attempt to find the best- 76 | fitting parameters that match this distributional data.} 77 | 78 | \item{maxParms}{A vector containing upper limits on possible parameter 79 | values.} 80 | 81 | \item{nTrials}{An integer stating how many trials to simulate per iteration 82 | of the fitting cycle for each congruency type.} 83 | 84 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 85 | subjects (multipleSubjects = TRUE) or to a single subject 86 | (multipleSubjects = FALSE).} 87 | 88 | \item{seed}{The value for the \code{set.seed} function to set random 89 | generation state.} 90 | } 91 | \value{ 92 | \code{bestParameters} A vector of the best-fitting parameters found 93 | by the current fit run. 94 | 95 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 96 | current fit run. 97 | 98 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 99 | obtained by the current fit run. This is calculated using the BIC equation 100 | for binned data, hence bBIC (binned BIC). 101 | } 102 | \description{ 103 | \code{fitSSPMultiple} fits the SSP model to a single experimental condition 104 | of human data (besides congruency, which it accounts for simutaneously). 105 | } 106 | \details{ 107 | This function can be employed by the user to find the best-fitting 108 | parameters of the SSP model to fit the human data of a single experimental 109 | condition. The fitting procedure accounts for congruent and incongruent 110 | trials simultaneously. The fit is obtained by a gradient-descent method 111 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 112 | fit to the proportion of data contained in human CDF and CAF distributional 113 | data. 114 | } 115 | \examples{ 116 | # Load the example data the comes with the \code{flankr} package 117 | data(exampleData) 118 | 119 | # Fit the model to the condition "present" in the example data set using 120 | # the default settings in the model. 121 | # (Note this is a toy example with very low trial numbers to speed up the 122 | # example. For proper use, increase nTrials.) 123 | \donttest{ 124 | fit <- fitMultipleSSP(data = exampleData, conditionName = "present", 125 | nTrials = 100) 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /man/fitMultipleSSP_fixed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sspFunctions.R, R/zzz_aliases.R 3 | \name{fitMultipleSSP_fixed} 4 | \alias{fitMultipleSSP_fixed} 5 | \alias{fit_multiple_ssp_fixed} 6 | \title{Fit the SSP model to human data with mutiple starting parmaeters with some 7 | fixed parameters} 8 | \usage{ 9 | fitMultipleSSP_fixed( 10 | data, 11 | conditionName = NULL, 12 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 13 | var = 10, 14 | nParms = 20, 15 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 16 | cafs = c(0.25, 0.5, 0.75), 17 | maxParms = c(1, 1, 1, 1, 2), 18 | nTrials = 50000, 19 | multipleSubjects = TRUE, 20 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE) 21 | ) 22 | 23 | fit_multiple_ssp_fixed( 24 | data, 25 | conditionName = NULL, 26 | parms = c(0.05, 0.3, 0.4, 0.05, 1.5), 27 | var = 10, 28 | nParms = 20, 29 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 30 | cafs = c(0.25, 0.5, 0.75), 31 | maxParms = c(1, 1, 1, 1, 2), 32 | nTrials = 50000, 33 | multipleSubjects = TRUE, 34 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE) 35 | ) 36 | } 37 | \arguments{ 38 | \item{data}{A data frame containing human data. See \code{?exampleData} for 39 | data formatted correctly.} 40 | 41 | \item{conditionName}{If there is an additional experimental manipulation 42 | (i.e., other than target congruency) the model can only be fit to one at a 43 | time. Tell the function which condition is currently being fit by passing 44 | a string to the function (e.g., "present"). The function by default assumes 45 | no additional condition (e.g., conditionName is set to NULL).} 46 | 47 | \item{parms}{A vector of starting parameters to use in the minimisation 48 | routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 49 | \code{sda}. These parameters will be the starting point for the random 50 | parameters.} 51 | 52 | \item{var}{An integer stating the percentage of each parameter value that 53 | should be used for finding random parameter starting points.} 54 | 55 | \item{nParms}{An integer stating how many random starting points to explore} 56 | 57 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 58 | to be estimated from the human data. The model will attempt to find the 59 | best-fitting parameters that match this distributional data.} 60 | 61 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 62 | estimated from the human data. The model will attempt to find the best- 63 | fitting parameters that match this distributional data.} 64 | 65 | \item{maxParms}{A vector containing upper limits on possible parameter 66 | values.} 67 | 68 | \item{nTrials}{An integer stating how many trials to simulate per iteration 69 | of the fitting cycle for each congruency type.} 70 | 71 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 72 | subjects (multipleSubjects = TRUE) or to a single subject 73 | (multipleSubjects = FALSE).} 74 | 75 | \item{fixed}{A vector of TRUE/FALSE stating whether each parameter should be 76 | fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 77 | order: \code{A}, \code{ter}, \code{p}, \code{rd}, \code{sda}.} 78 | } 79 | \value{ 80 | \code{bestParameters} A vector of the best-fitting parameters found 81 | by the current fit run. 82 | 83 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 84 | current fit run. 85 | 86 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 87 | obtained by the current fit run. This is calculated using the BIC equation 88 | for binned data, hence bBIC (binned BIC). 89 | } 90 | \description{ 91 | \code{fitMultipleSSP_fixed} fits the SSP model to a single experimental 92 | condition of human data (besides congruency, which it accounts for 93 | simutaneously). This function explores multiple starting parameters and 94 | allows user to fix model parameters. 95 | } 96 | \details{ 97 | This function can be employed by the user to find the best-fitting 98 | parameters of the SSP model to fit the human data of a single experimental 99 | condition. The fitting procedure accounts for congruent and incongruent 100 | trials simultaneously. The fit is obtained by a gradient-descent method 101 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 102 | fit to the proportion of data contained in human CDF and CAF distributional 103 | data. Multiple starting points of parameters are used. 104 | } 105 | \examples{ 106 | data(exampleData) 107 | # Fix the first parameter (A) during the fit. 108 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500) 109 | fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE) 110 | 111 | # run the model 112 | # (Note this is a toy example with very low trial numbers to speed up the 113 | # example. For proper use, increase nTrials.) 114 | \donttest{ 115 | fit <- fitMultipleSSP_fixed(exampleData, conditionName = "present", 116 | parms = parms, fixed = fixed, nTrials = 100) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /man/fitMultipleDSTP.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dstpFunctions.R, R/zzz_aliases.R 3 | \name{fitMultipleDSTP} 4 | \alias{fitMultipleDSTP} 5 | \alias{fit_multiple_dstp} 6 | \title{Fit the DSTP model to human data with mutiple starting parmaeters} 7 | \usage{ 8 | fitMultipleDSTP( 9 | data, 10 | conditionName = NULL, 11 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 12 | var = 10, 13 | nParms = 20, 14 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 15 | cafs = c(0.25, 0.5, 0.75), 16 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 17 | nTrials = 50000, 18 | multipleSubjects = TRUE, 19 | seed = NULL 20 | ) 21 | 22 | fit_multiple_dstp( 23 | data, 24 | conditionName = NULL, 25 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 26 | var = 10, 27 | nParms = 20, 28 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 29 | cafs = c(0.25, 0.5, 0.75), 30 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 31 | nTrials = 50000, 32 | multipleSubjects = TRUE, 33 | seed = NULL 34 | ) 35 | 36 | fit_multiple_dstp( 37 | data, 38 | conditionName = NULL, 39 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 40 | var = 10, 41 | nParms = 20, 42 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 43 | cafs = c(0.25, 0.5, 0.75), 44 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 45 | nTrials = 50000, 46 | multipleSubjects = TRUE, 47 | seed = NULL 48 | ) 49 | } 50 | \arguments{ 51 | \item{data}{A data frame containing human data. See \code{?exampleData} for 52 | data formatted correctly.} 53 | 54 | \item{conditionName}{If there is an additional experimental manipulation 55 | (i.e., other than target congruency) the model can only be fit to one at a 56 | time. Tell the function which condition is currently being fit by passing 57 | a string to the function (e.g., "present"). The function by default assumes 58 | no additional condition (e.g., conditionName is set to NULL).} 59 | 60 | \item{parms}{A vector of starting parameters to use in the minimisation 61 | routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 62 | \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 63 | These parameters will be the starting point for the random parameters.} 64 | 65 | \item{var}{An integer stating the percentage of each parameter value that 66 | should be used for finding random parameter starting points.} 67 | 68 | \item{nParms}{An integer stating how many random starting points to explore} 69 | 70 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 71 | to be estimated from the human data. The model will attempt to find the 72 | best-fitting parameters that match this distributional data.} 73 | 74 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 75 | estimated from the human data. The model will attempt to find the best- 76 | fitting parameters that match this distributional data.} 77 | 78 | \item{maxParms}{A vector containing upper limits on possible parameter 79 | values.} 80 | 81 | \item{nTrials}{An integer stating how many trials to simulate per iteration 82 | of the fitting cycle for each congruency type.} 83 | 84 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 85 | subjects (multipleSubjects = TRUE) or to a single subject 86 | (multipleSubjects = FALSE).} 87 | 88 | \item{seed}{The value for the \code{set.seed} function to set random 89 | generation state.} 90 | } 91 | \value{ 92 | \code{bestParameters} A vector of the best-fitting parameters found 93 | by the current fit run. 94 | 95 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 96 | current fit run. 97 | 98 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 99 | obtained by the current fit run. This is calculated using the BIC equation 100 | for binned data, hence bBIC (binned BIC). 101 | } 102 | \description{ 103 | \code{fitMultipleDSTP} fits the DSTP model to a single experimental condition 104 | of human data (besides congruency, which it accounts for simutaneously). 105 | This function explores multiple starting parameters. 106 | } 107 | \details{ 108 | This function can be employed by the user to find the best-fitting 109 | parameters of the DSTP model to fit the human data of a single experimental 110 | condition. The fitting procedure accounts for congruent and incongruent 111 | trials simultaneously. The fit is obtained by a gradient-descent method 112 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 113 | fit to the proportion of data contained in human CDF and CAF distributional 114 | data. Multiple starting points of parameters are used. 115 | } 116 | \examples{ 117 | # Load the example data the comes with the \code{flankr} package 118 | data(exampleData) 119 | 120 | # Fit the model to the condition "present" in the example data set using 121 | # the default settings in the model. 122 | # (Note this is a toy example with very low trial numbers to speed up the 123 | # example. For proper use, increase nTrials.) 124 | \donttest{ 125 | fit <- fitMultipleDSTP(data = exampleData, conditionName = "present", nTrials = 100) 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /man/fitMultipleDSTP_fixed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dstpFunctions.R, R/zzz_aliases.R 3 | \name{fitMultipleDSTP_fixed} 4 | \alias{fitMultipleDSTP_fixed} 5 | \alias{fit_multiple_dstp_fixed} 6 | \title{Fit the DSTP model to human data with multiple starting parameters with some 7 | fixed parameters} 8 | \usage{ 9 | fitMultipleDSTP_fixed( 10 | data, 11 | conditionName = NULL, 12 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 13 | var = 10, 14 | nParms = 20, 15 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 16 | cafs = c(0.25, 0.5, 0.75), 17 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 18 | nTrials = 50000, 19 | multipleSubjects = TRUE, 20 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 21 | ) 22 | 23 | fit_multiple_dstp_fixed( 24 | data, 25 | conditionName = NULL, 26 | parms = c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24), 27 | var = 10, 28 | nParms = 20, 29 | cdfs = c(0.1, 0.3, 0.5, 0.7, 0.9), 30 | cafs = c(0.25, 0.5, 0.75), 31 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 32 | nTrials = 50000, 33 | multipleSubjects = TRUE, 34 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 35 | ) 36 | } 37 | \arguments{ 38 | \item{data}{A data frame containing human data. See \code{?exampleData} for 39 | data formatted correctly.} 40 | 41 | \item{conditionName}{If there is an additional experimental manipulation 42 | (i.e., other than target congruency) the model can only be fit to one at a 43 | time. Tell the function which condition is currently being fit by passing 44 | a string to the function (e.g., "present"). The function by default assumes 45 | no additional condition (e.g., conditionName is set to NULL).} 46 | 47 | \item{parms}{A vector of starting parameters to use in the minimisation 48 | routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 49 | \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 50 | These parameters will be the starting point for the random parameters.} 51 | 52 | \item{var}{An integer stating the percentage of each parameter value that 53 | should be used for finding random parameter starting points.} 54 | 55 | \item{nParms}{An integer stating how many random starting points to explore} 56 | 57 | \item{cdfs}{A vector of quantile values for cumulative distribution functions 58 | to be estimated from the human data. The model will attempt to find the 59 | best-fitting parameters that match this distributional data.} 60 | 61 | \item{cafs}{A vector of quantiles for conditional accuracy functions to be 62 | estimated from the human data. The model will attempt to find the best- 63 | fitting parameters that match this distributional data.} 64 | 65 | \item{maxParms}{A vector containing upper limits on possible parameter 66 | values.} 67 | 68 | \item{nTrials}{An integer stating how many trials to simulate per iteration 69 | of the fitting cycle for each congruency type.} 70 | 71 | \item{multipleSubjects}{A boolean stating whether the fit is to multiple 72 | subjects (multipleSubjects = TRUE) or to a single subject 73 | (multipleSubjects = FALSE).} 74 | 75 | \item{fixed}{A vector of TRUE/FALSE stating whether each parameter should be 76 | fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 77 | order: \code{A}, \code{C}, \code{driftTarget}, \code{driftFlanker}, 78 | \code{diftStimSelection}, \code{driftRS2}, \code{ter}.} 79 | } 80 | \value{ 81 | \code{bestParameters} A vector of the best-fitting parameters found 82 | by the current fit run. 83 | 84 | \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 85 | current fit run. 86 | 87 | \code{bBIC} The value of the Bayesian Information Criterion (BIC) 88 | obtained by the current fit run. This is calculated using the BIC equation 89 | for binned data, hence bBIC (binned BIC). 90 | } 91 | \description{ 92 | \code{fitMultipleDSTP_fixed} fits the DSTP model to a single experimental 93 | condition of human data (besides congruency, which it accounts for 94 | simutaneously). This function explores multiple starting parameters and 95 | allows user to fix model parameters. 96 | } 97 | \details{ 98 | This function can be employed by the user to find the best-fitting 99 | parameters of the DSTP model to fit the human data of a single experimental 100 | condition. The fitting procedure accounts for congruent and incongruent 101 | trials simultaneously. The fit is obtained by a gradient-descent method 102 | (using the Nelder-Mead method contained in R's \code{optim} function) and is 103 | fit to the proportion of data contained in human CDF and CAF distributional 104 | data. Multiple starting points of parameters are used. 105 | } 106 | \examples{ 107 | # Load the example data the comes with the \code{flankr} package 108 | data(exampleData) 109 | 110 | # Fit the model whilst fixing the first parameter (A) 111 | # (Note this is a toy example with very low trial numbers to speed up the 112 | # example. For proper use, increase nTrials.) 113 | parms <- c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24) 114 | fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 115 | \donttest{ 116 | fit <- fitMultipleDSTP_fixed(exampleData, conditionName = "present", 117 | parms = parms, fixed = fixed, nTrials = 100) 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /R/cdfFunctions.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # get CDFs ---------------------------------------------------------------- 4 | 5 | 6 | #' Find cumulative distribution function (CDF) values for a single condition 7 | #' 8 | #' \code{cdf} takes a data frame for a single experimental condition and 9 | #' returns a vector of requested CDF values. 10 | #' 11 | #' The function only deals with one experimental condition. There is another 12 | #' function (\code{cdfAll}) which will return CDFs for all experimental 13 | #' conditions. If there are more than one subject in the data frame being 14 | #' passed to this function, the function first finds the CDF values for each 15 | #' subject, and then takes the average for each quantile. This average is then 16 | #' returned to the user. 17 | #' 18 | #' @param data A data frame containing the data to be passed to the function. 19 | #' At the very least, the data frame must contain columns named "accuracy" 20 | #' logging the accuracy (1 for correct, 0 for error) and "rt" containing the 21 | #' response time data. If the user wishes to find the average CDFs across 22 | #' multiple subjects, then another column must be included ("subject") with 23 | #' numbers identifying unique subjects. See \code{?exampleData} for a data 24 | #' frame formatted correctly. 25 | #' 26 | #' @param quantiles The quantile values to be found by the function. By 27 | #' default, the function finds the .1, .3, .5, .7, and .9 CDF values. 28 | #' 29 | #' @param correctTrials If set to 1, the function will find the CDFs of 30 | #' correct trials. Set to 2 to find the CDFs of error trials. Set to 3 to find 31 | #' CDFs of ALL trials. Note, though, that CDFs of error trials may be less 32 | #' accurate due to usually-low number of error trials. 33 | #' 34 | #' @param multipleSubjects Inform the function whether the data frame contains 35 | #' data from multiple subjects. If set to TRUE, the function returns the 36 | #' average CDF values across all subjects. If set to FALSE, the function 37 | #' assumes all data being passed is just from one subject. 38 | #' 39 | #' @return Returns a vector of response times for each quantile of CDF 40 | #' requested. 41 | #' 42 | #' @examples 43 | #' ### example of multiple subjects and default quantile values 44 | #' 45 | #' # only select the congruent data from the example data set 46 | #' data <- subset(exampleData, exampleData$congruency == "congruent") 47 | #' 48 | #' # get the CDFs 49 | #' getCDF <- cdf(data) 50 | #' 51 | #' ### example of single subject and different quantile values 52 | #' 53 | #' # only select subject 1 from the example data. Also, select only the 54 | #' # "absent" condition and incongruent trials. This is an example when working 55 | #' # with multiple conditions (besides target congruency). 56 | #' data <- subset(exampleData, exampleData$subject == 1 & 57 | #' exampleData$condition == "absent" & 58 | #' exampleData$congruency == "incongruent") 59 | #' 60 | #' # set new quantile values 61 | #' newQuantiles <- c(.1, .2, .3, .4, .5, .6, .7, .8, .9) 62 | #' 63 | #' # get the CDFs 64 | #' getCDF <- cdf(data, quantiles = newQuantiles, multipleSubjects = FALSE) 65 | #' 66 | #' @export 67 | cdf <- function(data, quantiles = c(.1, .3, .5, .7, .9), 68 | correctTrials = 1, multipleSubjects = TRUE){ 69 | 70 | # perform the simple operation of calculating CDFs if only one subject 71 | if(multipleSubjects == FALSE){ 72 | 73 | 74 | # select whether the user wants correct trials or error trials (or all!) 75 | if(correctTrials == 1){ 76 | tempData <- subset(data, data$accuracy == 1) 77 | } 78 | if(correctTrials == 2){ 79 | tempData <- subset(data, data$accuracy == 0) 80 | } 81 | if(correctTrials == 3){ 82 | tempData <- data 83 | } 84 | 85 | # calculate the CDFs 86 | cdfs <- as.numeric(quantile(tempData$rt, quantiles)) 87 | 88 | # return them to the user 89 | return(cdfs) 90 | } 91 | 92 | 93 | # if there are multiple subjects, find average CDF across these subjects 94 | if(multipleSubjects == TRUE){ 95 | 96 | # find the unique subject numbers 97 | subs <- unique(data$subject) 98 | 99 | # how many subjects are there? 100 | nSubs <- length(subs) 101 | 102 | # create a n*m matrix where rows (n) reflect quantile, and columns (m) are 103 | # subjects. At the end, return the average of each row (quantile) 104 | cdfData <- matrix(0, nrow = length(quantiles), ncol = nSubs) 105 | 106 | # loop over all subjects, find their CDFs, and place in cdfData matrix 107 | for(i in 1:nSubs){ 108 | 109 | tempData <- subset(data, data$subject == subs[i]) 110 | 111 | # select whether the user wants correct trials or error trials (or all!) 112 | if(correctTrials == 1){ 113 | tempData <- subset(data, data$accuracy == 1) 114 | } 115 | if(correctTrials == 2){ 116 | tempData <- subset(data, data$accuracy == 0) 117 | } 118 | if(correctTrials == 3){ 119 | tempData <- data 120 | } 121 | 122 | 123 | # log the result 124 | cdfData[, i] <- quantile(tempData$rt, quantiles) 125 | 126 | } 127 | 128 | #calculate average CDFs across subjects 129 | averageCDF <- apply(cdfData, 1, mean) 130 | 131 | } 132 | 133 | # return them to the user 134 | return(averageCDF) 135 | 136 | } 137 | 138 | 139 | # CDF bin size ------------------------------------------------------------ 140 | 141 | # Given a set of quantiles for CDFs, return the proportion of data within each 142 | # bin. For example, the CDFs c(.1, .3, .5, .7, .9) have proportions of 143 | # c(.1, .2, .2, .2, .2, .1). This is required because the model will try to 144 | # predict response times which match the proportions in the human data. 145 | cdfBinsize <- function(cdfs){ 146 | 147 | # get empty vector of the right length 148 | props <- numeric(length = (length(cdfs) + 1)) 149 | 150 | # loop over all cdf values 151 | for(i in 1:length(cdfs)){ 152 | 153 | # do the first one manually 154 | if(i == 1){ 155 | props[i] <- cdfs[i] - 0 156 | } 157 | 158 | 159 | # do the intermediate bins automatically 160 | if(i > 1 & i <= length(cdfs)){ 161 | props[i] <- cdfs[i] - cdfs[i - 1] 162 | } 163 | 164 | # do the final one manually 165 | if(i == length(cdfs)){ 166 | props[i + 1] <- 1 - cdfs[i] 167 | } 168 | 169 | } # end of bin loop 170 | 171 | # return the proportions 172 | return(props) 173 | 174 | } # end of function 175 | 176 | 177 | 178 | # opposite of cdfBinsize -------------------------------------------------- 179 | 180 | # The opposite of cdfBinsize. Given a set of proportions, work out the CDFs 181 | # For example, the proportions c(.1, .2, .2, .2, .2, .1) have CDFs of 182 | # c(.1, .3, .5, .7, .9). 183 | binsizeCDFs <- function(proportions){ 184 | 185 | # initialise empty vector for cdfs 186 | cdfs <- numeric(length(proportions) - 1) 187 | 188 | for(i in 1:length(cdfs)){ 189 | cdfs[i] <- sum(proportions[1:i]) 190 | } 191 | return(cdfs) 192 | } 193 | 194 | 195 | 196 | # CDF proportions --------------------------------------------------------- 197 | 198 | # Calculate the proportion of correct responses in each cdf bin for a given 199 | # condition. Takes two parameters: data (the data), and correctProportions; the 200 | # latter is a vector of proportions for each bin if accuracy were 100%. 201 | # 202 | # This function finds the accuracy for each subject (if applicable) and 203 | # multiplies the correctProportions vector by this value. This gives the 204 | # proportion in each bin for each subject. Then, the function returns the 205 | # average proportion in each bin. 206 | cdfProportions <- function(data, correctProportions, multipleSubjects = TRUE){ 207 | 208 | # if there is only one subject, then find the overall proportions and return 209 | # them (i.e., there is no loop or averaging) 210 | if(multipleSubjects == FALSE){ 211 | 212 | # find the accuracy 213 | accuracy <- sum(data$accuracy) / nrow(data) 214 | 215 | #scale the proportions by the accuracy 216 | proportions <- correctProportions * accuracy 217 | 218 | # return to user 219 | return(proportions) 220 | } 221 | 222 | if(multipleSubjects == TRUE){ 223 | 224 | # what are the unique subject numbers? 225 | subs <- unique(data$subject) 226 | 227 | # how many subjects are there? 228 | nSubs <- length(subs) 229 | 230 | # initiate a matrix to store all subject's proportions in 231 | allProportions <- matrix(0, nrow = nSubs, 232 | ncol = length(correctProportions)) 233 | 234 | # Loop over each subject 235 | for(i in 1:nSubs){ 236 | 237 | # get the current subject's data 238 | subjectData <- subset(data, data$subject == subs[i]) 239 | 240 | # calculate their accuracy 241 | accuracy <- sum(subjectData$accuracy) / nrow(subjectData) 242 | 243 | # scale the proportions by the accuracy, and store the result 244 | allProportions[i, ] <- correctProportions * accuracy 245 | 246 | } 247 | 248 | } 249 | 250 | # calculate the average proportions 251 | allProportions <- apply(allProportions, 2, mean) 252 | 253 | # return to the user 254 | return(allProportions) 255 | 256 | } # end of function 257 | 258 | 259 | 260 | 261 | # get model CDFs ---------------------------------------------------------- 262 | 263 | # Get model proportions from human CDFs (the RTs, not proportions). 264 | # Returns proportions 265 | getModelCDFs <- function(modelData, cdfs){ 266 | 267 | 268 | # only select the correct trials 269 | modelData <- subset(modelData, modelData[, 2] == 1) 270 | 271 | # initiate empty vector to store model CDFs in 272 | props <- numeric(length(cdfs)) 273 | 274 | # loop over each human CDF cutoff point, and find the proportion of model 275 | # data in each bin 276 | for(i in 1:length(cdfs)){ 277 | x <- subset(modelData, modelData[, 1] <= cdfs[i]) 278 | props[i] <- length(x[, 1]) / nrow(modelData) 279 | } 280 | 281 | return(props) 282 | 283 | } 284 | 285 | -------------------------------------------------------------------------------- /R/modelPrep.R: -------------------------------------------------------------------------------- 1 | ### 2 | # This file contains model preparation functions, such as calculating 3 | # proportions in each distributional bin of human data, finding proportions 4 | # predicted by a model etc. 5 | 6 | #------------------------------------------------------------------------------ 7 | # A function to get human distributional bin proportions from data, given 8 | # desired CDF and CAF qauntile values. These values will be used by the model 9 | # during fitting. 10 | getHumanProps <- function(conditionData, cdfs, cafs){ 11 | 12 | 13 | # split trials on congruency 14 | congruentData <- subset(conditionData, 15 | conditionData$congruency == "congruent") 16 | incongruentData <- subset(conditionData, 17 | conditionData$congruency == "incongruent") 18 | 19 | 20 | # CDFs----------------------------------------------------------------------- 21 | # get correct RT CDF proportions. They are a function of the desired CDF 22 | # quantile points, and the overall accuracy for the congruency condition 23 | congruentProps <- cdfBinsize(cdfs) 24 | incongruentProps <- cdfBinsize(cdfs) 25 | 26 | # scale by the proportion correct 27 | congruentCDFProps <- cdfProportions(congruentData, congruentProps) 28 | incongruentCDFProps <- cdfProportions(incongruentData, incongruentProps) 29 | 30 | # get the CDF cut-off values of response time 31 | congruentCDFs <- cdf(congruentData, quantiles = cdfs) 32 | incongruentCDFs <- cdf(incongruentData, quantiles = cdfs) 33 | 34 | # CAFs----------------------------------------------------------------------- 35 | # get the CAF proportions 36 | congruentCAFProps <- cafProportions(congruentData, quantiles = cafs) 37 | incongruentCAFProps <- cafProportions(incongruentData, quantiles = cafs) 38 | 39 | # get the CAF cut-off points 40 | congruentCAFsCutoff <- cdf(congruentData, quantiles = cafs, 41 | correctTrials = 3) 42 | incongruentCAFsCutoff <- cdf(incongruentData, quantiles = cafs, 43 | correctTrials = 3) 44 | 45 | # now get the CAFs themselves 46 | congruentCAFs <- caf(congruentData, quantiles = cafs) 47 | incongruentCAFs <- caf(incongruentData, quantiles = cafs) 48 | 49 | 50 | #collate data and return----------------------------------------------------- 51 | humanProportions <- list(cdfQuantiles = cdfs, 52 | cafQuantiles = cafs, 53 | congruentCDFProportions = congruentCDFProps, 54 | incongruentCDFProportions = incongruentCDFProps, 55 | congruentCAFProportions = congruentCAFProps, 56 | incongruentCAFProportions = incongruentCAFProps, 57 | congruentCDFs = congruentCDFs, 58 | incongruentCDFs = incongruentCDFs, 59 | congruentCAFsCutoff = congruentCAFsCutoff, 60 | incongruentCAFsCutoff = incongruentCAFsCutoff, 61 | congruentCAFsRT = congruentCAFs[1, ], 62 | congruentCAFsError = congruentCAFs[2, ], 63 | incongruentCAFsRT = incongruentCAFs[1, ], 64 | incongruentCAFsError = incongruentCAFs[2, ]) 65 | 66 | # return it 67 | return(humanProportions) 68 | 69 | } 70 | #------------------------------------------------------------------------------ 71 | 72 | 73 | 74 | #------------------------------------------------------------------------------ 75 | ########NEED TO MODIFY TO USE CORRECT PROPORTION FUNCTIONS 76 | 77 | 78 | 79 | # A function to get SINGLE human distributional bin proportions from data, 80 | # given desired CDF and CAF qauntile values. These values will be used by the 81 | # model during fitting. 82 | getHumanPropsSingle <- function(conditionData, cdfs, cafs){ 83 | 84 | 85 | # split trials on congruency 86 | congruentData <- subset(conditionData, 87 | conditionData$congruency == "congruent") 88 | incongruentData <- subset(conditionData, 89 | conditionData$congruency == "incongruent") 90 | 91 | # CDFs----------------------------------------------------------------------- 92 | # get correct RT CDF proportions. They are a function of the desired CDF 93 | # quantile points, and the overall accuracy for the congruency condition 94 | congruentProps <- cdfBinsize(cdfs) 95 | incongruentProps <- cdfBinsize(cdfs) 96 | 97 | # scale by the proportion correct 98 | congruentCDFProps <- cdfProportions(congruentData, congruentProps, 99 | multipleSubjects = FALSE) 100 | incongruentCDFProps <- cdfProportions(incongruentData, incongruentProps, 101 | multipleSubjects = FALSE) 102 | 103 | # get the CDF cut-off values of response time 104 | congruentCDFs <- cdf(congruentData, quantiles = cdfs, 105 | multipleSubjects = FALSE) 106 | incongruentCDFs <- cdf(incongruentData, quantiles = cdfs, 107 | multipleSubjects = FALSE) 108 | 109 | # CAFs----------------------------------------------------------------------- 110 | # get the CAF proportions 111 | congruentCAFProps <- cafProportions(congruentData, quantiles = cafs, 112 | multipleSubjects = FALSE) 113 | incongruentCAFProps <- cafProportions(incongruentData, quantiles = cafs, 114 | multipleSubjects = FALSE) 115 | 116 | # get the CAF cut-off points 117 | congruentCAFsCutoff <- cdf(congruentData, quantiles = cafs, 118 | correctTrials = 3,multipleSubjects = FALSE) 119 | incongruentCAFsCutoff <- cdf(incongruentData, quantiles = cafs, 120 | correctTrials = 3, multipleSubjects = FALSE) 121 | 122 | # now get the CAFs themselves 123 | congruentCAFs <- caf(congruentData, quantiles = cafs, 124 | multipleSubjects = FALSE) 125 | incongruentCAFs <- caf(incongruentData, quantiles = cafs, 126 | multipleSubjects = FALSE) 127 | 128 | 129 | #collate data and return----------------------------------------------------- 130 | humanProportions <- list(cdfQuantiles = cdfs, 131 | cafQuantiles = cafs, 132 | congruentCDFProportions = congruentCDFProps, 133 | incongruentCDFProportions = incongruentCDFProps, 134 | congruentCAFProportions = congruentCAFProps, 135 | incongruentCAFProportions = incongruentCAFProps, 136 | congruentCDFs = congruentCDFs, 137 | incongruentCDFs = incongruentCDFs, 138 | congruentCAFsCutoff = congruentCAFsCutoff, 139 | incongruentCAFsCutoff = incongruentCAFsCutoff, 140 | congruentCAFsRT = congruentCAFs[1, ], 141 | congruentCAFsError = congruentCAFs[2, ], 142 | incongruentCAFsRT = incongruentCAFs[1, ], 143 | incongruentCAFsError = incongruentCAFs[2, ]) 144 | 145 | # return it 146 | return(humanProportions) 147 | 148 | } 149 | #------------------------------------------------------------------------------ 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | #------------------------------------------------------------------------------ 158 | # Get model's bin proportions for CDF of correct RT. This uses the human CDFs 159 | # as cut-offs. It then calculates the proportion found in each bin, and 160 | # a later function then compares this to the proportions in the human data. 161 | getCDFProps <- function(cdfs, modelData){ 162 | 163 | # initialise vector to store proportions in 164 | props <- numeric(length(cdfs) + 1) 165 | 166 | # only analyse correct RT from the model 167 | data <- subset(modelData, modelData[, 2] == 1) 168 | 169 | 170 | 171 | # how many bins are there to work through? 172 | nBins <- length(props) 173 | 174 | # loop over each, find the bin boundaries, and calculate the proportion of RT 175 | # in each of the bins 176 | for(i in 1:nBins){ 177 | 178 | # do the first one manually 179 | if(i == 1){ 180 | # get the data in the current bin 181 | bin <- subset(data, data[, 1] <= cdfs[i]) 182 | # find the proportion of data in this bin 183 | props[i] <- length(bin[, 1]) / nrow(modelData) 184 | } 185 | 186 | 187 | # do the middle ones automatically 188 | if(i > 1 & i <= nBins){ 189 | bin <- subset(data, data[, 1] > cdfs[i - 1] & data[, 1] <= cdfs[i]) 190 | props[i] <- length(bin[, 1]) / nrow(modelData) 191 | } 192 | 193 | 194 | # do the last one manually 195 | if(i == nBins){ 196 | bin <- subset(data, data[, 1] > cdfs[i - 1]) 197 | props[i] <- length(bin[, 1]) / nrow(modelData) 198 | } 199 | 200 | } 201 | 202 | 203 | # return the proportions 204 | return(props) 205 | 206 | } 207 | #------------------------------------------------------------------------------ 208 | 209 | 210 | 211 | #------------------------------------------------------------------------------ 212 | # Get model's bin proportions for CAFs. This uses the CAF cutoff CDFs from the 213 | # human data, and finds the proportion of correct responses in each bin 214 | # predicted by the model. 215 | getCAFProps <- function(cdfs, modelData){ 216 | 217 | # initialise vector to store proportions in 218 | props <- numeric(length(cdfs) + 1) 219 | 220 | # how many bins are there to calculate? 221 | nBins <- length(props) 222 | 223 | # loop over each CDF value, find the bin boundaries, source the data, and 224 | # find the proportion of correct responses in each bin. 225 | for(i in 1:nBins){ 226 | 227 | 228 | # do the first bin manually 229 | if(i == 1){ 230 | 231 | # get the current bin's data 232 | bin <- subset(modelData, modelData[, 1] <= cdfs[i]) 233 | 234 | # if there are data points in this bin 235 | if(length(bin[, 2]) > 0) { 236 | 237 | # find the proportion of correct RTs 238 | props[i] <- (sum(bin[, 2] == 0)) / nrow(modelData) 239 | 240 | } else { 241 | props[i] <- 0 242 | } 243 | } 244 | 245 | 246 | # do middle ones automatically 247 | if(i > 1 & i <= nBins){ 248 | 249 | bin <- subset(modelData, modelData[, 1] > cdfs[i - 1] & 250 | modelData[, 1] <= cdfs[i]) 251 | if(length(bin[, 2]) > 0) { 252 | props[i] <- (sum(bin[, 2] == 0)) / nrow(modelData) 253 | } else { 254 | props[i] <- 0 255 | } 256 | 257 | } 258 | 259 | 260 | # do the final bin manually 261 | if(i == nBins){ 262 | bin <- subset(modelData, modelData[, 1] > cdfs[i - 1]) 263 | if(length(bin[, 2]) > 0) { 264 | props[i] <- (sum(bin[, 2] == 0)) / nrow(modelData) 265 | } else { 266 | props[i] <- 9 267 | } 268 | } 269 | 270 | 271 | } 272 | 273 | # return the proportions 274 | return(props) 275 | 276 | } 277 | #------------------------------------------------------------------------------ 278 | -------------------------------------------------------------------------------- /R/optimisation.R: -------------------------------------------------------------------------------- 1 | ### 2 | # Optimisation function for the different models 3 | 4 | #------------------------------------------------------------------------------ 5 | # Fit function for the DSTP model 6 | fitFunctionDSTP <- function(humanProportions, parms, n, maxParms, 7 | seed = NULL){ 8 | 9 | 10 | # Get the model's predictions 11 | modelPrediction <- predictionsDSTP(parms, 12 | n, 13 | propsForModel = humanProportions, 14 | seed = seed) 15 | 16 | 17 | # Put all human data into one vector, for ease of comparison with model's 18 | # prediction. 19 | humanProps <- c(humanProportions$congruentCDFProportions, 20 | humanProportions$incongruentCDFProportions, 21 | humanProportions$congruentCAFProportions, 22 | humanProportions$incongruentCAFProportions) 23 | 24 | 25 | # Do the same for the model data. 26 | modelProps <- c(modelPrediction$modelCongruentCDF, 27 | modelPrediction$modelIncongruentCDF, 28 | modelPrediction$modelCongruentCAF, 29 | modelPrediction$modelIncongruentCAF) 30 | 31 | 32 | # If any proportion is zero, change it to a very small number. This is 33 | # is because the fit statistic cannot handle zeros due to a division 34 | # by zero causing errors. 35 | humanProps[humanProps == 0] <- 0.0001 36 | modelProps[modelProps == 0] <- 0.0001 37 | 38 | # Calculate likelihood ratio chi-square statistic 39 | fitStatistic <- 2 * sum(250 * humanProps * log(humanProps / modelProps)) 40 | 41 | if(fitStatistic == Inf){ 42 | return(.Machine$double.xmax) 43 | } 44 | 45 | # If the parameters are below zero or are above maxParms, then return poor 46 | # fit 47 | if ((min(parms) < 0) | (min(maxParms - parms) < 0)){ 48 | return(.Machine$double.xmax) 49 | } else { 50 | return(fitStatistic) 51 | } 52 | } 53 | #------------------------------------------------------------------------------ 54 | 55 | 56 | 57 | #------------------------------------------------------------------------------ 58 | # Fit function for the SSP model 59 | fitFunctionSSP <- function(humanProportions, parms, n, 60 | maxParms, seed = NULL){ 61 | 62 | 63 | # Get the model's predictions 64 | modelPrediction <- predictionsSSP(parms, n, 65 | propsForModel = humanProportions, 66 | seed = seed) 67 | 68 | 69 | # Put all human data into one vector, for ease of comparison with model's 70 | # prediction. 71 | humanProps <- c(humanProportions$congruentCDFProportions, 72 | humanProportions$incongruentCDFProportions, 73 | humanProportions$congruentCAFProportions, 74 | humanProportions$incongruentCAFProportions) 75 | 76 | 77 | # Do the same for the model data. 78 | modelProps <- c(modelPrediction$modelCongruentCDF, 79 | modelPrediction$modelIncongruentCDF, 80 | modelPrediction$modelCongruentCAF, 81 | modelPrediction$modelIncongruentCAF) 82 | 83 | 84 | # If any proportion is zero, change it to a very small number. This is 85 | # is because the fit statistic cannot handle zeros due to a division 86 | # by zero causing errors. 87 | humanProps[humanProps == 0] <- 0.0001 88 | modelProps[modelProps == 0] <- 0.0001 89 | 90 | # Calculate likelihood ratio chi-square statistic 91 | fitStatistic <- 2 * sum(250 * humanProps * log(humanProps / modelProps)) 92 | 93 | if(fitStatistic == Inf){ 94 | return(.Machine$double.xmax) 95 | } 96 | 97 | # If the parameters are below zero or are above maxParms, then return poor 98 | # fit 99 | if ((min(parms) < 0) | (min(maxParms - parms) < 0)){ 100 | return(.Machine$double.xmax) 101 | } else { 102 | return(fitStatistic) 103 | } 104 | } 105 | #------------------------------------------------------------------------------ 106 | 107 | 108 | 109 | #------------------------------------------------------------------------------ 110 | # optimisation for fixed parameter values for the DSTP model 111 | # Code modified from the "optifix" function originally written by Barry 112 | # Rowlingson: 113 | # (http://geospaced.blogspot.co.uk/2011/10/optifix-optim-with-fixed-values.html) 114 | optimFix_DSTP <- function(parms, fixed, humanProportions, n, maxParms, 115 | seed = NULL){ 116 | 117 | # which parameters are fixed/free? 118 | whichFixed <- parms[fixed] 119 | whichFree <- parms[!fixed] 120 | 121 | # define function to run the fit after parameters have been fixed 122 | fixedFit <- function(.parms, fixed, humanProportions, parms, n, maxParms, 123 | seed = NULL){ 124 | 125 | currParms <- rep(NA, sum(!fixed)) 126 | currParms[!fixed] <- .parms 127 | currParms[fixed] <- whichFixed 128 | 129 | fitFunctionDSTP(humanProportions = humanProportions, parms = currParms, 130 | n = n, maxParms = maxParms, seed = seed) 131 | 132 | } 133 | 134 | fit <- optim(whichFree, fixed = fixed, fn = fixedFit, method = "Nelder-Mead", 135 | humanProportions = humanProportions, n = n, maxParms = maxParms, 136 | seed = seed) 137 | 138 | # now populate the output 139 | fit$fullPars <- rep(NA, sum(!fixed)) 140 | fit$fullPars[fixed] <- whichFixed 141 | fit$fullPars[!fixed] <- fit$par 142 | 143 | return(fit) 144 | } 145 | #------------------------------------------------------------------------------ 146 | 147 | 148 | 149 | #------------------------------------------------------------------------------ 150 | # optimisation for fixed parameter values for the SSP model 151 | # Code modified from the "optifix" function originally written by Barry 152 | # Rowlingson: 153 | # (http://geospaced.blogspot.co.uk/2011/10/optifix-optim-with-fixed-values.html) 154 | optimFix_SSP <- function(parms, fixed, humanProportions, n, maxParms, 155 | seed = NULL){ 156 | 157 | # which parameters are fixed/free? 158 | whichFixed <- parms[fixed] 159 | whichFree <- parms[!fixed] 160 | 161 | # define function to run the fit after parameters have been fixed 162 | fixedFit <- function(.parms, fixed, humanProportions, parms, n, maxParms, 163 | seed = seed){ 164 | 165 | currParms <- rep(NA, sum(!fixed)) 166 | currParms[!fixed] <- .parms 167 | currParms[fixed] <- whichFixed 168 | 169 | fitFunctionSSP(humanProportions = humanProportions, parms = currParms, 170 | n = n, maxParms = maxParms, seed = NULL) 171 | 172 | } 173 | 174 | fit <- optim(whichFree, fixed = fixed, fn = fixedFit, method = "Nelder-Mead", 175 | humanProportions = humanProportions, n = n, maxParms = maxParms, 176 | seed = seed) 177 | 178 | # now populate the output 179 | fit$fullPars <- rep(NA, sum(!fixed)) 180 | fit$fullPars[fixed] <- whichFixed 181 | fit$fullPars[!fixed] <- fit$par 182 | 183 | return(fit) 184 | } 185 | #------------------------------------------------------------------------------ 186 | 187 | 188 | 189 | #------------------------------------------------------------------------------ 190 | # BIC for binned data 191 | bBIC <- function(humanProportions, model, parms, nTrials){ 192 | 193 | n = nTrials 194 | 195 | # If the model selected is the DSTP model 196 | if(model == "DSTP"){ 197 | 198 | # Get the model's predictions 199 | modelPrediction <- predictionsDSTP(parms, n, 200 | propsForModel = humanProportions) 201 | } else { 202 | modelPrediction <- predictionsSSP(parms, n, 203 | propsForModel = humanProportions) 204 | } 205 | 206 | 207 | # Put all human data into one vector, for ease of comparison with model's 208 | # prediction. 209 | humanProps <- c(humanProportions$congruentCDFProportions, 210 | humanProportions$incongruentCDFProportions, 211 | humanProportions$congruentCAFProportions, 212 | humanProportions$incongruentCAFProportions) 213 | 214 | 215 | # Do the same for the model data. 216 | modelProps <- c(modelPrediction$modelCongruentCDF, 217 | modelPrediction$modelIncongruentCDF, 218 | modelPrediction$modelCongruentCAF, 219 | modelPrediction$modelIncongruentCAF) 220 | 221 | 222 | 223 | 224 | # If any proportion is zero, change it to a very small number. This is 225 | # is because the fit statistic cannot handle zeros due to a division 226 | # by zero causing errors. 227 | humanProps[humanProps == 0] <- 0.0001 228 | modelProps[modelProps == 0] <- 0.0001 229 | 230 | 231 | # sum the proportions of model versus human 232 | sumProps <- 250 * humanProps * log(modelProps) 233 | sumProps <- sum(sumProps) 234 | 235 | # set the required number of parameters 236 | if(model == "DSTP"){ 237 | m <- 7 238 | } else { 239 | m <- 5 240 | } 241 | 242 | bic <- -2 * sumProps + m * log(250) 243 | 244 | return(bic) 245 | 246 | } 247 | #------------------------------------------------------------------------------ 248 | 249 | 250 | 251 | #------------------------------------------------------------------------------ 252 | # BIC for binned data with fixed model parameters 253 | bBIC_fixed <- function(humanProportions, model, parms, fixed, nTrials){ 254 | 255 | 256 | n = nTrials 257 | 258 | # If the model selected is the DSTP model 259 | if(model == "DSTP"){ 260 | 261 | # Get the model's predictions 262 | modelPrediction <- predictionsDSTP(parms, n, 263 | propsForModel = humanProportions) 264 | } else { 265 | modelPrediction <- predictionsSSP(parms, n, 266 | propsForModel = humanProportions) 267 | } 268 | 269 | 270 | # Put all human data into one vector, for ease of comparison with model's 271 | # prediction. 272 | humanProps <- c(humanProportions$congruentCDFProportions, 273 | humanProportions$incongruentCDFProportions, 274 | humanProportions$congruentCAFProportions, 275 | humanProportions$incongruentCAFProportions) 276 | 277 | 278 | # Do the same for the model data. 279 | modelProps <- c(modelPrediction$modelCongruentCDF, 280 | modelPrediction$modelIncongruentCDF, 281 | modelPrediction$modelCongruentCAF, 282 | modelPrediction$modelIncongruentCAF) 283 | 284 | 285 | 286 | 287 | # If any proportion is zero, change it to a very small number. This is 288 | # is because the fit statistic cannot handle zeros due to a division 289 | # by zero causing errors. 290 | humanProps[humanProps == 0] <- 0.0001 291 | modelProps[modelProps == 0] <- 0.0001 292 | 293 | 294 | # sum the proportions of model versus human 295 | sumProps <- 250 * humanProps * log(modelProps) 296 | sumProps <- sum(sumProps) 297 | 298 | # set the required number of free parameters 299 | m <- length(fixed) - sum(fixed) 300 | 301 | bic <- -2 * sumProps + m * log(250) 302 | 303 | return(bic) 304 | } 305 | #------------------------------------------------------------------------------ 306 | -------------------------------------------------------------------------------- /R/cafFunctions.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # get CAF ----------------------------------------------------------------- 4 | 5 | #' Find conditional accuracy function (CAF) values for a single condition 6 | #' 7 | #' \code{caf} takes a data frame for a single experimental condition and 8 | #' returns a vector of requested conditional accuracy function (CAF) values. 9 | #' 10 | #' The function only deals with one experimental condition. There is another 11 | #' function (\code{cafAll}) which will return CAFs for all experimental 12 | #' conditions. If there are more than one subject in the data frame being 13 | #' passed to this function, the function first finds the CAF values for each 14 | #' subject, and then takes the average for each quantile. This average is then 15 | #' returned to the user. 16 | #' 17 | #' @param data A data frame containing the data to be passed to the function. 18 | #' At the very least, the data frame must contain columns named "accuracy" 19 | #' logging the accuracy (1 for correct, 0 for error) and "rt" containing the 20 | #' response time data. If the user wishes to find the average CAFs across 21 | #' multiple subjects, then another column must be included ("subject") with 22 | #' numbers identifying unique subjects. See \code{?exampleData} for a data 23 | #' frame formatted correctly. 24 | #' 25 | #' @param quantiles The quantile values to be found by the function. By 26 | #' default, the function finds the accuracy for the .25, .5, and .75 quantiles. 27 | #' 28 | #' @param multipleSubjects Inform the function whether the data frame contains 29 | #' data from multiple subjects. If set to TRUE, the function returns the 30 | #' average CAF values across all subjects. If set to FALSE, the function 31 | #' assumes all data being passed is just from one subject. 32 | #' 33 | #' @return Returns a matrix with response time (row 1) and accuracy (row 2) for 34 | #' each quantile of CAF requested. 35 | #' 36 | #' @examples 37 | #' ### example of multiple subjects and default quantile values 38 | #' 39 | #' # only select the congruent data from the example data set 40 | #' data <- subset(exampleData, exampleData$congruency == "congruent") 41 | #' 42 | #' # get the CDFs 43 | #' getCAF <- caf(data) 44 | #' 45 | #' #-- example of single subject and different quantile values 46 | #' 47 | #' # only select subject 1 from the example data. Also, select only the 48 | #' # "absent" condition and incongruent trials. This is an example when working 49 | #' # with multiple conditions (besides target congruency). 50 | #' data <- subset(exampleData, exampleData$subject == 1 & 51 | #' exampleData$condition == "absent" & 52 | #' exampleData$congruency == "incongruent") 53 | #' 54 | #' # set new quantile values 55 | #' newQuantiles <- c(.2, .4, .6, .8) 56 | #' 57 | #' # get the CAFs 58 | #' getCAF <- caf(data, quantiles = newQuantiles, multipleSubjects = FALSE) 59 | 60 | #' @export 61 | caf <- function(data, quantiles = c(.25, .50, .75), multipleSubjects = TRUE){ 62 | 63 | #--- single participant 64 | # perform simple CAF calculation if only one participant is being passed 65 | # to the function 66 | if(multipleSubjects == FALSE){ 67 | 68 | # initialise empty vector to store data 69 | cafData <- numeric(length = (length(quantiles) * 2) + 2) 70 | 71 | # get the RT values for quantile cut-offs 72 | cdfs <- quantile(data$rt, quantiles) 73 | 74 | #--- calculate mean RT and proportion error for each bin 75 | for(i in 1:length(quantiles)){ 76 | 77 | ## do the first one manually 78 | if(i == 1){ 79 | # get the data 80 | temp <- subset(data, data$rt < cdfs[i]) 81 | # log the RT 82 | cafData[i] <- mean(temp$rt) 83 | # log the accuracy 84 | cafData[i + length(quantiles) + 1] <- sum(temp$accuracy) / 85 | length(temp$accuracy) 86 | } 87 | 88 | ## do the rest of the slots automatically 89 | if(i > 1 & i <= length(quantiles)){ 90 | 91 | # get the data 92 | temp <- subset(data, data$rt > cdfs[i - 1] & data$rt < cdfs[i]) 93 | # log the RT 94 | cafData[i] <- mean(temp$rt) 95 | # log the accuracy 96 | cafData[i + length(quantiles) + 1] <- sum(temp$accuracy) / 97 | length(temp$accuracy) 98 | 99 | } 100 | 101 | ## do the last one manually, too 102 | if(i == length(quantiles)){ 103 | # get the data 104 | temp <- subset(data, data$rt > cdfs[i]) 105 | # log the RT 106 | cafData[i + 1] <- mean(temp$rt) 107 | # log the accuracy 108 | cafData[(i + 1) + length(quantiles) + 1] <- sum(temp$accuracy) / 109 | length(temp$accuracy) 110 | } 111 | 112 | } #end of loop over quantiles 113 | 114 | # coerce the data into a final matrix for ease of use for user 115 | finalData <- matrix(0, nrow = 2, ncol = (length(cafData) / 2)) 116 | row.names(finalData) <- c("rt", "accuracy") 117 | 118 | # populate the final data matrix 119 | finalData[1, 1:(length(cafData) / 2)] <- cafData[1:(length(cafData) / 2)] 120 | finalData[2, 1:(length(cafData) / 2)] <- cafData[((length(cafData) / 2) 121 | + 1): length(cafData)] 122 | 123 | # return the means 124 | return(finalData) 125 | 126 | } #end of single-subject sub-function 127 | 128 | 129 | #--- multiple subjects 130 | if(multipleSubjects == TRUE){ 131 | 132 | # what are the unique subject numbers? 133 | subs <- unique(data$subject) 134 | 135 | # how many subjects are there? 136 | nSubs <- length(subs) 137 | 138 | #empty matrix to store CAF data in 139 | cafData <- matrix(0, nrow = ((length(quantiles) * 2) + 2), ncol = nSubs) 140 | 141 | 142 | # loop over all subjects, get their CAFs, and store in cafData matrix 143 | for(j in 1:nSubs){ 144 | 145 | # get the current subject's data 146 | subData <- subset(data, data$subject == subs[j]) 147 | 148 | # get the current subject's CDF criteria 149 | subCDFs <- quantile(subData$rt, quantiles) 150 | 151 | 152 | #--- calculate mean RT and proportion error for each bin 153 | for(i in 1:length(quantiles)){ 154 | 155 | ## do the first one manually 156 | if(i == 1){ 157 | # get the data 158 | temp <- subset(subData, subData$rt < subCDFs[i]) 159 | # log the RT 160 | cafData[i, j] <- mean(temp$rt) 161 | # log the accuracy 162 | cafData[i + length(quantiles) + 1, j] <- sum(temp$accuracy) / 163 | length(temp$accuracy) 164 | } 165 | 166 | ## do the rest of the slots automatically 167 | if(i > 1 & i <= length(quantiles)){ 168 | 169 | # get the data 170 | temp <- subset(subData, subData$rt > subCDFs[i - 1] & subData$rt < 171 | subCDFs[i]) 172 | # log the RT 173 | cafData[i, j] <- mean(temp$rt) 174 | # log the accuracy 175 | cafData[i + length(quantiles) + 1, j] <- sum(temp$accuracy) / 176 | length(temp$accuracy) 177 | 178 | } 179 | 180 | ## do the last one manually, too 181 | if(i == length(quantiles)){ 182 | # get the data 183 | temp <- subset(subData, subData$rt > subCDFs[i]) 184 | # log the RT 185 | cafData[i + 1, j] <- mean(temp$rt) 186 | # log the accuracy 187 | cafData[(i + 1) + length(quantiles) + 1, j] <- sum(temp$accuracy) / 188 | length(temp$accuracy) 189 | } 190 | 191 | } # end of loop over quantiles 192 | 193 | 194 | } # end of loop over subjects 195 | 196 | # find the mean values 197 | cafData <- apply(cafData, 1, mean) 198 | 199 | # coerce the data into a final matrix for ease of use for user 200 | finalData <- matrix(0, nrow = 2, ncol = (length(cafData) / 2)) 201 | row.names(finalData) <- c("rt", "accuracy") 202 | 203 | # populate the final data matrix 204 | finalData[1, 1:(length(cafData) / 2)] <- cafData[1:(length(cafData) / 2)] 205 | finalData[2, 1:(length(cafData) / 2)] <- cafData[((length(cafData) / 2) 206 | + 1): length(cafData)] 207 | 208 | # return the means 209 | return(finalData) 210 | 211 | } # end of multiple subjects loop 212 | 213 | 214 | } 215 | 216 | 217 | 218 | 219 | # CAF proportions --------------------------------------------------------- 220 | 221 | # Calculate the proportion of error responses in each CAF bin for a single 222 | # condition. 223 | # 224 | # Note that this function returns the proportion of error responses in relation 225 | # to ALL data (not just overall error rate). 226 | cafProportions <- function(data, quantiles = c(.25, .50, .75), 227 | multipleSubjects = TRUE){ 228 | 229 | #--- single participant 230 | # perform simple CAF calculation if only one participant is being passed 231 | # to the function 232 | if(multipleSubjects == FALSE){ 233 | 234 | # initialise empty vector to store data 235 | cafData <- numeric(length = length(quantiles) + 1) 236 | 237 | # get the RT values for quantile cut-offs 238 | cdfs <- quantile(data$rt, quantiles) 239 | 240 | # calculate proportion error for each bin 241 | for(i in 1:length(cafData)){ 242 | 243 | ## do the first one manually 244 | if(i == 1){ 245 | # get the data 246 | temp <- subset(data, data$rt <= cdfs[i]) 247 | 248 | # log the proportion error 249 | cafData[i] <- sum(temp$accuracy == 0) / nrow(data) 250 | } 251 | 252 | ## do the rest of the slots automatically 253 | if(i > 1 & i < length(cafData)){ 254 | 255 | # get the data 256 | temp <- subset(data, data$rt > cdfs[i - 1] & data$rt <= cdfs[i]) 257 | 258 | # log the proportion error 259 | cafData[i] <- sum(temp$accuracy == 0) / nrow(data) 260 | 261 | } 262 | 263 | ## do the last one manually, too 264 | if(i == length(quantiles) + 1){ 265 | # get the data 266 | temp <- subset(data, data$rt > cdfs[i - 1]) 267 | 268 | # log the proportion error 269 | cafData[i] <- sum(temp$accuracy == 0) / nrow(data) 270 | } 271 | 272 | } #end of loop over quantiles 273 | 274 | # return the means 275 | return(cafData) 276 | 277 | } #end of single-subject sub-function 278 | 279 | 280 | #--- multiple subjects 281 | if(multipleSubjects == TRUE){ 282 | 283 | # what are the unique subject numbers? 284 | subs <- unique(data$subject) 285 | 286 | # how many subjects are there? 287 | nSubs <- length(subs) 288 | 289 | #empty matrix to store CAF data in 290 | cafData <- matrix(0, ncol = (length(quantiles) + 1), nrow = nSubs) 291 | 292 | 293 | # loop over all subjects, get their CAFs, and store in cafData matrix 294 | for(i in 1:nSubs){ 295 | 296 | # get the current subject's data 297 | subData <- subset(data, data$subject == subs[i]) 298 | 299 | # get the current subject's CDF criteria 300 | subCDFs <- quantile(subData$rt, quantiles) 301 | 302 | 303 | #--- calculate mean RT and proportion error for each bin 304 | for(j in 1:(length(quantiles) + 1)){ 305 | 306 | ## do the first one manually 307 | if(j == 1){ 308 | 309 | # get the current bin's data 310 | temp <- subset(subData, subData$rt <= subCDFs[j]) 311 | 312 | # log the proportion error 313 | cafData[i, j] <- sum(temp$accuracy == 0) / nrow(subData) 314 | } 315 | 316 | ## do the rest of the slots automatically 317 | if(j > 1 & j < length(quantiles) + 1){ 318 | 319 | # get the data 320 | temp <- subset(subData, subData$rt > subCDFs[j - 1] & 321 | subData$rt <= subCDFs[j]) 322 | 323 | # log the proportion error 324 | cafData[i, j] <- sum(temp$accuracy == 0) / nrow(subData) 325 | 326 | } 327 | 328 | ## do the final bin manually 329 | if(j == length(quantiles) + 1){ 330 | 331 | # get the data 332 | temp <- subset(subData, subData$rt > subCDFs[j - 1]) 333 | 334 | # log the proportion error 335 | cafData[i, j] <- sum(temp$accuracy == 0 )/ nrow(subData) 336 | } 337 | 338 | } # end of loop over quantiles 339 | 340 | 341 | } # end of loop over subjects 342 | 343 | # find the mean values 344 | cafData <- apply(cafData, 2, mean) 345 | 346 | 347 | # return the means 348 | return(cafData) 349 | 350 | } # end of multiple subjects loop 351 | 352 | 353 | } 354 | 355 | 356 | 357 | 358 | 359 | # get model CAFs ---------------------------------------------------------- 360 | 361 | ####THIS IS NOT CURRENTLY USED 362 | 363 | # Get model accuracy for each bin defined by human CAF input (each 25% of data 364 | # in human data, by default) 365 | getModelCAFs <- function(modelData, cafs){ 366 | 367 | # Empty vector to store results in 368 | props <- numeric(length(cafs) + 1) 369 | 370 | # loop across each CAF 371 | for(i in 1:length(cafs)){ 372 | 373 | # Do first bin manually 374 | if(i == 1){ 375 | x <- subset(modelData, modelData[, 1] <= cafs[i]) 376 | props[i] <- sum(x[, 2]) / length(x[, 1]) 377 | } 378 | 379 | 380 | # Do intermediate bins automatically 381 | if(i > 1 & i <= length(cafs)){ 382 | x <- subset(modelData, modelData[, 1] > cafs[i - 1] & 383 | modelData[, 1] <= cafs[i]) 384 | props[i] <- sum(x[, 2]) / length(x[, 1]) 385 | 386 | } 387 | 388 | # Do last bin manually 389 | if(i == length(cafs)){ 390 | x <- subset(modelData, modelData[, 1] > cafs[i]) 391 | props[i + 1] <- sum(x[, 2]) / length(x[, 1]) 392 | } 393 | 394 | } 395 | 396 | return(props) 397 | 398 | } 399 | -------------------------------------------------------------------------------- /R/plotting.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # plot fit (DSTP) --------------------------------------------------------- 4 | 5 | # Plot the fit of the DSTP model 6 | 7 | #'Plot the fit of the DSTP model to human data. 8 | #' 9 | #'\code{plotFitDSTP} will plot the fit of the model to human distributional 10 | #'data. 11 | #' 12 | #'This function is passed the object obtained by the model fitting procedure, 13 | #'as well as the human data and the condition that was fitted by the routine. 14 | #'The function simulates 100,000 trials (by default) using the best-fitting 15 | #'parameters found by the fit procedure. This synthetic data is then considered 16 | #'as the model's best predictions. The function then provides a plot of the 17 | #'model fit to cumulative distribution functions (CDFs) of correct response 18 | #'time, and conditional accuracy functions (CAFs) to show fit to accuracy data. 19 | #'The function also returns the data used to plot the fit so that the user can 20 | #'use their own plotting methods. 21 | #' 22 | #' @param modelFit The object obtained by the model fit. 23 | #' 24 | #' @param data The data frame of human data. 25 | #' @param conditionName The name of the condition that was fit. By default, 26 | #' it is set to conditionName = NULL. 27 | #' @param nTrials How many trials used to generate the model's best 28 | #' predictions. This should be higher than that used to fit the model. 29 | #' @param cdfs The cut-off points for the cumulative distribution functions. 30 | #' @param cafs The cut-off points for the conditional accuracy functions. 31 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 32 | #' subjects (multipleSubjects = TRUE) or to a single subject 33 | #' (multipleSubjects = FALSE). 34 | #' @param seed The value for the \code{set.seed} function to set random 35 | #' generation state. 36 | #' 37 | #' @return \code{cdfs} The CDF values requested by the user. 38 | #' @return \code{cafs} The CAF values requested by the user. 39 | #' @return \code{humanConCDFs} The response time cut-off values for each CDF 40 | #' bin for congruent human data. 41 | #' @return \code{humanInconCDFs} The response time cut-off values for each CDF 42 | #' bin for incongruent human data. 43 | #' @return \code{humanConCAFsRT} The mean response times for each bin of the 44 | #' CAF functions for congruent human data. 45 | #' @return \code{humanInconCAFsRT} The mean response times for each bin of the 46 | #' CAF functions for incongruent human data. 47 | #' @return \code{humanConCAFsError} The percent accuracy for each bin of the 48 | #' CAF functions for congruent human data. 49 | #' @return \code{humanConCAFsError} The percent accuracy for each bin of the 50 | #' CAF functions for congruent human data. 51 | #' @return \code{modelConCDFs} The quantile cut-off points for the model 52 | #' predictions for congruent data. A perfect fit would match the cdfs asked 53 | #' for by the user (e.g., .1, .3, .5, .7, .9). 54 | #' @return \code{modelInconCDFs} The quantile cut-off points for the model 55 | #' predictions for incongruent data. A perfect fit would match the cdfs asked 56 | #' for by the user (e.g., .1, .3, .5, .7, .9). 57 | #' @return \code{modelConCAFs} The percentage accuracy predicted for each CAF 58 | #' bin by the model for congruent data. 59 | #' @return \code{modelInconCAFs} The percentage accuracy predicted for each CAF 60 | #' bin by the model for incongruent data. 61 | #' 62 | #'@examples 63 | #'# Assume that the model was just fit to the data contained in 64 | #'# \code{exampleData} (condition "present") and saved to the variable called 65 | #'# "fit", then we can obtain a plot of that fit by using the following: 66 | #'# (Note this is a toy example with very low trial numbers to speed up the 67 | #'# example. For proper use, increase nTrials.) 68 | #' fit <- fitDSTP(data = exampleData, conditionName = "present", nTrials = 100) 69 | #' plot <- plotFitDSTP(modelFit = fit, data = exampleData, 70 | #' conditionName = "present", nTrials = 100) 71 | #' 72 | #'@export 73 | plotFitDSTP <- function(modelFit, data, conditionName = NULL, nTrials = 50000, 74 | cdfs = c(.1, .3, .5, .7, .9), cafs = c(.25, .50, .75), 75 | multipleSubjects = TRUE, seed = NULL){ 76 | 77 | # protect user's original plotting environment 78 | old_par <- par(no.readonly = TRUE) 79 | on.exit(par(old_par)) 80 | 81 | # Change the plotting window 82 | par(mfrow = c(1, 2)) 83 | 84 | 85 | 86 | #--- get the desired condition's data 87 | if(is.null(conditionName)){ 88 | conditionData <- data 89 | } else{ 90 | conditionData <- subset(data, data$condition == conditionName) 91 | } 92 | 93 | 94 | 95 | # get all of the distribution & proportion information from human data. 96 | # This returns a list with all information in separate "cotainers" for ease 97 | # of access & generalisation to different CDF and CAF sizes. 98 | if(multipleSubjects == TRUE){ 99 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 100 | } else { 101 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 102 | } 103 | 104 | 105 | 106 | 107 | #--- get model proportions by running the model 108 | 109 | # First, what were the best-fitting parameters? 110 | parms <- modelFit$bestParameters 111 | 112 | # simulate the DSTP model with these parameters 113 | modelData <- plotPredictionsDSTP(parms, 114 | n = nTrials, 115 | propsForModel = humanProportions, 116 | seed = seed) 117 | 118 | # Find model proportion predictions for 119 | # congruent and incongruent trials (CDF & CAFs) 120 | modelConCDF <- modelData$modelCongruentCDF 121 | modelConCAF <- modelData$modelCongruentCAF 122 | 123 | modelInconCDF <- modelData$modelIncongruentCDF 124 | modelInconCAF <- modelData$modelIncongruentCAF 125 | 126 | 127 | #--- Generate the return data to go back to the user 128 | # Pass the human proportions to an object with a shorter name to save typing 129 | x <- humanProportions 130 | returnData <- list(cdfs = cdfs, 131 | cafs = cafs, 132 | humanCongruentCDFs = x$congruentCDFs, 133 | humanIncongruentCDFs = x$incongruentCDFs, 134 | humanCongruentCAFsRT = x$congruentCAFsRT, 135 | humanIncongruentCAFsRT = x$incongruentCAFsRT, 136 | humanCongruentCAFsError = x$congruentCAFsError, 137 | humanIncongruentCAFsError = x$incongruentCAFsError, 138 | modelCongruentCDFs = modelConCDF, 139 | modelIncongruentCDFs = modelInconCDF, 140 | modelCongruentCAFs = modelConCAF, 141 | modelIncongruentCAFs = modelInconCAF) 142 | 143 | 144 | #--- Plot the CDFs 145 | 146 | # first, find the response time boundaries to ensure plots are in bounds 147 | minRT <- min(humanProportions$congruentCDFs, humanProportions$incongruentCDFs) 148 | maxRT <- max(humanProportions$congruentCDFs, humanProportions$incongruentCDFs) 149 | 150 | # Incongruent human first 151 | plot(x = humanProportions$incongruentCDFs, y = cdfs, xlab = "Response Time", 152 | ylab = "Cumulative Probability", pch = 1, ylim = c(0, 1), 153 | xlim = c(minRT, maxRT)) 154 | lines(humanProportions$incongruentCDFs, modelInconCDF, type = "l", 155 | lty = 2) 156 | 157 | # Now congruent 158 | points(x = humanProportions$congruentCDFs, y = cdfs, pch = 19) 159 | lines(humanProportions$congruentCDFs, modelConCDF, type = "l", lty = 1) 160 | 161 | 162 | #--- Plot the CAFs 163 | minRT <- min(humanProportions$congruentCAFsRT, 164 | humanProportions$incongruentCAFsRT) 165 | maxRT <- max(humanProportions$congruentCAFsRT, 166 | humanProportions$incongruentCAFsRT) 167 | 168 | # Incongruent data 169 | plot(x = humanProportions$incongruentCAFsRT, 170 | y = humanProportions$incongruentCAFsError, 171 | xlab = "Response Time", ylab = "Accuracy", pch = 1, ylim = c(0.5, 1), 172 | xlim = c(minRT, maxRT)) 173 | lines(humanProportions$incongruentCAFsRT, modelInconCAF, type = "l", lty = 2) 174 | 175 | # Congruent data 176 | points(x = humanProportions$congruentCAFsRT, 177 | y = humanProportions$congruentCAFsError, 178 | pch = 19) 179 | lines(humanProportions$congruentCAFsRT, modelConCAF, type = "l", lty = 1) 180 | 181 | # Add legend 182 | legend("bottom", c("Congruent","Incongruent"), cex=1, pch=c(19, 1), 183 | lty=1:2, bty="n"); 184 | 185 | # Change the plotting window 186 | par(mfrow = c(1, 1)) 187 | 188 | # Return the information used to plot the model so the user can use their own 189 | # software should they so please. 190 | return(returnData) 191 | 192 | } 193 | 194 | 195 | 196 | 197 | # plot fit (SSP) ---------------------------------------------------------- 198 | #'Plot the fit of the SSP model to human data. 199 | #' 200 | #'\code{plotFitSSP} will plot the fit of the model to human distributional 201 | #'data. 202 | #' 203 | #'This function is passed the object obtained by the model fitting procedure, 204 | #'as well as the human data and the condition that was fitted by the routine. 205 | #'The function simulates 100,000 trials (by default) using the best-fitting 206 | #'parameters found by the fit procedure. This synthetic data is then considered 207 | #'as the model's best predictions. The function then provides a plot of the 208 | #'model fit to cumulative distribution functions (CDFs) of correct response 209 | #'time, and conditional accuracy functions (CAFs) to show fit to accuracy data. 210 | #'The function also returns the data used to plot the fit so that the user can 211 | #'use their own plotting methods. 212 | #' 213 | #' @param modelFit The object obtained by the model fit. 214 | #' 215 | #' @param data The data frame of human data. 216 | #' @param conditionName The name of the condition that was fit. By default, 217 | #' it is set to conditionName = NULL. 218 | #' @param nTrials How many trials used to generate the model's best 219 | #' predictions. This should be higher than that used to fit the model. 220 | #' @param cdfs The cut-off points for the cumulative distribution functions. 221 | #' @param cafs The cut-off points for the conditional accuracy functions. 222 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 223 | #' subjects (multipleSubjects = TRUE) or to a single subject 224 | #' (multipleSubjects = FALSE). 225 | #' @param seed The value for the \code{set.seed} function to set random 226 | #' generation state. 227 | #' 228 | #' @return \code{cdfs} The CDF values requested by the user. 229 | #' @return \code{cafs} The CAF values requested by the user. 230 | #' @return \code{humanConCDFs} The response time cut-off values for each CDF 231 | #' bin for congruent human data. 232 | #' @return \code{humanInconCDFs} The response time cut-off values for each CDF 233 | #' bin for incongruent human data. 234 | #' @return \code{humanConCAFsRT} The mean response times for each bin of the 235 | #' CAF functions for congruent human data. 236 | #' @return \code{humanInconCAFsRT} The mean response times for each bin of the 237 | #' CAF functions for incongruent human data. 238 | #' @return \code{humanConCAFsError} The percent accuracy for each bin of the 239 | #' CAF functions for congruent human data. 240 | #' @return \code{humanConCAFsError} The percent accuracy for each bin of the 241 | #' CAF functions for congruent human data. 242 | #' @return \code{modelConCDFs} The quantile cut-off points for the model 243 | #' predictions for congruent data. A perfect fit would match the cdfs asked 244 | #' for by the user (e.g., .1, .3, .5, .7, .9). 245 | #' @return \code{modelInconCDFs} The quantile cut-off points for the model 246 | #' predictions for incongruent data. A perfect fit would match the cdfs asked 247 | #' for by the user (e.g., .1, .3, .5, .7, .9). 248 | #' @return \code{modelConCAFs} The percentage accuracy predicted for each CAF 249 | #' bin by the model for congruent data. 250 | #' @return \code{modelInconCAFs} The percentage accuracy predicted for each CAF 251 | #' bin by the model for incongruent data. 252 | #' 253 | #'@examples 254 | #'# Assume that the model was just fit to the data contained in 255 | #'# \code{exampleData} (condition "present") and saved to the variable called 256 | #'# "fit", then we can obtain a plot of that fit by using the following: 257 | #' # (Note this is a toy example with very low trial numbers to speed up the 258 | #' # example. For proper use, increase nTrials.) 259 | #' fit <- fitSSP(data = exampleData, conditionName = "present", nTrials = 100) 260 | #' plot <- plotFitSSP(modelFit = fit, data = exampleData, 261 | #' conditionName = "present", nTrials = 100) 262 | #' 263 | #'@export 264 | plotFitSSP <- function(modelFit, 265 | data, 266 | conditionName = NULL, 267 | nTrials = 50000, 268 | cdfs = c(.1, .3, .5, .7, .9), 269 | cafs = c(.25, .50, .75), 270 | multipleSubjects = TRUE, 271 | seed = NULL){ 272 | 273 | # protect user's original plotting environment 274 | old_par <- par(no.readonly = TRUE) 275 | on.exit(par(old_par)) 276 | 277 | # Change the plotting window 278 | par(mfrow = c(1, 2)) 279 | 280 | 281 | #--- get the desired condition's data 282 | if(is.null(conditionName)){ 283 | conditionData <- data 284 | } else{ 285 | conditionData <- subset(data, data$condition == conditionName) 286 | } 287 | 288 | # get all of the distribution & proportion information from human data. 289 | # This returns a list with all information in separate "cotainers" for ease 290 | # of access & generalisation to different CDF and CAF sizes. 291 | if(multipleSubjects == TRUE){ 292 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 293 | } else { 294 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 295 | } 296 | 297 | #--- get model proportions by running the model 298 | 299 | # First, what were the best-fitting parameters? 300 | parms <- modelFit$bestParameters 301 | 302 | # simulate the DSTP model with these parameters 303 | modelData <- plotPredictionsSSP(parms, 304 | n = nTrials, 305 | propsForModel = humanProportions, 306 | seed = seed) 307 | 308 | # Find model proportion predictions for 309 | # congruent and incongruent trials (CDF & CAFs) 310 | modelConCDF <- modelData$modelCongruentCDF 311 | modelConCAF <- modelData$modelCongruentCAF 312 | 313 | modelInconCDF <- modelData$modelIncongruentCDF 314 | modelInconCAF <- modelData$modelIncongruentCAF 315 | 316 | 317 | #--- Generate the return data to go back to the user 318 | # Pass the human proportions to an object with a shorter name to save typing 319 | x <- humanProportions 320 | returnData <- list(cdfs = cdfs, 321 | cafs = cafs, 322 | humanCongruentCDFs = x$congruentCDFs, 323 | humanIncongruentCDFs = x$incongruentCDFs, 324 | humanCongruentCAFsRT = x$congruentCAFsRT, 325 | humanIncongruentCAFsRT = x$incongruentCAFsRT, 326 | humanCongruentCAFsError = x$congruentCAFsError, 327 | humanIncongruentCAFsError = x$incongruentCAFsError, 328 | modelCongruentCDFs = modelConCDF, 329 | modelIncongruentCDFs = modelInconCDF, 330 | modelCongruentCAFs = modelConCAF, 331 | modelIncongruentCAFs = modelInconCAF) 332 | 333 | 334 | 335 | #--- Plot the CDFs 336 | 337 | # first, find the response time boundaries to ensure plots are in bounds 338 | minRT <- min(humanProportions$congruentCDFs, 339 | humanProportions$incongruentCDFs) 340 | maxRT <- max(humanProportions$congruentCDFs, 341 | humanProportions$incongruentCDFs) 342 | 343 | # Incongruent human first 344 | plot(x = humanProportions$incongruentCDFs, y = cdfs, xlab = "Response Time", 345 | ylab = "Cumulative Probability", pch = 1, ylim = c(0, 1), 346 | xlim = c(minRT, maxRT)) 347 | lines(humanProportions$incongruentCDFs, modelInconCDF, type = "l", 348 | lty = 2) 349 | 350 | # Now congruent 351 | points(x = humanProportions$congruentCDFs, y = cdfs, pch = 19) 352 | lines(humanProportions$congruentCDFs, modelConCDF, type = "l", lty = 1) 353 | 354 | 355 | #--- Plot the CAFs 356 | minRT <- min(humanProportions$congruentCAFsRT, 357 | humanProportions$incongruentCAFsRT) 358 | maxRT <- max(humanProportions$congruentCAFsRT, 359 | humanProportions$incongruentCAFsRT) 360 | 361 | # Incongruent data 362 | plot(x = humanProportions$incongruentCAFsRT, 363 | y = humanProportions$incongruentCAFsError, 364 | xlab = "Response Time", ylab = "Accuracy", pch = 1, ylim = c(0.5, 1), 365 | xlim = c(minRT, maxRT)) 366 | lines(humanProportions$incongruentCAFsRT, modelInconCAF, type = "l", lty = 2) 367 | 368 | # Congruent data 369 | points(x = humanProportions$congruentCAFsRT, 370 | y = humanProportions$congruentCAFsError, 371 | pch = 19) 372 | lines(humanProportions$congruentCAFsRT, modelConCAF, type = "l", lty = 1) 373 | 374 | # Add legend 375 | legend("bottom", c("Congruent","Incongruent"), cex=1, pch=c(19, 1), 376 | lty=1:2, bty="n"); 377 | 378 | # Change the plotting window 379 | par(mfrow = c(1, 1)) 380 | 381 | # Return the information used to plot the model so the user can use their own 382 | # software should they so please. 383 | return(returnData) 384 | 385 | } 386 | 387 | -------------------------------------------------------------------------------- /R/sspFunctions.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # simulate SSP ------------------------------------------------------------ 4 | 5 | #' Obtain simulated response times and accuracy from the SSP model 6 | #' 7 | #' \code{simulateSSP} generates synthetic data from the DSTP model in the 8 | #' form of response time (RT) in seconds and accuracy for both congruent and 9 | #' incongruent trials. 10 | #' 11 | #' This function can be employed by the user to generate synthetic data, but 12 | #' its main purpose is to be used by the fitting procedure to generate model 13 | #' predictions for a set of parameter values when trying to find the best- 14 | #' fitting values. 15 | #' 16 | #' @param parms The set of parameters to use to simulate the data. Must be 17 | #' contained in a vector in the order: \code{A}, \code{ter}, 18 | #' \code{p}, \code{rd}, \code{sda}. 19 | #' @param nTrials How many trials to simulate per congruency condition. 20 | #' @param var The variance of the diffusion process. By default this is set to 21 | #' 0.01. 22 | #' @param dt The diffusion scaling parameter (i.e., time steps). By default, 23 | #' this is set to 0.001. 24 | #' @param seed The value for the \code{set.seed} function to set random 25 | #' generation state. 26 | #' 27 | #' @examples 28 | #' 29 | #' # declare the parameters 30 | #' parms <- c(0.050, 0.300, 0.400, 0.040, 1.500) 31 | #' 32 | #' # simulate the data 33 | #' # (Note this is a toy example with very low trial numbers to speed up the 34 | #' # example. For proper use, increase nTrials.) 35 | #' modelData <- simulateSSP(parms, nTrials = 100) 36 | #' 37 | #' @return Returns a data frame with three columns: rt (response time) in 38 | #' seconds, accuracy of the model's response (1 for correct, 0 for error), and 39 | #' congruency condition. 40 | #' @useDynLib flankr 41 | #' @importFrom Rcpp sourceCpp 42 | #' @export 43 | simulateSSP <- function(parms, 44 | nTrials, 45 | var = 0.01, 46 | dt = 1/1000, 47 | seed = NULL){ 48 | 49 | # transfer nTrials to shorter name 50 | n <- nTrials 51 | 52 | # Set random number seed, so same predictions occur every time. 53 | if(!is.null(seed)){ 54 | set.seed(seed) 55 | } 56 | 57 | 58 | # initialise empty matrix for simulation data with two columns 59 | # (RT & accuracy) and with rows = number of trials 60 | trialData <- matrix(0, nrow = n * 2, ncol = 3) 61 | colnames(trialData) <- c("rt", "accuracy", "congruency") 62 | trialData <- data.frame(trialData) 63 | 64 | # first generate congruent data by calling the C++ function 65 | trialData[1:n, 1:2] <- getSSP_new(parms, 66 | trialType = 1, 67 | nTrials = n, 68 | dt, 69 | var) 70 | trialData[1:n, 3] <- "congruent" 71 | 72 | # now do incongruent data 73 | trialData[(n + 1):(n * 2), 1:2] <- getSSP_new(parms, 74 | trialType = 2, 75 | nTrials = n, 76 | dt, 77 | var) 78 | trialData[(n + 1):(n * 2), 3] <- "incongruent" 79 | 80 | 81 | return(trialData); 82 | 83 | } # end of function 84 | 85 | 86 | 87 | 88 | 89 | # fit SSP ----------------------------------------------------------------- 90 | 91 | 92 | #' Fit the SSP model to human data 93 | #' 94 | #' \code{fitSSP} fits the SSP model to a single experimental condition of 95 | #' human data (besides congruency, which it accounts for simutaneously). 96 | #' 97 | #' This function can be employed by the user to find the best-fitting 98 | #' parameters of the SSP model to fit the human data of a single experimental 99 | #' condition. The fitting procedure accounts for congruent and incongruent 100 | #' trials simultaneously. The fit is obtained by a gradient-descent method 101 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 102 | #' fit to the proportion of data contained in human CDF and CAF distributional 103 | #' data. 104 | #' 105 | #' @param data A data frame containing human data. See \code{?exampleData} for 106 | #' data formatted correctly. 107 | #' 108 | #' @param conditionName If there is an additional experimental manipulation 109 | #' (i.e., other than target congruency) the model can only be fit to one at a 110 | #' time. Tell the function which condition is currently being fit by passing 111 | #' a string to the function (e.g., "present"). The function by default assumes 112 | #' no additional condition (e.g., conditionName is set to NULL). 113 | #' 114 | #' @param parms A vector of starting parameters to use in the minimisation 115 | #' routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 116 | #' \code{sda}. 117 | #' 118 | #' @param cdfs A vector of quantile values for cumulative distribution functions 119 | #' to be estimated from the human data. The model will attempt to find the 120 | #' best-fitting parameters that match this distributional data. 121 | #' 122 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 123 | #' estimated from the human data. The model will attempt to find the best- 124 | #' fitting parameters that match this distributional data. 125 | #' 126 | #' @param maxParms A vector containing upper limits on possible parameter 127 | #' values. 128 | #' 129 | #' @param nTrials An integer stating how many trials to simulate per iteration 130 | #' of the fitting cycle for each congruency type. 131 | #' 132 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 133 | #' subjects (multipleSubjects = TRUE) or to a single subject 134 | #' (multipleSubjects = FALSE). 135 | #' 136 | #' @param seed The value for the \code{set.seed} function to set random 137 | #' generation state. 138 | #' 139 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 140 | #' by the current fit run. 141 | #' 142 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 143 | #' current fit run. 144 | #' 145 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 146 | #' obtained by the current fit run. This is calculated using the BIC equation 147 | #' for binned data, hence bBIC (binned BIC). 148 | #' 149 | #' @examples 150 | #' # Load the example data the comes with the \code{flankr} package 151 | #' data(exampleData) 152 | #' 153 | #' # Fit the model to the condition "present" in the example data set using 154 | #' # the default settings in the model. 155 | #' # (Note this is a toy example with very low trial numbers to speed up the 156 | #' # example. For proper use, increase nTrials.) 157 | #' fit <- fitSSP(data = exampleData, conditionName = "present", nTrials = 100) 158 | #' 159 | #'@export 160 | fitSSP<- function(data, conditionName = NULL, 161 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500), 162 | cdfs = c(.1, .3, .5, .7, .9), cafs = c(.25, .50, .75), 163 | maxParms = c(1, 1, 1, 1, 3), nTrials = 50000, 164 | multipleSubjects = TRUE, 165 | seed = NULL){ 166 | 167 | # declare the scaling on the parameters 168 | parscale <- c(0.1, 1.0, 1.0, 1.0, 10) 169 | 170 | # get the desired condition's data 171 | if(is.null(conditionName)){ 172 | conditionData <- data 173 | } else{ 174 | conditionData <- subset(data, data$condition == conditionName) 175 | } 176 | 177 | # get all of the distribution & proportion information from human data. 178 | # This returns a list with all information in separate "cotainers" for ease 179 | # of access & generalisation to different CDF and CAF sizes. 180 | if(multipleSubjects == TRUE){ 181 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 182 | } else { 183 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 184 | } 185 | 186 | message("Model Fit Running. Please Wait...") 187 | 188 | 189 | # perform the fit 190 | fit <- optim(parms, fn = fitFunctionSSP, 191 | humanProportions = humanProportions, 192 | n = nTrials, maxParms = maxParms, seed = seed, 193 | control = list(parscale = parscale)) 194 | 195 | # what are the best-fitting parameters? 196 | bestParameters <- round(fit$par, 3) 197 | 198 | # what is the fit statistic value? 199 | g2 <- fit$value 200 | 201 | # get the approximate BIC value 202 | bBIC <- bBIC(humanProportions, model = "SSP", parms = bestParameters, 203 | nTrials = nTrials) 204 | 205 | # put all results into a list, and return the list to the user 206 | modelFit <- list(bestParameters = bestParameters, g2 = g2, 207 | bBIC = bBIC) 208 | 209 | message("Model Fit Finished.") 210 | 211 | return(modelFit) 212 | 213 | } # end of function 214 | 215 | 216 | 217 | # fit SSP (multiple) ------------------------------------------------------ 218 | 219 | #' Fit the SSP model to human data with multiple starting parameters 220 | #' 221 | #' \code{fitSSPMultiple} fits the SSP model to a single experimental condition 222 | #' of human data (besides congruency, which it accounts for simutaneously). 223 | #' 224 | #' This function can be employed by the user to find the best-fitting 225 | #' parameters of the SSP model to fit the human data of a single experimental 226 | #' condition. The fitting procedure accounts for congruent and incongruent 227 | #' trials simultaneously. The fit is obtained by a gradient-descent method 228 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 229 | #' fit to the proportion of data contained in human CDF and CAF distributional 230 | #' data. 231 | #' 232 | #' @param data A data frame containing human data. See \code{?exampleData} for 233 | #' data formatted correctly. 234 | #' 235 | #' @param conditionName If there is an additional experimental manipulation 236 | #' (i.e., other than target congruency) the model can only be fit to one at a 237 | #' time. Tell the function which condition is currently being fit by passing 238 | #' a string to the function (e.g., "present"). The function by default assumes 239 | #' no additional condition (e.g., conditionName is set to NULL). 240 | #' 241 | #' @param parms A vector of starting parameters to use in the minimisation 242 | #' routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 243 | #' \code{sda}. These parameters will be the starting point for the random 244 | #' parameters. 245 | #' 246 | #' @param var An integer stating the percentage of each parameter value that 247 | #' should be used for finding random parameter starting points. 248 | #' 249 | #' @param nParms An integer stating how many random starting points to explore 250 | #' 251 | #' @param cdfs A vector of quantile values for cumulative distribution functions 252 | #' to be estimated from the human data. The model will attempt to find the 253 | #' best-fitting parameters that match this distributional data. 254 | #' 255 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 256 | #' estimated from the human data. The model will attempt to find the best- 257 | #' fitting parameters that match this distributional data. 258 | #' 259 | #' @param maxParms A vector containing upper limits on possible parameter 260 | #' values. 261 | #' 262 | #' @param nTrials An integer stating how many trials to simulate per iteration 263 | #' of the fitting cycle for each congruency type. 264 | #' 265 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 266 | #' subjects (multipleSubjects = TRUE) or to a single subject 267 | #' (multipleSubjects = FALSE). 268 | #' 269 | #' @param seed The value for the \code{set.seed} function to set random 270 | #' generation state. 271 | #' 272 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 273 | #' by the current fit run. 274 | #' 275 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 276 | #' current fit run. 277 | #' 278 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 279 | #' obtained by the current fit run. This is calculated using the BIC equation 280 | #' for binned data, hence bBIC (binned BIC). 281 | #' 282 | #' @examples 283 | #' # Load the example data the comes with the \code{flankr} package 284 | #' data(exampleData) 285 | #' 286 | #' # Fit the model to the condition "present" in the example data set using 287 | #' # the default settings in the model. 288 | #' # (Note this is a toy example with very low trial numbers to speed up the 289 | #' # example. For proper use, increase nTrials.) 290 | #' \donttest{ 291 | #' fit <- fitMultipleSSP(data = exampleData, conditionName = "present", 292 | #' nTrials = 100) 293 | #'} 294 | #' 295 | #'@export 296 | fitMultipleSSP <- function(data, conditionName = NULL, 297 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500), 298 | var = 10, nParms = 20, cdfs = c(.1, .3, .5, .7, .9), 299 | cafs = c(.25, .50, .75), 300 | maxParms = c(1, 1, 1, 1, 2), nTrials = 50000, 301 | multipleSubjects = TRUE, 302 | seed = NULL){ 303 | 304 | # declare the scaling on the parameters 305 | parscale <- c(0.1, 1.0, 1.0, 1.0, 10) 306 | 307 | # get the desired condition's data 308 | if(is.null(conditionName)){ 309 | conditionData <- data 310 | } else{ 311 | conditionData <- subset(data, data$condition == conditionName) 312 | } 313 | 314 | # get all of the distribution & proportion information from human data. 315 | # This returns a list with all information in separate "cotainers" for ease 316 | # of access & generalisation to different CDF and CAF sizes. 317 | if(multipleSubjects == TRUE){ 318 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 319 | } else { 320 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 321 | } 322 | 323 | 324 | # get random starting parameters 325 | varParms <- (parms/ 100) * var 326 | parameters <- getRandomParms(parms, varParms, maxParms, nParms) 327 | 328 | #--- 329 | # Start the optimisation 330 | 331 | message("Model Fit Running. Please Wait...") 332 | 333 | # initialise best-fitting parameters & best fit so far 334 | bestFit <- .Machine$integer.max 335 | bestParms <- numeric(length(parms)) 336 | bestBIC <- .Machine$integer.max 337 | 338 | # start loop over all parameters now 339 | for(i in 1:nParms){ 340 | 341 | # get the current run's parameters 342 | currParms <- parameters[i, ] 343 | 344 | fit <- optim(currParms, fn = fitFunctionSSP, 345 | humanProportions = humanProportions, 346 | n = nTrials, 347 | maxParms = maxParms, 348 | seed = seed, 349 | control = list(parscale = parscale)) 350 | 351 | if(fit$value < bestFit){ 352 | bestFit <- fit$value 353 | bestParms <- round(fit$par, 3) 354 | bestBIC <- bBIC(humanProportions, model = "SSP", parms = bestParms, 355 | nTrials = nTrials) 356 | } 357 | 358 | } 359 | 360 | modelFit <- list(bestParameters = bestParms, g2 = bestFit, 361 | bBIC = bestBIC) 362 | 363 | message("Model Fit Finished.") 364 | 365 | return(modelFit) 366 | 367 | } # end of function 368 | 369 | 370 | 371 | 372 | # fit SSP (fixed) --------------------------------------------------------- 373 | 374 | #' Fit the SSP model to human data with some fixed parameters 375 | #' 376 | #' \code{fitSSP_fixed} fits the SSP model to a single experimental condition of 377 | #' human data (besides congruency, which it accounts for simutaneously). This 378 | #' function allows the user to fix some parameters (using the \code{fixed} 379 | #' variable). 380 | #' 381 | #' This function can be employed by the user to find the best-fitting 382 | #' parameters of the SSP model to fit the human data of a single experimental 383 | #' condition. The fitting procedure accounts for congruent and incongruent 384 | #' trials simultaneously. The fit is obtained by a gradient-descent method 385 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 386 | #' fit to the proportion of data contained in human CDF and CAF distributional 387 | #' data. 388 | #' 389 | #' @param data A data frame containing human data. See \code{?exampleData} for 390 | #' data formatted correctly. 391 | #' 392 | #' @param conditionName If there is an additional experimental manipulation 393 | #' (i.e., other than target congruency) the model can only be fit to one at a 394 | #' time. Tell the function which condition is currently being fit by passing 395 | #' a string to the function (e.g., "present"). The function by default assumes 396 | #' no additional condition (e.g., conditionName is set to NULL). 397 | #' 398 | #' @param parms A vector of starting parameters to use in the minimisation 399 | #' routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 400 | #' \code{sda}. 401 | #' 402 | #' @param cdfs A vector of quantile values for cumulative distribution functions 403 | #' to be estimated from the human data. The model will attempt to find the 404 | #' best-fitting parameters that match this distributional data. 405 | #' 406 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 407 | #' estimated from the human data. The model will attempt to find the best- 408 | #' fitting parameters that match this distributional data. 409 | #' 410 | #' @param maxParms A vector containing upper limits on possible parameter 411 | #' values. 412 | #' 413 | #' @param nTrials An integer stating how many trials to simulate per iteration 414 | #' of the fitting cycle for each congruency type. 415 | #' 416 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 417 | #' subjects (multipleSubjects = TRUE) or to a single subject 418 | #' (multipleSubjects = FALSE). 419 | #' 420 | #' @param fixed A vector of TRUE/FALSE stating whether each parameter should be 421 | #' fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 422 | #' order: \code{A}, \code{ter}, \code{p}, \code{rd}, \code{sda}. 423 | #' 424 | #' @param seed The value for the \code{set.seed} function to set random 425 | #' generation state. 426 | #' 427 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 428 | #' by the current fit run. 429 | #' 430 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 431 | #' current fit run. 432 | #' 433 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 434 | #' obtained by the current fit run. This is calculated using the BIC equation 435 | #' for binned data, hence bBIC (binned BIC). 436 | #' 437 | #' @examples 438 | #' # Load the example data the comes with the \code{flankr} package 439 | #' data(exampleData) 440 | #' # Fix the first parameter (A) during the fit. 441 | #' parms = c(0.050, 0.300, 0.400, 0.050, 1.500) 442 | #' fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE) 443 | #' 444 | #' # fit the model 445 | #' # (Note this is a toy example with very low trial numbers to speed up the 446 | #' # example. For proper use, increase nTrials.) 447 | #' \donttest{ 448 | #' fit <- fitSSP_fixed(exampleData, conditionName = "present", parms = parms, 449 | #' fixed = fixed, nTrials = 100) 450 | #'} 451 | #' 452 | #'@export 453 | fitSSP_fixed <- function(data, conditionName = NULL, 454 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500), 455 | cdfs = c(.1, .3, .5, .7, .9), cafs = c(.25, .50, .75), 456 | maxParms = c(1, 1, 1, 1, 2), nTrials = 50000, 457 | multipleSubjects = TRUE, 458 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE), 459 | seed = NULL){ 460 | 461 | # get the desired condition's data 462 | if(is.null(conditionName)){ 463 | conditionData <- data 464 | } else{ 465 | conditionData <- subset(data, data$condition == conditionName) 466 | } 467 | 468 | # get all of the distribution & proportion information from human data. 469 | # This returns a list with all information in separate "cotainers" for ease 470 | # of access & generalisation to different CDF and CAF sizes. 471 | if(multipleSubjects == TRUE){ 472 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 473 | } else { 474 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 475 | } 476 | 477 | message("Model Fit Running. Please Wait...") 478 | 479 | # perform the fit using the wrapper function 480 | fit <- optimFix_SSP(parms, fixed, humanProportions = humanProportions, 481 | n = nTrials, maxParms = maxParms, 482 | seed = seed) 483 | 484 | # what are the best-fitting parameters? 485 | bestParameters <- round(fit$fullPars, 3) 486 | 487 | # what is the fit statistic value? 488 | g2 <- fit$value 489 | 490 | # get the approximate BIC value 491 | bBIC <- bBIC_fixed(humanProportions, model = "SSP", parms = bestParameters, 492 | fixed = fixed, nTrials = nTrials) 493 | 494 | # put all results into a list, and return the list to the user 495 | modelFit <- list(bestParameters = bestParameters, g2 = g2, 496 | bBIC = bBIC) 497 | 498 | message("Model Fit Finished.") 499 | 500 | 501 | return(modelFit) 502 | 503 | 504 | } # end of function 505 | 506 | 507 | 508 | 509 | # fit SSP (multiple, fixed) ----------------------------------------------- 510 | 511 | #' Fit the SSP model to human data with mutiple starting parmaeters with some 512 | #' fixed parameters 513 | #' 514 | #' \code{fitMultipleSSP_fixed} fits the SSP model to a single experimental 515 | #' condition of human data (besides congruency, which it accounts for 516 | #' simutaneously). This function explores multiple starting parameters and 517 | #' allows user to fix model parameters. 518 | #' 519 | #' This function can be employed by the user to find the best-fitting 520 | #' parameters of the SSP model to fit the human data of a single experimental 521 | #' condition. The fitting procedure accounts for congruent and incongruent 522 | #' trials simultaneously. The fit is obtained by a gradient-descent method 523 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 524 | #' fit to the proportion of data contained in human CDF and CAF distributional 525 | #' data. Multiple starting points of parameters are used. 526 | #' 527 | #' @param data A data frame containing human data. See \code{?exampleData} for 528 | #' data formatted correctly. 529 | #' 530 | #' @param conditionName If there is an additional experimental manipulation 531 | #' (i.e., other than target congruency) the model can only be fit to one at a 532 | #' time. Tell the function which condition is currently being fit by passing 533 | #' a string to the function (e.g., "present"). The function by default assumes 534 | #' no additional condition (e.g., conditionName is set to NULL). 535 | #' 536 | #' @param parms A vector of starting parameters to use in the minimisation 537 | #' routine. Must be in the order: \code{A}, \code{ter}, \code{p}, \code{rd}, 538 | #' \code{sda}. These parameters will be the starting point for the random 539 | #' parameters. 540 | #' 541 | #' @param var An integer stating the percentage of each parameter value that 542 | #' should be used for finding random parameter starting points. 543 | #' 544 | #' @param nParms An integer stating how many random starting points to explore 545 | #' 546 | #' @param cdfs A vector of quantile values for cumulative distribution functions 547 | #' to be estimated from the human data. The model will attempt to find the 548 | #' best-fitting parameters that match this distributional data. 549 | #' 550 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 551 | #' estimated from the human data. The model will attempt to find the best- 552 | #' fitting parameters that match this distributional data. 553 | #' 554 | #' @param maxParms A vector containing upper limits on possible parameter 555 | #' values. 556 | #' 557 | #' @param nTrials An integer stating how many trials to simulate per iteration 558 | #' of the fitting cycle for each congruency type. 559 | #' 560 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 561 | #' subjects (multipleSubjects = TRUE) or to a single subject 562 | #' (multipleSubjects = FALSE). 563 | #' 564 | #' @param fixed A vector of TRUE/FALSE stating whether each parameter should be 565 | #' fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 566 | #' order: \code{A}, \code{ter}, \code{p}, \code{rd}, \code{sda}. 567 | #' 568 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 569 | #' by the current fit run. 570 | #' 571 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 572 | #' current fit run. 573 | #' 574 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 575 | #' obtained by the current fit run. This is calculated using the BIC equation 576 | #' for binned data, hence bBIC (binned BIC). 577 | #' 578 | #' @examples 579 | #' data(exampleData) 580 | #' # Fix the first parameter (A) during the fit. 581 | #' parms = c(0.050, 0.300, 0.400, 0.050, 1.500) 582 | #' fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE) 583 | #' 584 | #' # run the model 585 | #' # (Note this is a toy example with very low trial numbers to speed up the 586 | #' # example. For proper use, increase nTrials.) 587 | #' \donttest{ 588 | #' fit <- fitMultipleSSP_fixed(exampleData, conditionName = "present", 589 | #' parms = parms, fixed = fixed, nTrials = 100) 590 | #'} 591 | #'@export 592 | fitMultipleSSP_fixed <- function(data, conditionName = NULL, 593 | parms = c(0.050, 0.300, 0.400, 0.050, 1.500), 594 | var = 10, nParms = 20, 595 | cdfs = c(.1, .3, .5, .7, .9), 596 | cafs = c(.25, .50, .75), 597 | maxParms = c(1, 1, 1, 1, 2), 598 | nTrials = 50000, multipleSubjects = TRUE, 599 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE)){ 600 | 601 | 602 | # get the desired condition's data 603 | if(is.null(conditionName)){ 604 | conditionData <- data 605 | } else{ 606 | conditionData <- subset(data, data$condition == conditionName) 607 | } 608 | 609 | # get all of the distribution & proportion information from human data. 610 | # This returns a list with all information in separate "cotainers" for ease 611 | # of access & generalisation to different CDF and CAF sizes. 612 | if(multipleSubjects == TRUE){ 613 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 614 | } else { 615 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 616 | } 617 | 618 | 619 | # get random starting parameters 620 | varParms <- (parms/ 100) * var 621 | parameters <- getRandomParms(parms, varParms, maxParms, nParms) 622 | 623 | #--- 624 | # Start the optimisation 625 | 626 | message("Model Fit Running. Please Wait...") 627 | 628 | 629 | 630 | # initialise best-fitting parameters & best fit so far 631 | bestFit <- .Machine$integer.max 632 | bestParms <- numeric(length(parms)) 633 | bestBIC <- .Machine$integer.max 634 | 635 | # start loop over all parameters now 636 | for(i in 1:nParms){ 637 | 638 | # get the current run's parameters 639 | currParms <- parameters[i, ] 640 | 641 | # check whether any parameter needs to be fixed 642 | for(i in 1:length(currParms)){ 643 | if(fixed[i] == TRUE){ 644 | currParms[i] <- parms[i] 645 | } 646 | } 647 | 648 | 649 | # run the fit whilst fixing necessary parameters 650 | fit <- optimFix_SSP(parms, fixed, humanProportions = humanProportions, 651 | n = nTrials, maxParms = maxParms) 652 | 653 | if(fit$value < bestFit){ 654 | bestFit <- fit$value 655 | bestParms <- round(fit$fullPars, 3) 656 | bestBIC <- bBIC_fixed(humanProportions, model = "SSP", parms = bestParms, 657 | fixed = fixed, nTrials = nTrials) 658 | 659 | } 660 | 661 | } 662 | 663 | modelFit <- list(bestParameters = bestParms, g2 = bestFit, 664 | bBIC = bestBIC) 665 | 666 | 667 | message("Model Fit Finished.") 668 | 669 | 670 | return(modelFit) 671 | 672 | } # end of function 673 | 674 | 675 | 676 | 677 | 678 | # predicted proportions SSP ----------------------------------------------- 679 | 680 | # Get the predicted proportions from the SSP model 681 | predictionsSSP<- function(parms, 682 | n, 683 | propsForModel, 684 | dt = 0.001, 685 | var = 0.01, 686 | seed = NULL){ 687 | 688 | # parms = parameters for the model run 689 | # n = number of trials per congruency condition 690 | # propsForModel = CDF & CAF distributional information 691 | 692 | # Set random number seed, so same predictions occur every time. 693 | if(!is.null(seed)){ 694 | set.seed(seed) 695 | } 696 | 697 | # Run model to get congruent RTs 698 | modelCon <- getSSP_new(parms, 699 | trialType = 1, 700 | nTrials = n, 701 | dt, 702 | var) 703 | 704 | modelConCDF <- getCDFProps(propsForModel$congruentCDFs, modelCon) 705 | modelConCAF <- getCAFProps(propsForModel$congruentCAFsCutoff, modelCon) 706 | 707 | # Run model to get incontruent RTs 708 | modelIncon <- getSSP_new(parms, 709 | trialType = 2, 710 | nTrials = n, 711 | dt, 712 | var) 713 | 714 | modelInconCDF <- getCDFProps(propsForModel$incongruentCDFs, modelIncon) 715 | modelInconCAF <- getCAFProps(propsForModel$incongruentCAFsCutoff, modelIncon) 716 | 717 | modelProps <- list(modelCongruentCDF = modelConCDF, 718 | modelCongruentCAF = modelConCAF, 719 | modelIncongruentCDF = modelInconCDF, 720 | modelIncongruentCAF = modelInconCAF) 721 | 722 | 723 | return(modelProps) 724 | 725 | } 726 | 727 | 728 | 729 | 730 | # plot predictions ------------------------------------------------------- 731 | 732 | 733 | # Get the predicted Quantiles from the DSTP model. 734 | # This returns quantiles, not proportion per bin 735 | # e.g., c(.1, .3, .5, .7, .9) not c(.1, .2, .2, .2, .2, 1) 736 | plotPredictionsSSP <- function(parms, n, propsForModel, 737 | dt = 0.001, var = 0.01, seed = NULL){ 738 | 739 | # parms = parameters for the model run 740 | # n = number of trials per congruency condition 741 | # propsForModel = CDF & CAF distributional information 742 | 743 | # Set random number seed, so same predictions occur every time. 744 | if(!is.null(seed)){ 745 | set.seed(seed) 746 | } 747 | 748 | # Run model to get congruent RTs 749 | modelCon <- getSSP_new(parms, trialType = 1, nTrials = n, dt, var) 750 | modelConCDF <- getModelCDFs(modelCon, propsForModel$congruentCDFs) 751 | modelConCAF <- getModelCAFs(modelCon, propsForModel$congruentCAFsCutoff) 752 | 753 | # Run model to get incontruent RTs 754 | modelIncon <- getSSP_new(parms, trialType = 2, nTrials = n, dt, var) 755 | modelInconCDF <- getModelCDFs(modelIncon, propsForModel$incongruentCDFs) 756 | modelInconCAF <- getModelCAFs(modelIncon, propsForModel$incongruentCAFsCutoff) 757 | 758 | modelProps <- list(modelCongruentCDF = modelConCDF, 759 | modelCongruentCAF = modelConCAF, 760 | modelIncongruentCDF = modelInconCDF, 761 | modelIncongruentCAF = modelInconCAF) 762 | 763 | return(modelProps) 764 | } 765 | 766 | -------------------------------------------------------------------------------- /R/dstpFunctions.R: -------------------------------------------------------------------------------- 1 | 2 | # simulate DSTP ----------------------------------------------------------- 3 | 4 | #' Obtain simulated response times and accuracy from the DSTP model 5 | #' 6 | #' \code{simulateDSTP} generates synthetic data from the DSTP model in the 7 | #' form of response time (RT) in seconds and accuracy for both congruent and 8 | #' incongruent trials. 9 | #' 10 | #' This function can be employed by the user to generate synthetic data, but 11 | #' its main purpose is to be used by the fitting procedure to generate model 12 | #' predictions for a set of parameter values when trying to find the best- 13 | #' fitting values.d 14 | #' 15 | #' @param parms The set of parameters to use to simulate the data. Must be 16 | #' contained in a vector in the order: \code{A}, \code{C}, \code{driftTarget}, 17 | #' \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 18 | #' @param nTrials How many trials to simulate per congruency condition. 19 | #' @param var The variance of the diffusion process. By default this is set to 20 | #' 0.01. 21 | #' @param dt The diffusion scaling parameter (i.e., time steps). By default, 22 | #' this is set to 0.001. 23 | #' @param seed The value for the \code{set.seed} function to set random 24 | #' generation state. 25 | #' 26 | #' @examples 27 | #' # declare the parameters 28 | #' parms <- c(0.070, 0.086, 0.045, 0.065, 0.368, 1.575, 0.225) 29 | #' 30 | #' # simulate the data. (Note this is a toy example with very low trial numbers 31 | #' # to speed up the example. For proper use, increase nTrials.) 32 | #' modelData <- simulateDSTP(parms, nTrials = 100) 33 | #' 34 | #' @return Returns a data frame with three columns: rt (response time) in 35 | #' seconds, accuracy of the model's response (1 for correct, 0 for error), and 36 | #' congruency condition. 37 | #' @useDynLib flankr 38 | #' @importFrom Rcpp sourceCpp 39 | #' @export 40 | simulateDSTP <- function(parms, nTrials, var = 0.01, 41 | dt = 1/1000, seed = NULL){ 42 | 43 | # transfer nTrials to shorter name 44 | n <- nTrials 45 | 46 | # Set random number seed, so same predictions occur every time. 47 | if(!is.null(seed)){ 48 | set.seed(seed) 49 | } 50 | 51 | # initialise empty matrix for simulation data with two columns 52 | # (RT & accuracy) and with rows = number of trials 53 | trialData <- matrix(0, nrow = n * 2, ncol = 3) 54 | colnames(trialData) <- c("rt", "accuracy", "congruency") 55 | trialData <- data.frame(trialData) 56 | 57 | # first generate congruent data by calling the C++ function 58 | trialData[1:n, 1:2] <- getDSTP_new(parms, 59 | trialType = 1, 60 | nTrials = n, 61 | dt, var) 62 | trialData[1:n, 3] <- "congruent" 63 | 64 | # now do incongruent data 65 | trialData[(n + 1):(n * 2), 1:2] <- getDSTP_new(parms, 66 | trialType = 2, 67 | nTrials = n, 68 | dt, var) 69 | trialData[(n + 1):(n * 2), 3] <- "incongruent" 70 | 71 | 72 | return(trialData); 73 | 74 | } # end of function 75 | 76 | 77 | 78 | # fit DSTP ---------------------------------------------------------------- 79 | #' Fit the DSTP model to human data 80 | #' 81 | #' \code{fitDSTP} fits the DSTP model to a single experimental condition of 82 | #' human data (besides congruency, which it accounts for simutaneously). 83 | #' 84 | #' This function can be employed by the user to find the best-fitting 85 | #' parameters of the DSTP model to fit the human data of a single experimental 86 | #' condition. The fitting procedure accounts for congruent and incongruent 87 | #' trials simultaneously. The fit is obtained by a gradient-descent method 88 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 89 | #' fit to the proportion of data contained in human CDF and CAF distributional 90 | #' data. 91 | #' 92 | #' @param data A data frame containing human data. See \code{?exampleData} for 93 | #' data formatted correctly. 94 | #' 95 | #' @param conditionName If there is an additional experimental manipulation 96 | #' (i.e., other than target congruency) the model can only be fit to one at a 97 | #' time. Tell the function which condition is currently being fit by passing 98 | #' a string to the function (e.g., "present"). The function by default assumes 99 | #' no additional condition (e.g., conditionName is set to NULL). 100 | #' 101 | #' @param parms A vector of starting parameters to use in the minimisation 102 | #' routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 103 | #' \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 104 | #' 105 | #' @param cdfs A vector of quantile values for cumulative distribution functions 106 | #' to be estimated from the human data. The model will attempt to find the 107 | #' best-fitting parameters that match this distributional data. 108 | #' 109 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 110 | #' estimated from the human data. The model will attempt to find the best- 111 | #' fitting parameters that match this distributional data. 112 | #' 113 | #' @param maxParms A vector containing upper limits on possible parameter 114 | #' values. 115 | #' 116 | #' @param nTrials An integer stating how many trials to simulate per iteration 117 | #' of the fitting cycle for each congruency type. 118 | #' 119 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 120 | #' subjects (multipleSubjects = TRUE) or to a single subject 121 | #' (multipleSubjects = FALSE). 122 | #' 123 | #' @param seed The value for the \code{set.seed} function to set random 124 | #' generation state. 125 | #' 126 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 127 | #' by the current fit run. 128 | #' 129 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 130 | #' current fit run. 131 | #' 132 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 133 | #' obtained by the current fit run. This is calculated using the BIC equation 134 | #' for binned data, hence bBIC (binned BIC). 135 | #' 136 | #' @examples 137 | #' # Load the example data the comes with the \code{flankr} package 138 | #' data(exampleData) 139 | #' 140 | #' # Fit the model to the condition "present" in the example data set using 141 | #' # the default settings in the model. 142 | #' # (Note this is a toy example with very low trial numbers to speed up the 143 | #' # example. For proper use, increase nTrials.) 144 | #' \donttest{ 145 | #' fit <- fitDSTP(data = exampleData, conditionName = "present", nTrials = 100) 146 | #'} 147 | #' 148 | #'@export 149 | fitDSTP <- function(data, conditionName = NULL, 150 | parms = c(0.145, 0.08, 0.10, 0.07, 0.325, 1.30, 0.240), 151 | cdfs = c(.1, .3, .5, .7, .9), cafs = c(.25, .50, .75), 152 | maxParms = c(1, 1, 1, 1, 1, 2, 1), nTrials = 50000, 153 | multipleSubjects = TRUE, 154 | seed = NULL){ 155 | 156 | 157 | # declare the scaling on the parameters 158 | parscale <- c(0.1, 0.1, 0.1, 0.1, 0.1, 1.0, 0.1) 159 | 160 | # get the desired condition's data 161 | if(is.null(conditionName)){ 162 | conditionData <- data 163 | } else{ 164 | conditionData <- subset(data, data$condition == conditionName) 165 | } 166 | 167 | # get all of the distribution & proportion information from human data. 168 | # This returns a list with all information in separate "containers" for ease 169 | # of access & generalisation to different CDF and CAF sizes. 170 | if(multipleSubjects == TRUE){ 171 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 172 | } else { 173 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 174 | } 175 | 176 | message("Model Fit Running. Please Wait...") 177 | 178 | 179 | # perform the fit 180 | fit <- optim(parms, fn = fitFunctionDSTP, 181 | humanProportions = humanProportions, 182 | n = nTrials, seed = seed, 183 | maxParms = maxParms, 184 | control = list(parscale = parscale)) 185 | 186 | # what are the best-fitting parameters? 187 | bestParameters <- round(fit$par, 3) 188 | 189 | # what is the fit statistic value? 190 | g2 <- fit$value 191 | 192 | # get the approximate BIC value 193 | bBIC <- bBIC(humanProportions, model = "DSTP", parms = bestParameters, 194 | nTrials = nTrials) 195 | 196 | # put all results into a list, and return the list to the user 197 | modelFit <- list(bestParameters = bestParameters, g2 = g2, 198 | bBIC = bBIC) 199 | 200 | message("Model Fit Finished.") 201 | 202 | 203 | return(modelFit) 204 | 205 | 206 | } # end of function 207 | 208 | 209 | 210 | # fit DSTP (multiple) ----------------------------------------------------- 211 | #' Fit the DSTP model to human data with mutiple starting parmaeters 212 | #' 213 | #' \code{fitMultipleDSTP} fits the DSTP model to a single experimental condition 214 | #' of human data (besides congruency, which it accounts for simutaneously). 215 | #' This function explores multiple starting parameters. 216 | #' 217 | #' This function can be employed by the user to find the best-fitting 218 | #' parameters of the DSTP model to fit the human data of a single experimental 219 | #' condition. The fitting procedure accounts for congruent and incongruent 220 | #' trials simultaneously. The fit is obtained by a gradient-descent method 221 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 222 | #' fit to the proportion of data contained in human CDF and CAF distributional 223 | #' data. Multiple starting points of parameters are used. 224 | #' 225 | #' @param data A data frame containing human data. See \code{?exampleData} for 226 | #' data formatted correctly. 227 | #' 228 | #' @param conditionName If there is an additional experimental manipulation 229 | #' (i.e., other than target congruency) the model can only be fit to one at a 230 | #' time. Tell the function which condition is currently being fit by passing 231 | #' a string to the function (e.g., "present"). The function by default assumes 232 | #' no additional condition (e.g., conditionName is set to NULL). 233 | #' 234 | #' @param parms A vector of starting parameters to use in the minimisation 235 | #' routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 236 | #' \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 237 | #' These parameters will be the starting point for the random parameters. 238 | #' 239 | #' @param var An integer stating the percentage of each parameter value that 240 | #' should be used for finding random parameter starting points. 241 | #' 242 | #' @param nParms An integer stating how many random starting points to explore 243 | #' 244 | #' @param cdfs A vector of quantile values for cumulative distribution functions 245 | #' to be estimated from the human data. The model will attempt to find the 246 | #' best-fitting parameters that match this distributional data. 247 | #' 248 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 249 | #' estimated from the human data. The model will attempt to find the best- 250 | #' fitting parameters that match this distributional data. 251 | #' 252 | #' @param maxParms A vector containing upper limits on possible parameter 253 | #' values. 254 | #' 255 | #' @param nTrials An integer stating how many trials to simulate per iteration 256 | #' of the fitting cycle for each congruency type. 257 | #' 258 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 259 | #' subjects (multipleSubjects = TRUE) or to a single subject 260 | #' (multipleSubjects = FALSE). 261 | #' 262 | #' @param seed The value for the \code{set.seed} function to set random 263 | #' generation state. 264 | #' 265 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 266 | #' by the current fit run. 267 | #' 268 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 269 | #' current fit run. 270 | #' 271 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 272 | #' obtained by the current fit run. This is calculated using the BIC equation 273 | #' for binned data, hence bBIC (binned BIC). 274 | #' 275 | #' @examples 276 | #' # Load the example data the comes with the \code{flankr} package 277 | #' data(exampleData) 278 | #' 279 | #' # Fit the model to the condition "present" in the example data set using 280 | #' # the default settings in the model. 281 | #' # (Note this is a toy example with very low trial numbers to speed up the 282 | #' # example. For proper use, increase nTrials.) 283 | #' \donttest{ 284 | #' fit <- fitMultipleDSTP(data = exampleData, conditionName = "present", nTrials = 100) 285 | #'} 286 | #' 287 | #'@export 288 | fitMultipleDSTP <- function(data, 289 | conditionName = NULL, 290 | parms = c(0.145, 0.08, 0.10, 0.07, 0.325, 1.30, 0.240), 291 | var = 10, 292 | nParms = 20, 293 | cdfs = c(.1, .3, .5, .7, .9), 294 | cafs = c(.25, .50, .75), 295 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 296 | nTrials = 50000, 297 | multipleSubjects = TRUE, 298 | seed = NULL){ 299 | 300 | 301 | # declare the scaling on the parameters 302 | parscale <- c(0.1, 0.1, 0.1, 0.1, 0.1, 1.0, 0.1) 303 | 304 | # get the desired condition's data 305 | if(is.null(conditionName)){ 306 | conditionData <- data 307 | } else{ 308 | conditionData <- subset(data, data$condition == conditionName) 309 | } 310 | 311 | # get all of the distribution & proportion information from human data. 312 | # This returns a list with all information in separate "cotainers" for ease 313 | # of access & generalisation to different CDF and CAF sizes. 314 | if(multipleSubjects == TRUE){ 315 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 316 | } else { 317 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 318 | } 319 | 320 | 321 | # get random starting parameters 322 | varParms <- (parms/ 100) * var 323 | parameters <- getRandomParms(parms, varParms, maxParms, nParms) 324 | 325 | #--- 326 | # Start the optimisation 327 | 328 | message("Model Fit Running. Please Wait...") 329 | 330 | # initialise best-fitting parameters & best fit so far 331 | bestFit <- .Machine$integer.max 332 | bestParms <- numeric(length(parms)) 333 | bestBIC <- .Machine$integer.max 334 | 335 | # start loop over all parameters now 336 | for(i in 1:nParms){ 337 | 338 | # get the current run's parameters 339 | currParms <- parameters[i, ] 340 | 341 | fit <- optim(currParms, 342 | fn = fitFunctionDSTP, 343 | humanProportions = humanProportions, 344 | n = nTrials, 345 | maxParms = maxParms, 346 | seed = seed, 347 | control = list(parscale = parscale)) 348 | 349 | if(fit$value < bestFit){ 350 | bestFit <- fit$value 351 | bestParms <- round(fit$par, 3) 352 | bestBIC <- bBIC(humanProportions, model = "DSTP", parms = bestParms, 353 | nTrials = nTrials) 354 | 355 | } 356 | 357 | } 358 | 359 | modelFit <- list(bestParameters = bestParms, g2 = bestFit, 360 | bBIC = bestBIC) 361 | 362 | message("Model Fit Finished.") 363 | 364 | return(modelFit) 365 | 366 | } # end of function 367 | 368 | 369 | 370 | # fit DSTP (fixed) -------------------------------------------------------- 371 | 372 | #' Fit the DSTP model to human data with some fixed parameters 373 | #' 374 | #' \code{fitDSTP_fixed} fits the DSTP model to a single experimental condition 375 | #' of human data (besides congruency, which it accounts for simutaneously). 376 | #' This function allows the user to fix some parameters (using the \code{fixed} 377 | #' variable). 378 | #' 379 | #' This function can be employed by the user to find the best-fitting 380 | #' parameters of the DSTP model to fit the human data of a single experimental 381 | #' condition. The fitting procedure accounts for congruent and incongruent 382 | #' trials simultaneously. The fit is obtained by a gradient-descent method 383 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 384 | #' fit to the proportion of data contained in human CDF and CAF distributional 385 | #' data. 386 | #' 387 | #' @param data A data frame containing human data. See \code{?exampleData} for 388 | #' data formatted correctly. 389 | #' 390 | #' @param conditionName If there is an additional experimental manipulation 391 | #' (i.e., other than target congruency) the model can only be fit to one at a 392 | #' time. Tell the function which condition is currently being fit by passing 393 | #' a string to the function (e.g., "present"). The function by default assumes 394 | #' no additional condition (e.g., conditionName is set to NULL). 395 | #' 396 | #' @param parms A vector of starting parameters to use in the minimisation 397 | #' routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 398 | #' \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 399 | #' 400 | #' @param cdfs A vector of quantile values for cumulative distribution functions 401 | #' to be estimated from the human data. The model will attempt to find the 402 | #' best-fitting parameters that match this distributional data. 403 | #' 404 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 405 | #' estimated from the human data. The model will attempt to find the best- 406 | #' fitting parameters that match this distributional data. 407 | #' 408 | #' @param maxParms A vector containing upper limits on possible parameter 409 | #' values. 410 | #' 411 | #' @param nTrials An integer stating how many trials to simulate per iteration 412 | #' of the fitting cycle for each congruency type. 413 | #' 414 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 415 | #' subjects (multipleSubjects = TRUE) or to a single subject 416 | #' (multipleSubjects = FALSE). 417 | #' 418 | #' @param fixed A vector of TRUE/FALSE stating whether each parameter should be 419 | #' fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 420 | #' order: \code{A}, \code{C}, \code{driftTarget}, \code{driftFlanker}, 421 | #' \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 422 | #' 423 | #' @param seed The value for the \code{set.seed} function to set random 424 | #' generation state. 425 | #' 426 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 427 | #' by the current fit run. 428 | #' 429 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 430 | #' current fit run. 431 | #' 432 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 433 | #' obtained by the current fit run. This is calculated using the BIC equation 434 | #' for binned data, hence bBIC (binned BIC). 435 | #' 436 | #' @examples 437 | #' # Load the example data the comes with the \code{flankr} package 438 | #' data(exampleData) 439 | #' 440 | #' # Fix the first parameter (A) during the fit. 441 | #' parms <- c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24) 442 | #' fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 443 | #' 444 | #' # fit the model. 445 | #' # (Note this is a toy example with very low trial numbers to speed up the 446 | #' # example. For proper use, increase nTrials.) 447 | #' \donttest{ 448 | #' fit <- fitDSTP_fixed(exampleData, conditionName = "present", parms = parms, 449 | #' fixed = fixed, nTrials = 100) 450 | #'} 451 | #' 452 | #'@export 453 | fitDSTP_fixed <- function(data, conditionName = NULL, 454 | parms = c(0.145, 0.08, 0.10, 0.07, 0.325, 1.30, 0.240), 455 | cdfs = c(.1, .3, .5, .7, .9), cafs = c(.25, .50, .75), 456 | maxParms = c(1, 1, 1, 1, 1, 2, 1), nTrials = 50000, 457 | multipleSubjects = TRUE, 458 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 459 | FALSE), 460 | seed = NULL){ 461 | 462 | # get the desired condition's data 463 | if(is.null(conditionName)){ 464 | conditionData <- data 465 | } else{ 466 | conditionData <- subset(data, data$condition == conditionName) 467 | } 468 | 469 | # get all of the distribution & proportion information from human data. 470 | # This returns a list with all information in separate "cotainers" for ease 471 | # of access & generalisation to different CDF and CAF sizes. 472 | if(multipleSubjects == TRUE){ 473 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 474 | } else { 475 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 476 | } 477 | 478 | message("Model Fit Running. Please Wait...") 479 | 480 | # perform the fit using the wrapper function 481 | fit <- optimFix_DSTP(parms, fixed, humanProportions = humanProportions, 482 | n = nTrials, maxParms = maxParms, seed = seed) 483 | 484 | # what are the best-fitting parameters? 485 | bestParameters <- round(fit$fullPars, 3) 486 | 487 | # what is the fit statistic value? 488 | g2 <- fit$value 489 | 490 | # get the approximate BIC value 491 | bBIC <- bBIC_fixed(humanProportions, model = "DSTP", parms = bestParameters, 492 | fixed = fixed, nTrials = nTrials) 493 | 494 | # put all results into a list, and return the list to the user 495 | modelFit <- list(bestParameters = bestParameters, g2 = g2, 496 | bBIC = bBIC) 497 | 498 | message("Model Fit Finished.") 499 | 500 | 501 | return(modelFit) 502 | 503 | 504 | } # end of function 505 | 506 | 507 | 508 | 509 | # fit DSPT (fixed, multiple) ---------------------------------------------- 510 | 511 | #' Fit the DSTP model to human data with multiple starting parameters with some 512 | #' fixed parameters 513 | #' 514 | #' \code{fitMultipleDSTP_fixed} fits the DSTP model to a single experimental 515 | #' condition of human data (besides congruency, which it accounts for 516 | #' simutaneously). This function explores multiple starting parameters and 517 | #' allows user to fix model parameters. 518 | #' 519 | #' This function can be employed by the user to find the best-fitting 520 | #' parameters of the DSTP model to fit the human data of a single experimental 521 | #' condition. The fitting procedure accounts for congruent and incongruent 522 | #' trials simultaneously. The fit is obtained by a gradient-descent method 523 | #' (using the Nelder-Mead method contained in R's \code{optim} function) and is 524 | #' fit to the proportion of data contained in human CDF and CAF distributional 525 | #' data. Multiple starting points of parameters are used. 526 | #' 527 | #' @param data A data frame containing human data. See \code{?exampleData} for 528 | #' data formatted correctly. 529 | #' 530 | #' @param conditionName If there is an additional experimental manipulation 531 | #' (i.e., other than target congruency) the model can only be fit to one at a 532 | #' time. Tell the function which condition is currently being fit by passing 533 | #' a string to the function (e.g., "present"). The function by default assumes 534 | #' no additional condition (e.g., conditionName is set to NULL). 535 | #' 536 | #' @param parms A vector of starting parameters to use in the minimisation 537 | #' routine. Must be in the order: \code{A}, \code{C}, \code{driftTarget}, 538 | #' \code{driftFlanker}, \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 539 | #' These parameters will be the starting point for the random parameters. 540 | #' 541 | #' @param var An integer stating the percentage of each parameter value that 542 | #' should be used for finding random parameter starting points. 543 | #' 544 | #' @param nParms An integer stating how many random starting points to explore 545 | #' 546 | #' @param cdfs A vector of quantile values for cumulative distribution functions 547 | #' to be estimated from the human data. The model will attempt to find the 548 | #' best-fitting parameters that match this distributional data. 549 | #' 550 | #' @param cafs A vector of quantiles for conditional accuracy functions to be 551 | #' estimated from the human data. The model will attempt to find the best- 552 | #' fitting parameters that match this distributional data. 553 | #' 554 | #' @param maxParms A vector containing upper limits on possible parameter 555 | #' values. 556 | #' 557 | #' @param nTrials An integer stating how many trials to simulate per iteration 558 | #' of the fitting cycle for each congruency type. 559 | #' 560 | #' @param multipleSubjects A boolean stating whether the fit is to multiple 561 | #' subjects (multipleSubjects = TRUE) or to a single subject 562 | #' (multipleSubjects = FALSE). 563 | #' 564 | #' @param fixed A vector of TRUE/FALSE stating whether each parameter should be 565 | #' fixed (TRUE) or free (FALSE) during the fitting routine. Must be in the 566 | #' order: \code{A}, \code{C}, \code{driftTarget}, \code{driftFlanker}, 567 | #' \code{diftStimSelection}, \code{driftRS2}, \code{ter}. 568 | #' 569 | #' @return \code{bestParameters} A vector of the best-fitting parameters found 570 | #' by the current fit run. 571 | #' 572 | #' @return \code{g2} The value of Wilks likelihood ratio (G2) obtained by the 573 | #' current fit run. 574 | #' 575 | #' @return \code{bBIC} The value of the Bayesian Information Criterion (BIC) 576 | #' obtained by the current fit run. This is calculated using the BIC equation 577 | #' for binned data, hence bBIC (binned BIC). 578 | #' 579 | #' @examples 580 | #' # Load the example data the comes with the \code{flankr} package 581 | #' data(exampleData) 582 | #' 583 | #' # Fit the model whilst fixing the first parameter (A) 584 | #' # (Note this is a toy example with very low trial numbers to speed up the 585 | #' # example. For proper use, increase nTrials.) 586 | #' parms <- c(0.145, 0.08, 0.1, 0.07, 0.325, 1.3, 0.24) 587 | #' fixed <- c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) 588 | #' \donttest{ 589 | #' fit <- fitMultipleDSTP_fixed(exampleData, conditionName = "present", 590 | #' parms = parms, fixed = fixed, nTrials = 100) 591 | #'} 592 | #' 593 | #'@export 594 | fitMultipleDSTP_fixed <- function(data, conditionName = NULL, 595 | parms = c(0.145, 0.08, 0.10, 0.07, 0.325, 596 | 1.30, 0.240), var = 10, 597 | nParms = 20, cdfs = c(.1, .3, .5, .7, .9), 598 | cafs = c(.25, .50, .75), 599 | maxParms = c(1, 1, 1, 1, 1, 2, 1), 600 | nTrials = 50000, multipleSubjects = TRUE, 601 | fixed = c(FALSE, FALSE, FALSE, FALSE, FALSE, 602 | FALSE, FALSE)){ 603 | 604 | 605 | # get the desired condition's data 606 | if(is.null(conditionName)){ 607 | conditionData <- data 608 | } else{ 609 | conditionData <- subset(data, data$condition == conditionName) 610 | } 611 | 612 | # get all of the distribution & proportion information from human data. 613 | # This returns a list with all information in separate "cotainers" for ease 614 | # of access & generalisation to different CDF and CAF sizes. 615 | if(multipleSubjects == TRUE){ 616 | humanProportions <- getHumanProps(conditionData, cdfs, cafs) 617 | } else { 618 | humanProportions <- getHumanPropsSingle(conditionData, cdfs, cafs) 619 | } 620 | 621 | 622 | # get random starting parameters 623 | varParms <- (parms/ 100) * var 624 | parameters <- getRandomParms(parms, varParms, maxParms, nParms) 625 | 626 | #--- 627 | # Start the optimisation 628 | 629 | message("Model Fit Running. Please Wait...") 630 | 631 | 632 | 633 | # initialise best-fitting parameters & best fit so far 634 | bestFit <- .Machine$integer.max 635 | bestParms <- numeric(length(parms)) 636 | bestBIC <- .Machine$integer.max 637 | 638 | # start loop over all parameters now 639 | for(i in 1:nParms){ 640 | 641 | # get the current run's parameters 642 | currParms <- parameters[i, ] 643 | 644 | # check whether any parameter needs to be fixed 645 | for(i in 1:length(currParms)){ 646 | if(fixed[i] == TRUE){ 647 | currParms[i] <- parms[i] 648 | } 649 | } 650 | 651 | 652 | # run the fit whilst fixing necessary parameters 653 | fit <- optimFix_DSTP(parms, fixed, humanProportions = humanProportions, 654 | n = nTrials, maxParms = maxParms) 655 | 656 | if(fit$value < bestFit){ 657 | bestFit <- fit$value 658 | bestParms <- round(fit$fullPars, 3) 659 | bestBIC <- bBIC_fixed(humanProportions, model = "DSTP", parms = bestParms, 660 | fixed = fixed, nTrials = nTrials) 661 | 662 | } 663 | 664 | } 665 | 666 | modelFit <- list(bestParameters = bestParms, g2 = bestFit, 667 | bBIC = bestBIC) 668 | 669 | 670 | message("Model Fit Finished.") 671 | 672 | 673 | return(modelFit) 674 | 675 | } # end of function 676 | 677 | 678 | 679 | 680 | # predicted proportions DSTP ---------------------------------------------- 681 | 682 | # Get the predicted proportions from the DSTP model. 683 | # This returns proportion per bin, not qunatiles 684 | # e.g., c(.1, .2, .2, .2, .2, 1) not c(.1, .3, .5, .7, .9) 685 | predictionsDSTP <- function(parms, n, propsForModel, 686 | dt = 0.001, var = 0.01, seed = NULL){ 687 | 688 | # parms = parameters for the model run 689 | # n = number of trials per congruency condition 690 | # propsForModel = CDF & CAF distributional information 691 | 692 | # Set random number seed, so same predictions occur every time. 693 | if(!is.null(seed)){ 694 | set.seed(seed) 695 | } 696 | 697 | # Run model to get congruent RTs 698 | modelCon <- getDSTP_new(parms, 699 | trialType = 1, 700 | nTrials = n, 701 | dt, 702 | var) 703 | 704 | modelConCDF <- getCDFProps(propsForModel$congruentCDFs, modelCon) 705 | modelConCAF <- getCAFProps(propsForModel$congruentCAFsCutoff, modelCon) 706 | 707 | # Run model to get incongruent RTs 708 | modelIncon <- getDSTP_new(parms, 709 | trialType = 2, 710 | nTrials = n, 711 | dt, 712 | var) 713 | modelInconCDF <- getCDFProps(propsForModel$incongruentCDFs, modelIncon) 714 | modelInconCAF <- getCAFProps(propsForModel$incongruentCAFsCutoff, modelIncon) 715 | 716 | modelProps <- list(modelCongruentCDF = modelConCDF, 717 | modelCongruentCAF = modelConCAF, 718 | modelIncongruentCDF = modelInconCDF, 719 | modelIncongruentCAF = modelInconCAF) 720 | 721 | return(modelProps) 722 | 723 | } 724 | 725 | 726 | 727 | 728 | # plot predictions -------------------------------------------------------- 729 | 730 | # Get the predicted Quantiles from the DSTP model. 731 | # This returns quantiles, not proportion per bin 732 | # e.g., c(.1, .3, .5, .7, .9) not c(.1, .2, .2, .2, .2, 1) 733 | plotPredictionsDSTP <- function(parms, 734 | n, 735 | propsForModel, 736 | dt = 0.001, 737 | var = 0.01, 738 | seed = NULL){ 739 | 740 | # parms = parameters for the model run 741 | # n = number of trials per congruency condition 742 | # propsForModel = CDF & CAF distributional information 743 | 744 | # Set random number seed, so same predictions occur every time. 745 | if(!is.null(seed)){ 746 | set.seed(seed) 747 | } 748 | 749 | # Run model to get congruent RTs 750 | modelCon <- getDSTP_new(parms, trialType = 1, nTrials = n, dt, var) 751 | modelConCDF <- getModelCDFs(modelCon, propsForModel$congruentCDFs) 752 | modelConCAF <- getModelCAFs(modelCon, propsForModel$congruentCAFsCutoff) 753 | 754 | # Run model to get incontruent RTs 755 | modelIncon <- getDSTP_new(parms, trialType = 2, nTrials = n, dt, var) 756 | modelInconCDF <- getModelCDFs(modelIncon, propsForModel$incongruentCDFs) 757 | modelInconCAF <- getModelCAFs(modelIncon, propsForModel$incongruentCAFsCutoff) 758 | 759 | modelProps <- list(modelCongruentCDF = modelConCDF, 760 | modelCongruentCAF = modelConCAF, 761 | modelIncongruentCDF = modelInconCDF, 762 | modelIncongruentCAF = modelInconCAF) 763 | 764 | return(modelProps) 765 | } 766 | 767 | --------------------------------------------------------------------------------