diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/py/bayes.ipynb b/py/bayes.ipynb new file mode 100644 index 0000000..786f655 --- /dev/null +++ b/py/bayes.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n", + "is_executing": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "stem_cell": { + "cell_type": "raw", + "source": "", + "metadata": { + "pycharm": { + "metadata": false + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/py/bayes.ipynb b/py/bayes.ipynb new file mode 100644 index 0000000..786f655 --- /dev/null +++ b/py/bayes.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n", + "is_executing": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "stem_cell": { + "cell_type": "raw", + "source": "", + "metadata": { + "pycharm": { + "metadata": false + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/contiguous_seqs.ipynb b/py/contiguous_seqs.ipynb new file mode 100644 index 0000000..44905ae --- /dev/null +++ b/py/contiguous_seqs.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "name": "stdout", + "text": [ + "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" + ], + "output_type": "stream" + } + ], + "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/py/bayes.ipynb b/py/bayes.ipynb new file mode 100644 index 0000000..786f655 --- /dev/null +++ b/py/bayes.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n", + "is_executing": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "stem_cell": { + "cell_type": "raw", + "source": "", + "metadata": { + "pycharm": { + "metadata": false + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/contiguous_seqs.ipynb b/py/contiguous_seqs.ipynb new file mode 100644 index 0000000..44905ae --- /dev/null +++ b/py/contiguous_seqs.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "name": "stdout", + "text": [ + "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" + ], + "output_type": "stream" + } + ], + "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/ddm_playground.ipynb b/py/ddm_playground.ipynb new file mode 100644 index 0000000..be389b6 --- /dev/null +++ b/py/ddm_playground.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/py/bayes.ipynb b/py/bayes.ipynb new file mode 100644 index 0000000..786f655 --- /dev/null +++ b/py/bayes.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n", + "is_executing": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "stem_cell": { + "cell_type": "raw", + "source": "", + "metadata": { + "pycharm": { + "metadata": false + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/contiguous_seqs.ipynb b/py/contiguous_seqs.ipynb new file mode 100644 index 0000000..44905ae --- /dev/null +++ b/py/contiguous_seqs.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "name": "stdout", + "text": [ + "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" + ], + "output_type": "stream" + } + ], + "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/ddm_playground.ipynb b/py/ddm_playground.ipynb new file mode 100644 index 0000000..be389b6 --- /dev/null +++ b/py/ddm_playground.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/test_jupyter.ipynb b/py/test_jupyter.ipynb new file mode 100644 index 0000000..04a3fb9 --- /dev/null +++ b/py/test_jupyter.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "pycharm": {} + }, + "outputs": [ + { + "data": { + "text/plain": [ + "26" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": "import random\nrandom.Random().randint(1,100)\n" + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": "from matplotlib import pyplot as plt\nimport numpy as np\n%matplotlib inline\n\n# Data for plotting\nt \u003d np.arange(0.0, 2.0, 0.01)\ns \u003d 1 + np.sin(2 * np.pi * t)\n\nfig, ax \u003d plt.subplots()\nax.plot(t, s)\n\nax.set(xlabel\u003d\u0027time (s)\u0027, ylabel\u003d\u0027voltage (mV)\u0027,\n title\u003d\u0027About as simple as it gets, folks\u0027)\nax.grid()\n\nfig.savefig(\"test.png\")\nplt.show()" + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "pycharm": {} + }, + "outputs": [], + "source": "# change to R kernel\n#library(ggplot2)\n#qplot(wt,mpg,data\u003dmtcars)" + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "pycharm": {} + }, + "outputs": [ + { + "data": { + "image/png": "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\nQIAAAQK1JyAg1V6fqTEBAgQIECBAgAABAjkJCEg5wSqWAAECBAgQIECAAIHaExCQaq/P1JgA\nAQIECBAgQIAAgZwEBKScYBVLgAABAgQIECBAgEDtCQhItddnakyAAAECBAgQIECAQE4CAlJO\nsIolQIAAAQIECBAgQKD2BASk2uszNSZAgAABAgQIECBAICcBASknWMUSIECAAAECBAgQIFB7\nAgJS7fWZGhMgQIAAAQIECBAgkJOAgJQTrGIJECBAgAABAgQIEKg9AQGp9vpMjQkQIECAAAEC\nBAgQyElAQMoJVrEECBAgQIAAAQIECNSegIBUe32mxgQIECBAgAABAgQI5CQgIOUEq1gCBAgQ\nIECAAAECBGpPoLH2qlx7NV69enU89thj0dDQEHvssUcMHDiw14145pln4pVXXomddtopxo4d\n2+tyPJEAAQIECBAgQIAAgY4CAlJHk7LOue222+L000+PVatWZeUOHTo0vv71r8fUqVN7tJ2/\n/vWvceqpp8bvf//7aGxsjKampjjhhBPiK1/5yiYFrh5VwsoECBAgQIAAAQIECi7gFLscO/jX\nv/51nHLKKbF8+fJoaWnJbsuWLYsZM2bEb3/7225vubm5OY477rh48sknY+3atVk4Sk++4447\n4l/+5V+6XY4VCRAgQIAAAQIECBDYsICAtGGfTVr6zW9+Mws0nRVy1VVXdTa703n33HNPpCNI\nKWStO61ZsyZuuummeP3119ed7T4BAgQIECBAgAABAr0UEJB6Cdedpz399NOdBqTW1tb44x//\n2J0isnX+/Oc/R79+nXdVKuv555/vdllWJECAAAECBAgQIECga4HOP3V3vb4lPRDYbrvtulx7\nQ8vWf9LWW2+9/qx2j9/2tre1e+wBAQIECBAgQIAAAQK9ExCQeufWrWel3xr179+/w7rpaFBa\n1t3pyCOPjGHDhmWj4K37nAEDBsR73/veGD169Lqz3SdAgAABAgQIECBAoJcCAlIv4brztBRe\nvvSlL2Wnxw0ePDjSLQWmNLDC4Ycf3p0isnXSyHe33HJLjBkzJlIoGjJkSFbOPvvsk42I1+2C\nrEiAAAECBAgQIECAwAYFDPO9QZ5NX/j5z38+G9J77ty5WWEHH3xwjBs3rscF77777vHQQw/F\n/fffH4sWLYqdd9459t9//x6X4wkECBAgQIAAAQIECHQtICB1bVO2Jek3RNOmTdvk8gYNGhTv\nec97NrkcBRAgQIAAAQIECBAg0LmAU+w6dzGXAAECBAgQIECAAIE6FKiKI0ivvfZazJkzJxsS\n+8ADD4z1R2VL1/959NFHswul7rrrrnHAAQfUYVdpMgECBAgQIECAAAECeQtU/AjSL3/5yzj2\n2GPjV7/6Vdx3333x0Y9+NB5++OG2dqdw9IlPfCIuuOCC7GKpF110UVxxxRVty90hQIAAAQIE\nCBAgQIBAuQQqegSpqakprrnmmvj4xz8eJ5xwQtamyy67LL7zne+0DUBw2223xRtvvBG33npr\nNtT1X/7ylzj55JPjqKOOil122aVcDsohQIAAAQIECBAgQIBAVPQIUjo6NHPmzPjABz7Q1hWj\nRo2KJUuWtD1+4IEH4ogjjsjCUZq5ww47RBrRbfbs2W3ruEOAAAECBAgQIECAAIFyCFT0CFK6\nLtDkyZOzdixevDgbxvpHP/pRfOxjH2tr24IFCyKNArfulB6noa7Xn9Iw2MuWLWubPXLkyNhx\nxx3bHlfiTkNDQ6TR51pbWyux+brYZrrwbprSNaaStSk/gWScrsWV9mtTvgJpv7Y/52vc2NiY\n/faVc77OpdcLzvk6p9dm74P5GqfSS585Bg4c6LNdjtzJufQZupybKb0ebazMigakdSuXfls0\nf/78LAwdeuih2aLm5uZ49dVXY/PNN1931ezx008/3W5eenDJJZfEU0891TY/XSfopptuantc\nqTspqJnyF0hvvt6A+8Y5/63YQvrwvsUWW4DoA4Fhw4b1wVZswv7cN/uA98G+cfbZrm+cy/26\nsWbNmm5VvGoC0pVXXhlpNLv0+6P0G6Pbb789C0IpQaagtO6UHnf2hpael45ElaY0Gt7rr79e\neliRv6meK1asyL6lrEgF6mCjaR8ZPnx4pJ1+1apVddDiyjUxHfVN///W/z9ZuRoVc8ubbbZZ\n9s3k8uXLi9nAKmlV+gY4Td19w6ySatdcNdL7YHqdXvcMj5prRA1UOH2pkm7eB/PtrCFDhmRn\nUqT9ee3atflurI5LT0d6knX6DF3OKfVZ6bV/Q+VWTUBKlUxpfMaMGXHnnXfGvHnz4r3vfW/2\nDer6L6op9IwbN65Du9JoeOtP6RS9Sk6lznWKXX69kE4pSAEpfWj3gTI/51RyevNduXKlD5T5\nMkcKSOk3mvbnnKHfLD69WZb7DTj/WtfWFtL7YApI9ud8+y0dOUpfYnHO1zmdyphu6b0wvU6b\n8hFIrxlpny73/pw+M3ZnquggDc8991xMmzYtXnrppba6pm8+0g5XSuVvf/vb44knnmhbnu48\n+eSTsc0227Sb5wEBAgQIECBAgAABAgQ2VaCiAWn8+PGx1VZbZUN9L126NF5++eW4+uqrY8SI\nETFx4sSsbemo0D333JOFohSa0ql36XSIqVOnbmrbPZ8AAQIECBAgQIAAAQLtBCp+it1ZZ50V\nF154YRxzzDHZOfdpGO9Zs2ZFGu47TSkopWsknXnmmdkhzXTk6Pzzz89OqWrXEg8IECBAgAAB\nAgQIECCwiQIVD0gTJkzIRppLw3Z3NWrTqaeeGieddFI24MKYMWM2scmeToAAAQIECBAgQIAA\ngc4FKh6QStUaO3Zs6W6nf9OIE8JRpzRmEiBAgAABAgQIECBQJoGK/gapTG1QDAECBAgQIECA\nAAECBMoiICCVhVEhBAgQIECAAAECBAgUQUBAKkIvagMBAgQIECBAgAABAmUREJDKwqgQAgQI\nECBAgAABAgSKICAgFaEXtYEAAQIECBAgQIAAgbIICEhlYVQIAQIECBAgQIAAAQJFEBCQitCL\n2kCAAAECBAgQIECAQFkEBKSyMCqEAAECBAgQIECAAIEiCAhIRehFbSBAgAABAgQIECBAoCwC\nAlJZGBVCgAABAgQIECBAgEARBASkIvSiNhAgQIAAAQIECBAgUBYBAaksjAohQIAAAQIECBAg\nQKAIAgJSEXpRGwgQIECAAAECBAgQKIuAgFQWRoUQIECAAAECBAgQIFAEAQGpCL2oDQQIECBA\ngAABAgQIlEVAQCoLo0IIECBAgAABAgQIECiCgIBUhF7UBgIECBAgQIAAAQIEyiIgIJWFUSEE\nCBAgQIAAAQIECBRBQEAqQi9qAwECBAgQIECAAAECZREQkMrCqBACBAgQIECAAAECBIogICAV\noRe1gQABAgQIECBAgACBsggISGVhVAgBAgQIECBAgAABAkUQEJCK0IvaQIAAAQIECBAgQIBA\nWQQEpLIwKoQAAQIECBAgQIAAgSIICEhF6EVtIECAAAECBAgQIECgLAICUlkYFUKAAAECBAgQ\nIECAQBEEBKQi9KI2ECBAgAABAgQIECBQFgEBqSyMCiFAgAABAgQIECBAoAgCAlIRelEbCBAg\nQIAAAQIECBAoi4CAVBZGhRAgQIAAAQIECBAgUAQBAakIvagNBAgQIECAAAECBAiURUBAKguj\n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\nCBAgQIBAvQkISPXW49pLgAABAgQIECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYS\nIECAAAECBAgQINClgIDUJY0FBAgQIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1\nSWMBAQIECBAgQIAAAQL1JiAg1VuPay8BAgQIECBAgAABAl0KCEhd0lhAgAABAgQIECBAgEC9\nCQhI9dbj2kuAAAECBAgQIECAQJcCAlKXNBYQIECAAAECBAgQIFBvAgJSvfW49hIgQIAAAQIE\nCBAg0KWAgNQljQUECBAgQIAAAQIECNSbgIBUbz2uvQQIECBAgAABAgQIdCkgIHVJYwEBAgQI\nECBAgAABAvUmICDVW49rLwECBAgQIECAAAECXQoISF3SWECAAAECBAgQIECAQL0JCEj11uPa\nS4AAAQIECBAgQIBAlwICUpc0FhAgQIAAAQIECBAgUG8CAlK99bj2EiBAgAABAgQIECDQpYCA\n1CWNBQQIECBAgAABAgQI1JuAgFRvPa69BAgQIECAAAECBAh0KSAgdUljAQECBAgQIECAAAEC\n9SYgINVbj2svAQIECBAgQIAAAQJdCghIXdJYQIAAAQIECBAgQIBAvQkISPXW49pLgAABAgQI\nECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYSIECAAAECBAgQINClgIDUJY0FBAgQ\nIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1SWMBAQIECBAgQIAAAQL1JiAg1VuP\nay8BAgQIECBAgAABAl0KCEhd0lhAoDoEWltb4+qrr4799tsvxo8fH1OmTIm77rqrOiqnFjUr\n8Oc//zlOPvnk2GmnnWKXXXaJT3/60/Hqq6/WbHtUnAABAgQIlEtAQCqXpHII5CRw1llnxVe/\n+tVYsGBBrFmzJv74xz/GjBkz4pZbbslpi4otusBzzz0XRx55ZNx3332xYsWKWLZsWfz4xz+O\nf/iHf4ilS5cWvfnaR4AAAQIENiggIG2Qx0IClRV44okn4vbbb4+mpqZ2FWlpaYl/+Zd/yQJT\nuwUeEOiGwGWXXRarV6+OtB+Vpubm5li8eHF85zvfKc3ylwABAgQI1KWAgFSX3a7RtSLw61//\nOgYOHNhpddM3/+lokolATwUefPDBduGo9Px0hPK//uu/Sg/9JUCAAAECdSkgINVlt2t0rQgM\n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\npo4CG3PZ2PKOJZpDgAABAgSqW0BAqu7+UTsCfSqwxx57xJVXXtmn2+yrjaXrOv3rv/5rh82l\no2R77713pBHNTB0Fdtxxx+x6dy+++GKHhatXr44pU6Z0mG8GAQIECBCoZQGn2NVy76k7AQLd\nFthvv/3in/7pn7JTB0tPSkc/0umFX//610uz/O1E4N/+7d+y36ilEQ3TlI7Epdv/9//9fzF+\n/Phsnn8IECBAgEBRBBxBKkpPagcBAhsVSBfCnTRpUtx6663x6quvxoEHHhinn356pOsOmboW\nSIN43HffffGtb30rHn/88dhmm23i5JNPjsmTJ3f9JEsIECBAgECNCghINdpxqk2AQO8Epk6d\nGulm6plAOlL01a9+tWdPsjYBAgQIEKhBAafY1WCnqTIBAgQIECBAgAABAvkICEj5uCqVAAEC\nBAgQIECAAIEaFBCQarDTVJkAAQIECBAgQIAAgXwEBKR8XJVKgEA3BO6444448sgjIw0vfvTR\nR8e9997bjWdVfpUf/OAH8fd///dZvadNmxbz5s2rfKXUgAABAgQIECiLgIBUFkaFECDQU4HL\nL788PvOZz8Tvf//7WLx4cfzmN7/JRkZLI8xV83T++efHueeeG3/4wx+yev/qV7+K4447Ln76\n059Wc7XVjQABAgQIEOimgIDUTSirESBQPoF00dFvfvOb0dLS0q7Q1tbW7No6K1eubDe/Wh48\n/fTT8e///u/R3NzcVqW1a9dGqvfnPve5dvPbVnCHAAECBAgQqCkBAammuktlCRRDIB11GThw\nYKeNaWpqivnz53e6rNIz586dG4MGDeq0Gq+//nqkAGUiQIAAAQIEaltAQKrt/lN7AjUp0L9/\n/y7rnY7INDZW5yXaNlSvVO8BAwZ02S4LCBAgQIAAgdoQEJBqo5/UkkChBA499NAuT0cbPnx4\n7LnnnlXZ3sMOOyzWrFnTad222mqr2GmnnTpdZiYBAgQIECBQOwICUu30lZoSKIzAmDFj4pJL\nLomGhobslhqWjiql27/+679W7ZGY7bffPvuNVKp3aUp1TkeO/u3f/q2tLaVl/hIgQIAAAQK1\nJ1Cd57HUnqMaEyDQQ4GTTz45JkyYENdff3385S9/iV122SU++clPxjve8Y4eltS3q59xxhlZ\nHf/jP/4j0mATu+++e1bv1BYTAQIECBAgUPsCAlLt96EWEKhZgYkTJ0a61dr07ne/O9LNRIAA\n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\nZcvSww8/nOLv/vvvnz7xiU9swbvq85L169enxx9/PL322mtp5513Tp/+9KfT6NGj61N4zqVI\nkHIGVjwBAgQIECBAgACB/hZ47LHH0syZMzurbW9vTwceeGD69a9/nXuismTJkjRjxoz01ltv\npYED/3fCWktLS7r55pvToYce2tmmZp1xil2z9ox2ESBAgAABAgQIENgGgYULF6azzjorvf/+\n+52PSJCef/75dOGFF25DiVv3llmzZqU333wzrV27Nq1ZsyZ7rFq1Kp1xxhkp/jb7JEFq9h7S\nPgIECBAgQIAAAQJbIXD33XenAQMGbPaOSFhiXWtr62br6rVg0aJF6cknn0yRkG06tbW1pYce\nemjTxU33XILUdF2iQQQIECBAgAABAgS2XSCSlK4SlChx3bp1acWKFdteeC/vXLx4cbeviKQt\n2tbskwSp2XtI+wgQIECAAAECBAhshcC+++6bBg0a1OU7Ro4cmXbaaacu19Vj4Z577tlt3ZGc\nfeADH6hHNbmWIUHKlVfhBAgQIECAAAECBPpX4MQTT0w77rjjZonK4MGD0/nnn7/Z8nq2LhKw\ns88+Ow0ZMmSjYqPuffbZJx155JEbLW/GJxKkZuwVbSJAgAABAgQIECCwjQLDhg1Ld955ZzZq\nXUcRMYrcBRdckL7yla90LMrt70UXXZSNoFd7FOvwww9Pt99+e+eodrlVXoeCDfNdB0RFECBA\ngAABAgQIEGgmgV133TXdc889acGCBWn58uVpr732SsOHD++XJkZi9K1vfSs7WjVv3rzslL44\nolWUSYJUlJ7STgIECBAgQIAAAQJbKTBx4sQUj0ZMcbrdlClTGlF1n+p0il2f+LyZAAECBAgQ\nIECAAIEyCTTVEaQnnngiu7PvQQcdtJFxjHjx3HPPpZdffjlNnjw5feQjH9lovScECBAgQIAA\nAQIECBCoh0DTHEGKBOjb3/52lgTVBhbJ0TnnnJO+853vpH//+9/p0ksvTVdffXXtS8wTIECA\nAAECBAgQIECgLgINP4IUN7G6+eabs0dXd/yN0S5Wr16dbrvtthTnMc6fPz+dccYZ6YQTTkgx\nxruJAAECBAgQIECAAAEC9RJo+BGk+++/P913333psssuS7vttttmcT311FPpmGOOyZKjWLnH\nHnuk/fffPz388MObvdYCAgQIECBAgAABAgQI9EWg4UeQPvaxj6Xjjz8+xc2jrr/++s1iiaEJ\n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\u003d\u003d", + "text/plain": [ + "plot without title" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": "" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/bayes.ipynb b/bayes.ipynb deleted file mode 100644 index 786f655..0000000 --- a/bayes.ipynb +++ /dev/null @@ -1,59 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "outputs": [], - "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n", - "is_executing": false - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - }, - "stem_cell": { - "cell_type": "raw", - "source": "", - "metadata": { - "pycharm": { - "metadata": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ccn2019.Rmd b/ccn2019.Rmd deleted file mode 100644 index 9074227..0000000 --- a/ccn2019.Rmd +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: "Evaluating N-Back Sequences" ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = FALSE) -library(tidyverse) -library(ggplot2) -library(stringi) -library(GA) -library(dbscan) -library(inspectdf) - -load('./data/CL2015.RData') -``` - -### Variables -- $T$ number of targets -- $L$ number of lures -- $S$ Skewness score -- $U$ Uniformity (!repetition) -- $RT_{mean}$ -- $Accuracy_{mean}$ -- $dprime$ -- $criterion$ - -## Constraints - -- fixed number of targets -- fixed number of lures (a.k.a, foils) -- uniform distribution of choices -- controlled local lumpiness - - -Each constraint is an up side down quadratic function to be minimized. - -```{r, eval=F} -targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) -skewness_cost <- function(x, choices) { - uniform_ratio <- length(x) / length(choices) - deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) - for (c in choices) { - deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) - } - #TODO convert to gaussian loss - max(deviation_from_uniform) -} - -lumpiness_cost <- function(x, choices) { - #trials = len(seq) - #freqs = [float(seq.count(c)) for c in choices] - #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) - #return ralph_skewed - NA -} - -#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) -#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) -#plot(GA) -``` - - -```{r} - -with_lures <- function(condition, stim, stim_type, history = NA) { - sapply(1:length(stim), - function(i) { - switch(as.character(condition[i]), - "2-back" = { - ifelse( - stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), - 'lure', - as.character(stim_type[i]) - )}, - "3-back" = { - ifelse( - stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), - 'lure', - as.character(stim_type[i]) - )} - ) - - }) -} - -with_targets_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-stri_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="target"]) - }) -} - -with_lures_ratio <- function(stimulus_type, history) { - sapply(1:length(history), function(i) { - trials <- stimulus_type[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - length(trials[trials=="lure"]) - }) -} - -with_lumpiness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - max(table(trials)) - 1 - }) -} - -with_lag <- function(stimulus, history) { - # find last occurance the of stimulus -} - -with_skewness_score <- function(stimulus, history) { - sapply(1:length(history), function(i) { - trials <- stimulus[(i-str_length(history[i])):i] - trials <- unlist(trials, use.names=FALSE) - sum(sort(table(trials), decreasing = T)[1:2]) - 1 - }) -} - -with_history <- function(stims, size=16) { - res <- c('') - for (i in 2:length(stims)) { - res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) - } - #res <- ifelse(stri_length(res)==size, res, NA) - res -} - -normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { - #TODO - sapply(1:length(targets_ratio), function(i) 0) -} - -window_size <- 8 - -NB_modified <- NB %>% - group_by(participant, condition, block) %>% - mutate(history = with_history(stimulus, size=window_size)) %>% - #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) - mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% - mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% - mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% - mutate(skewness = with_skewness_score(stimulus, history)) %>% - mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% - filter(stri_length(history)==window_size) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% - ungroup() - -pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) - -NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) - - -## participant-level averaged NB, a single row represent an observation for a single subject -## in a single condition -NB_avg <- NB_modified %>% - group_by(participant, condition) %>% - mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% - summarise( - targets=sum(targets), - lures=sum(lures), - skewness=sum(skewness), - lumpiness=sum(lumpiness), - rt = mean(rt, na.rm=T), - correct=sum(correct,na.rm=T)/90) %>% - ungroup() - -# print -# NB_modified %>% -# filter(participant=='P1') %>% -# View() -# - - -fit <- lm(correct ~ t * s * u * l * d, NB_modified) - -``` - - -```{r} - -# DBSCAN Clustering (RT+ACCURACY against skewness) -NB_avg <- NB_avg %>% - mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) - -NB_avg %>% - ggplot(aes(skewness, correct, color=factor(cluster))) + - ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + - geom_point(alpha=0.3) + - #geom_smooth(method='lm', se = F) + - facet_wrap(~condition) - -``` - - -```{r} -## single-subject figures -NB_modified %>% - ggplot(aes(t,s,color=correct)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - inspect_cor(show_plot = T) - -NB_avg %>% - inspect_cor(show_plot = T) - -NB_modified %>% - ggplot(aes(rt,correct,color=u)) + - geom_jitter() + - geom_point() + - stat_summary(fun.y="mean") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(t),color=correct)) + - geom_jitter() + - geom_point(alpha=0.1) - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(s),jitter(u),color=correct)) + - geom_jitter() + - geom_point() + - facet_wrap(~condition) - -# rt/accuracy and lures -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + - geom_jitter() + - geom_point(shape=16) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,pc2,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,rt,color=correct)) + - geom_point(alpha=0.3) + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - -NB_modified %>% - filter(!is.na(correct)) %>% - ggplot(aes(pc1,correct,color=correct)) + - geom_point() + - geom_smooth(method="lm",se = F) + - facet_wrap(~condition, scales="free") - - -``` - -## TODO - - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), - - constraint3=fitness(history)) - - kmeans(NB) - - ggplot(kmeans_clusters$accuracy) - - ggplot(kmeans_clusters$rt) - - - - - - -```{python} -a=2 -p -``` diff --git a/ccn2019.rev0.Rmd b/ccn2019.rev0.Rmd new file mode 100644 index 0000000..9220ff4 --- /dev/null +++ b/ccn2019.rev0.Rmd @@ -0,0 +1,581 @@ +--- +title: "Statistical Properties of the N-Back Sequences" +output: + html_notebook: default + pdf_document: default +editor_options: + chunk_output_type: inline +--- + +# Problems + +Statistical properties of n-back sequences bias behaviors. These bias, under specified structure, allows multiple cognitive strategies, producing heterogeneous behavior in a "gold standard" cognitive task. + +# Gaps + +- Unclear how to parameterize interesting variations for sequence generation +- How do we model these multiple strategies (which requires identifying which sequence variations matter) + - local vs. global properties, which one matters the most? + - Local: lumpiness, short sequence patterns -> could be exploited by “reactive”/automaticity + - Global: No lures, large vocabulary -> pattern repeats implies a target + + +## Formulating Generating the N-Back Sequences as a CSP instance + +$P=\langle V,D,C,W\rangle$ + +$V=\{x_N,x_{T},x_{T,local},x_L,x_{L,local},x_V,x_U,x_S,x_{S,local},x_G\}$ + +$D=\{\}$ + + +Constraints: + +$$ +\\ + +x_n = N, W_n = 1 - |10 \times dnorm(x_n-N,sd=4)| + +\\\\ + +x_t = T \times trials, W_t = 1 - |10\times dnorm(T\times trials-x_t,sd=4)| + +\\\\ + +x_{tl} = {T \times w \over trials}, W_{tl} = 1 - |10\times dnorm(x_{tl} - {T \over trials} \times w,sd=4)| + +\\\\ + +x_{l} = L \times trials +\\\\ + +x_{ll} = L \times w +\\\\ + +x_{v} = |V| +\\ + +x_{ul} = w +\\\\ + +x_{s} = {trials \over |V|} +\\\\ + +x_{sl} = max(1, {w \over |V|}) +\\\\ + +x_{g} = {trials \over w} + +\\\\ + +x_{vl} = min(|V|, w) +$$ + +```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(plsRglm) +library(plsdof) +library(caret) +``` + +```{r params} +load('./data/CL2015.RData') + +window_size <- 8 +``` + + + +```{r history} + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + +with_history <- function(stimuli, length=16, fixed=F) { + seq <- paste(stimuli, collapse = '') + + sapply(1:length(stimuli), function(i) { + stri_reverse(str_sub(seq, max(1,i-length+1), i)) + }) + #ifelse(fixed, h[str_length(h)==size], h) +} + +# $x_{s,local}$ +with_skewness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + sum(sort(freqs, decreasing = T)[1:2]) - 1 + }) +} + +# $x_{u,local}$ +with_lumpiness <- function(history) { + sapply(history, function(h) { + freqs <- table(unlist(str_split(h,""))) + max(freqs) - 1 + }) +} + + +with_targets_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="target"]) / length(trials) + }) +} + +with_lures_ratio <- function(stimulus_type, length=16) { + sapply(1:length(stimulus_type), function(i) { + trials <- stimulus_type[max(1,i-length):i] + length(trials[trials=="lure"]) / length(trials) + }) +} + +#TODO change to list column workflow with broom for model fitting and evaluating the fits +# duh! we are using list nested insided a tibble, so put all new columns in a new list column +# instead of adding a new column for each. +NB2 <- NB %>% + group_by(participant, condition, block) %>% + nest() %>% unnest(data) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(history = with_history(stimulus, window_size)) %>% + mutate(x_sl = with_skewness(history)) %>% + mutate(x_ul = with_lumpiness(history)) %>% + mutate(x_t = with_targets_ratio(stimulus_type, window_size)) %>% + mutate(x_l = with_lures_ratio(stimulus_type, window_size)) %>% + ungroup() + +pca <- prcomp(~x_sl+x_ul+x_t+x_l, NB2, center = TRUE,scale. = TRUE, na.action=na.exclude) +NB2 <- NB2 %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + +# caret +library(caret) +# Compile cross-validation settings + + +any(is.na(NB2)) +NB2 <- na.omit(NB2) + +# set.seed(100) +# trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) +# +# # PLS +# mod1 <- train(correct ~ ., data = NB2[,c("correct","x_sl","x_ul","x_t","x_l")], +# method = "pls", +# metric = "Accuracy", +# tuneLength = 20, +# trControl = trainControl("repeatedcv", index = trainingfold, selectionFunction = "oneSE"), +# preProc = c("zv","center","scale")) +# +# # Check CV +# plot(mod1) + + +plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) + + +plsResult +``` + + + +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` + + + +--- +title: "PLS Training" +output: html_notebook +--- + +PLS: + + +```{r} +#detach("package:MASS","plsdof") # to avoid conflict with dplyr::select +library(tidyverse) +library(pls) + +## 1. load sample data +#data <- read.csv("http://wiki.q-researchsoftware.com/images/d/db/Stacked_colas.csv") + +rm(NB) +load("./data/CL2015.RData") +data <- NB +str(data) + +## 2. clean data (remove brand and URLID) +data <- data %>% + mutate(n=ifelse(condition=='2-back', 2, 3)) %>% + select(-condition, + -stimulus, + -block, + -trial) +# %>% +# rename( +# ev.participant=participant, +# ev.n=n, +# ev.block=block, +# ev.stimulus_type=stimulus_type, +# rv.choice=choice, +# rv.rt=rt, +# rv.correct=correct +# ) + +## 3. use cross validatation to find the optimal number of dimensions +pls.model = plsr(rt ~ ., data = data, validation = "CV") + +## 3.1. find the model with lowest cv error +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +## 4. rebuild the model +pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) + +## 5. Sort, and visualize top coefficients +coefs <- coef(pls.model) + +barplot(sort(coefs[,1,1], decreasing = T)[1:4]) +``` + + +```{r simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +pls.model <- plsr(Y ~ X, validation = "CV") + +cv <- RMSEP(pls.model) +best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 +pls.model <- plsr(Y ~ X, ncomp = best_dims) +coefs <- sort(coef(pls.model)[,1,1], decreasing = T) + +barplot(coefs) + +``` + + +```{r cca-simulate} +X <- matrix(rnorm(1100), 100, 11) +Y <- matrix(rnorm(400), 100, 4) + +M <- cor(cbind(X,Y)) +corrplot(M, method="ellipse", order="hclust", addrect=2, addCoef.col="black") +cc <- cancor(X, Y) + +#NB: cc <- cancor(cbind(rt,correct, accuracy) ~ xt + xl + xtl, data = data) + +``` + + +```{r plsrglm} +rm(list = ls()) +library(plsRglm) + +data(Cornell) +df <- Cornell +x <- subset(df, select = -c(Y)) +y <- df$Y +## K is the number of folds in CV, and nt is the maximum number of components, +#cv.modpls<-cv.plsRglm(dataY=y,dataX=x ,nt=10,modele="pls-glm-logistic",K=8) + +modpls <- plsRglm(dataY = y,dataX = x, nt = 10, modele = "pls-glm-logistic", sparse=TRUE,sparseStop=TRUE) +res.cv.modpls<-cvtable(summary(cv.modpls)) + +res6<-plsR(Y~.,data=Cornell, nt=6, typeVC="missing", pvals.expli=TRUE) + +``` + + + diff --git a/ccn2019.rev1.Rmd b/ccn2019.rev1.Rmd new file mode 100644 index 0000000..9074227 --- /dev/null +++ b/ccn2019.rev1.Rmd @@ -0,0 +1,281 @@ +--- +title: "Evaluating N-Back Sequences" +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = FALSE) +library(tidyverse) +library(ggplot2) +library(stringi) +library(GA) +library(dbscan) +library(inspectdf) + +load('./data/CL2015.RData') +``` + +### Variables +- $T$ number of targets +- $L$ number of lures +- $S$ Skewness score +- $U$ Uniformity (!repetition) +- $RT_{mean}$ +- $Accuracy_{mean}$ +- $dprime$ +- $criterion$ + +## Constraints + +- fixed number of targets +- fixed number of lures (a.k.a, foils) +- uniform distribution of choices +- controlled local lumpiness + + +Each constraint is an up side down quadratic function to be minimized. + +```{r, eval=F} +targets_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +lures_cost <- function(x) 1.0 - 10*dnorm(x,mean=0,sd=4) +skewness_cost <- function(x, choices) { + uniform_ratio <- length(x) / length(choices) + deviation_from_uniform <- setNames(vector('numeric', length(choices)), choices) + for (c in choices) { + deviation_from_uniform[c] = abs(length(x[x==c]) - uniform_ratio) + } + #TODO convert to gaussian loss + max(deviation_from_uniform) +} + +lumpiness_cost <- function(x, choices) { + #trials = len(seq) + #freqs = [float(seq.count(c)) for c in choices] + #ralph_skewed = sum(heapq.nlargest(int(len(choices) / 2), freqs)) > (trials * 2 / 3) + #return ralph_skewed + NA +} + +#merged_cost <- function(x) targets_fitness(x) + lures_fitness(x) + skewness_fitness(x) +#GA <- ga(type = "real-valued", fitness = merged_cost, lower = -10, upper = 10) +#plot(GA) +``` + + +```{r} + +with_lures <- function(condition, stim, stim_type, history = NA) { + sapply(1:length(stim), + function(i) { + switch(as.character(condition[i]), + "2-back" = { + ifelse( + stim[i]==stri_sub(history[i],-2,-2) || stim[i]==stri_sub(history[i],-4,-4), + 'lure', + as.character(stim_type[i]) + )}, + "3-back" = { + ifelse( + stim[i]==stri_sub(history[i],-3,-3) || stim[i]==stri_sub(history[i],-5,-5), + 'lure', + as.character(stim_type[i]) + )} + ) + + }) +} + +with_targets_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-stri_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="target"]) + }) +} + +with_lures_ratio <- function(stimulus_type, history) { + sapply(1:length(history), function(i) { + trials <- stimulus_type[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + length(trials[trials=="lure"]) + }) +} + +with_lumpiness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + max(table(trials)) - 1 + }) +} + +with_lag <- function(stimulus, history) { + # find last occurance the of stimulus +} + +with_skewness_score <- function(stimulus, history) { + sapply(1:length(history), function(i) { + trials <- stimulus[(i-str_length(history[i])):i] + trials <- unlist(trials, use.names=FALSE) + sum(sort(table(trials), decreasing = T)[1:2]) - 1 + }) +} + +with_history <- function(stims, size=16) { + res <- c('') + for (i in 2:length(stims)) { + res[i] <- stri_sub(paste(res[i-1], stims[i], sep=''),from=-size,length=size) + } + #res <- ifelse(stri_length(res)==size, res, NA) + res +} + +normalize_scores <- function(targets_ratio, lures_ratio, skewness, lumpiness) { + #TODO + sapply(1:length(targets_ratio), function(i) 0) +} + +window_size <- 8 + +NB_modified <- NB %>% + group_by(participant, condition, block) %>% + mutate(history = with_history(stimulus, size=window_size)) %>% + #mutate(stimulus_type = map_chr(.x=stimulus, stim_type=stimulus_type, history=history,.f=with_lures)) + mutate(stimulus_type_2 = with_lures(condition, stimulus, stimulus_type, history)) %>% + mutate(targets = with_targets_ratio(stimulus_type_2, history)) %>% + mutate(lures = with_lures_ratio(stimulus_type_2, history)) %>% + mutate(skewness = with_skewness_score(stimulus, history)) %>% + mutate(lumpiness = with_lumpiness_score(stimulus, history)) %>% + filter(stri_length(history)==window_size) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + #normalize_scores(targets_ratio, lures_ratio, skewness, lumpiness) %>% + ungroup() + +pca <- prcomp(NB_modified[,c('targets','lures','skewness','lumpiness')], center = TRUE,scale. = TRUE) + +NB_modified <- NB_modified %>% mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) + + +## participant-level averaged NB, a single row represent an observation for a single subject +## in a single condition +NB_avg <- NB_modified %>% + group_by(participant, condition) %>% + mutate(correct = ifelse(stimulus_type=='burn-in',NA,correct)) %>% + summarise( + targets=sum(targets), + lures=sum(lures), + skewness=sum(skewness), + lumpiness=sum(lumpiness), + rt = mean(rt, na.rm=T), + correct=sum(correct,na.rm=T)/90) %>% + ungroup() + +# print +# NB_modified %>% +# filter(participant=='P1') %>% +# View() +# + + +fit <- lm(correct ~ t * s * u * l * d, NB_modified) + +``` + + +```{r} + +# DBSCAN Clustering (RT+ACCURACY against skewness) +NB_avg <- NB_avg %>% + mutate(cluster = dbscan(cbind(correct,rt), eps = 0.3, minPts = 3)$cluster) + +NB_avg %>% + ggplot(aes(skewness, correct, color=factor(cluster))) + + ggtitle(" clusters (window = 16 trials)", "NOTE: each point is a single participant") + + geom_point(alpha=0.3) + + #geom_smooth(method='lm', se = F) + + facet_wrap(~condition) + +``` + + +```{r} +## single-subject figures +NB_modified %>% + ggplot(aes(t,s,color=correct)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + inspect_cor(show_plot = T) + +NB_avg %>% + inspect_cor(show_plot = T) + +NB_modified %>% + ggplot(aes(rt,correct,color=u)) + + geom_jitter() + + geom_point() + + stat_summary(fun.y="mean") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(t),color=correct)) + + geom_jitter() + + geom_point(alpha=0.1) + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(s),jitter(u),color=correct)) + + geom_jitter() + + geom_point() + + facet_wrap(~condition) + +# rt/accuracy and lures +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(jitter(l),rt,color=correct,alpha=0.01)) + + geom_jitter() + + geom_point(shape=16) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,pc2,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,rt,color=correct)) + + geom_point(alpha=0.3) + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + +NB_modified %>% + filter(!is.na(correct)) %>% + ggplot(aes(pc1,correct,color=correct)) + + geom_point() + + geom_smooth(method="lm",se = F) + + facet_wrap(~condition, scales="free") + + +``` + +## TODO + - data %>% mutate(constraint1=fitness1(history), constrain2=fitness2(history), + - constraint3=fitness(history)) + - kmeans(NB) + - ggplot(kmeans_clusters$accuracy) + - ggplot(kmeans_clusters$rt) + - + + + + +```{python} +a=2 +p +``` diff --git a/ccn2019.rev2.Rmd b/ccn2019.rev2.Rmd index 7582591..7e19f45 100644 --- a/ccn2019.rev2.Rmd +++ b/ccn2019.rev2.Rmd @@ -3,6 +3,8 @@ output: html_notebook: default pdf_document: default +editor_options: + chunk_output_type: console --- # Problems @@ -69,7 +71,7 @@ x_{vl} = min(|V|, w) $$ -```{r libraries, message=FALSE, include=FALSE, paged.print=FALSE} +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} library(ggplot2) library(tidyverse) library(stringi) @@ -80,10 +82,14 @@ library(caret) library(here) library(tsibble) +library(broom) +library(rsample) + ``` ```{r preprocessing} -load(here('data/CL2015.RData')) + +load(here('notebooks/data/CL2015.RData')) window_size <- 8 with_lures <- function(stimulus, stimulus_type, n) { @@ -96,37 +102,111 @@ }) } -NB2 <- NB %>% - group_by(participant, condition, block) %>% +seqs <- NB %>% + group_by(participant, block, condition) %>% mutate(n = ifelse(condition=='2-back',2,3)) %>% mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% - mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size)) %>% - mutate(ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size)) %>% - mutate(sl = slide_dbl(stimulus, ~sum(sort(table(.), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size)) %>% - mutate(ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size)) %>% - mutate(vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size)) %>% - mutate(t = length(which(stimulus_type=='target'))) %>% - mutate(l = length(which(stimulus_type=='lure'))) %>% - mutate(s = sum(sort(table(stimulus), decreasing = T)[1:2]) - 1) %>% - mutate(v = length(unique(stimulus))) %>% - # replace NAs in sl column - mutate(sl = ifelse(is.na(sl), 0, sl)) %>% - nest(.key='design_matrix') + mutate(tl = slide_dbl(stimulus_type, ~length(which(.=='target')), .partial=T,.size=window_size), + ll = slide_dbl(stimulus_type, ~length(which(.=='lure')), .partial=T, .size=window_size), + sl = slide_dbl(stimulus, ~(sum(sort(table(.), decreasing = T)[1:2]) - 1), .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + ul = slide_dbl(stimulus, ~(max(table(.))-1), .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~(length(unique(.))), .partial=T, .size=window_size), + al = slide_dbl(correct, ~(length(which(.))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) -# Models -NB2 <- NB2 %>% - mutate(model.lm = map(design_matrix, ~lm(rt~.,.x))) %>% - mutate(model.pls = map(design_matrix, ~plsr(rt ~ ., data = .x, validation = "CV"))) +View() +inspectdf::inspect_cor(seqs) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +model1 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a,data=., family = "gaussian") +aug1 <- augment(model1) +aug1 %>% + ggplot(aes(a,rt)) + + geom_point() + + geom_smooth(aes(y=.fitted, color='red')) +``` + +```{r} +model2 <- NB2 %>% + select(-participant, -stimulus) %>% + glm(rt~t+n+a+al+s+sl+ll+l,data=., family = "gaussian") +aug2 <- augment(model2) +aug2 %>% + ggplot(aes(jitter(al),rt)) + + geom_point(alpha=0.2,shape=18) + + xlab("accuracy") + + geom_smooth(aes(y=.fitted), color='blue') + + geom_smooth(aes(y=aug1$.fitted), color='red') + +``` + +```{r models} + +nb_split <- initial_split(NB2, prop = 0.75) +training_data <- training(nb_split) +testing_data <- testing(nb_split) +cv_split <- vfold_cv(training_data, v = 5) +cv_data <- cv_split %>% + mutate( + train = map(splits, ~training(.x)), + validate = map(splits, ~testing(.x)) + ) + +cv_models_lm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_glm_a <- cv_data %>% + mutate(model = map(train, ~lm(formula = a~., data = .x)), + tidied = map(model, tidy), + glanced = map(model, glance), + augment = map(model, augment)) + +cv_models_pls_a <- cv_data %>% + mutate(model = map(train, ~plsr(a~., data = .x, validation = "CV")), + best_dims = map_dbl(model, ~which.min(RMSEP(.x)$val[estimate="adjCV",,]) - 1)) %>% + mutate(model = map(train, ~plsr(a ~ ., data = .x, ncomp = best_dims)) + ) + +head(cv_models_pls_a) + + +cv_models_pls_a1 <- cv_data[3][[1]] + + +NBx <- NB %>% + group_by(participant) %>% + summarise(freq = as.data.frame(table(stimulus))) + +ggplot(NBx$freq, aes(, group=participant)) + + geom_point(se = F) + + +#%>% +# mutate(model.pls = map(variables, ~plsr(rt ~ ., data = .x, validation = "CV"))) #mutate(model.pca = map(design_matrix, ~prcomp(~rt,.x, center=T,scale.=T, na.action=na.exclude))) %>% #mutate(pc1=pca$x[,'PC1'], pc2=pca$x[,'PC2']) -# caret -library(caret) # Compile cross-validation settings - -any(is.na(NB2)) -NB2 <- na.omit(NB2) +#any(is.na(NB2)) +#NB2 <- na.omit(NB2) # set.seed(100) # trainingfold <- createMultiFolds(NB2@correct, k = 5, times = 10) @@ -143,9 +223,7 @@ # plot(mod1) -plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) -plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(rt ~ ., data=NB2[,c("rt","x_sl","x_ul","x_t","x_l")],3) +#plsResult <- plsR(correct ~ ., data=NB2[,c("correct","x_sl","x_ul","x_t","x_l")],3) - -plsResult -``` \ No newline at end of file +``` diff --git a/ccn2019.rev3.Rmd b/ccn2019.rev3.Rmd new file mode 100644 index 0000000..06a6d04 --- /dev/null +++ b/ccn2019.rev3.Rmd @@ -0,0 +1,102 @@ +```{r setup, message=FALSE, include=FALSE, paged.print=FALSE} +library(ggplot2) +library(tidyverse) +library(stringi) +library(pls) +#library(plsRglm) +#library(plsdof) +library(pls) +library(caret) +library(here) +library(tsibble) +library(broom) +library(rsample) +library(inspectdf) +``` + + +```{r preprocessing} + +load(here('notebooks/data/CL2015.RData')) +window_size <- 8 + +with_lures <- function(stimulus, stimulus_type, n) { + sapply(1:length(stimulus), function(i) { + lures <- c(as.character(stimulus[i-n-1]), as.character(stimulus[i-n+1])) + are_valid_trials <- i>n && all(!is.na(c(lures,stimulus[i]))) + ifelse(are_valid_trials && stimulus[i] %in% lures, + "lure", + as.character(stimulus_type[i])) + }) +} + + +invs <- function(s) { + print(length(s)!=8) + 1 +} + +seqs <- NB %>% + group_by(participant, block, condition) %>% + mutate(n = ifelse(condition=='2-back',2,3)) %>% + mutate(stimulus_type = with_lures(stimulus, stimulus_type, n)) %>% + mutate(tl = slide2_dbl(stimulus_type, rt, ~length(which(.x=='target'))/length(which(!is.na(.y))), .partial=T,.size=window_size), + ll = slide2_dbl(stimulus_type, rt, ~length(which(.x=='lure'))/length(which(!is.na(.y))), .partial=T, .size=window_size), + sl = slide_dbl(stimulus_type, ~sum(sort(table(.x), decreasing = T)[1:2]) - 1, .partial=T, .size=window_size), + sl = ifelse(is.na(sl), 0, sl), + tl = ifelse(is.na(tl), NA, tl), + ll = ifelse(is.na(ll), NA, ll), + ul = slide_dbl(stimulus, ~max(table(.))-1, .partial=T, .size=window_size), + vl = slide_dbl(stimulus, ~length(unique(.)), .partial=T, .size=window_size), + al = slide2_dbl(correct, rt, ~length(which(.x))/length(which(!is.na(.y))), .partial=T, .size=window_size)) %>% + nest(.key='local_stats') %>% + #mutate(stimuli = map(local_stats, ~paste0(.x$stimulus,collapse = ''))) %>% + mutate(a = map_dbl(local_stats, ~length(which(.x$correct)))) %>% + mutate(t = map_dbl(local_stats, ~length(which(.x$stimulus_type=='target')))) %>% + mutate(l = map_dbl(local_stats, ~length(which(.x$stimulus_type=='lure')))) %>% + mutate(s = map_dbl(local_stats, ~sum(sort(table(.x$stimulus), decreasing = T)[1:2]) - 1)) %>% + mutate(v = map_dbl(local_stats, ~length(unique(.x$stimulus)))) %>% + mutate(local_stats = map(local_stats, ~.x %>% select(-trial,-stimulus,-stimulus_type,-choice))) %>% + ungroup() %>% + select(-participant,-block,-condition) + +inspect_cor(seqs %>% unnest(local_stats), show_plot = T) +#inspect_cor(NB,show_plot = T) +``` + +```{r} +data <- seqs %>% + unnest(local_stats) %>% + mutate(correct=factor(as.numeric(correct),labels=c("C","I"))) %>% + filter(!is.na(correct), !is.na(rt)) + +shuff <- sample(nrow(data)) +split <- nrow(data) * 0.8 + + +train <- data[1:split,] +test <- data[(split+1):nrow(data),] + +model <- train( + correct ~ ., + data = train, + method = "glm", + family = "binomial", + trControl = trainControl( + method = "cv", + number = 5, + classProbs = T, + summaryFunction = twoClassSummary + ) +) + +model + +p <- predict(model, test, type="prob") + +confusionMatrix(ds$correct, prd) + +library(caTools) +colAUC(p,test$correct, plotROC=T) +``` + diff --git a/contiguous_seqs.ipynb b/contiguous_seqs.ipynb deleted file mode 100644 index 44905ae..0000000 --- a/contiguous_seqs.ipynb +++ /dev/null @@ -1,57 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "text": [ - "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" - ], - "output_type": "stream" - } - ], - "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", - "metadata": { - "pycharm": { - "metadata": false, - "name": "#%%\n" - } - } - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/ddm_playground.ipynb b/ddm_playground.ipynb deleted file mode 100644 index be389b6..0000000 --- a/ddm_playground.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" - } - ], - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - }, - "kernelspec": { - "name": "python3", - "language": "python", - "display_name": "Python 3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/pls_playground.Rmd b/pls_playground.Rmd index d4da99c..c566656 100644 --- a/pls_playground.Rmd +++ b/pls_playground.Rmd @@ -43,8 +43,8 @@ pls.model = plsr(rt ~ ., data = data, validation = "CV") ## 3.1. find the model with lowest cv error -cv <- RMSEP(pls.model) -best_dims <- which.min(cv$val[estimate = "adjCV", , ]) - 1 + +best_dims <- which.min(RMSEP(pls.model)$val[estimate = "adjCV", , ]) - 1 ## 4. rebuild the model pls.model <- plsr(rt ~ ., data = data, ncomp = best_dims) diff --git a/py/bayes.ipynb b/py/bayes.ipynb new file mode 100644 index 0000000..786f655 --- /dev/null +++ b/py/bayes.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": "\nimport numpy as np\n\nnp.arange(16)\n??np\n\n", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n", + "is_executing": false + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "paste(\u0027a\u0027,\u0027b\u0027)\n\n??", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + }, + "stem_cell": { + "cell_type": "raw", + "source": "", + "metadata": { + "pycharm": { + "metadata": false + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/contiguous_seqs.ipynb b/py/contiguous_seqs.ipynb new file mode 100644 index 0000000..44905ae --- /dev/null +++ b/py/contiguous_seqs.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "name": "stdout", + "text": [ + "a\nab\nabc\nb\nbc\nbcd\nc\ncd\ncde\nd\nde\ndef\ne\nef\nf\n" + ], + "output_type": "stream" + } + ], + "source": "original_seq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027]\nmin_len \u003d 1\nmax_len \u003d 3\n\n\ncontig_seqs \u003d list()\n\nfor st in range(len(original_seq)):\n min_fin_index \u003d st + min_len\n max_fin_index \u003d min(st + max_len, len(original_seq)) + 1\n\n for fin in range(min_fin_index, max_fin_index):\n seq \u003d original_seq[st:fin]\n contig_seqs.append(seq)\n\nfor cs in contig_seqs:\n print(\u0027\u0027.join(cs))\n" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": "from scipy import stats\nimport heapq # to extract n largest values with nlargest()\n\n# PARAMS\n\nseq \u003d [\u0027a\u0027,\u0027b\u0027,\u0027c\u0027,\u0027d\u0027,\u0027e\u0027,\u0027f\u0027,\u0027e\u0027] # trials\nN \u003d 2 # N as in N-Back\n\n\ntrials \u003d len(seq)\n\ndef count_targets_and_lures():\n # the first trials are distractors\n mask \u003d \u0027D\u0027 * N\n for index in range(N, trials):\n if seq[index] \u003d\u003d seq[index - N]:\n mask +\u003d \u0027T\u0027\n elif seq[index] in seq[index - N - 1:index - N + 1]:\n mask +\u003d \u0027L\u0027\n else:\n mask +\u003d \u0027D\u0027\n return mask.count(\u0027T\u0027), mask.count(\u0027L\u0027)\n\n\ntargets,lures \u003d count_targets_and_lures()\ntargets_norm \u003d stats.norm(targets, 0.5)\nskewness_norm \u003d stats.norm(0, 0.5)\n\ndef skewness_cost(choices):\n even_ratio \u003d len(seq) / len(choices)\n costs \u003d {c: abs(seq.count(c) - even_ratio) for c in choices}\n max_deviation_from_even_dist \u003d max(list(costs.values()))\n cost \u003d 1.0 - (skewness_norm.pdf(max_deviation_from_even_dist) / skewness_norm.pdf(0))\n return cost\n\n\n\ndef lures_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\n\ndef targets_ratio_cost():\n return 1.0 - targets_norm.pdf(targets)\n\ndef ralph2014_skewness(choices):\n freqs \u003d [float(seq.count(c)) for c in choices]\n ralph_skewed \u003d sum(heapq.nlargest(int(len(choices) / 2), freqs)) \u003e (trials * 2 / 3)\n return ralph_skewed", + "metadata": { + "pycharm": { + "metadata": false, + "name": "#%%\n" + } + } + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/ddm_playground.ipynb b/py/ddm_playground.ipynb new file mode 100644 index 0000000..be389b6 --- /dev/null +++ b/py/ddm_playground.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": "from ddm import Model\nimport matplotlib.pyplot as plt\n\n%matplotlib inline\n\nm \u003d Model()\ns \u003d m.solve()\nplt.plot(s.model.t_domain(), s.pdf_corr())\nplt.show()\n" + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + }, + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/py/test_jupyter.ipynb b/py/test_jupyter.ipynb new file mode 100644 index 0000000..04a3fb9 --- /dev/null +++ b/py/test_jupyter.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "pycharm": {} + }, + "outputs": [ + { + "data": { + "text/plain": [ + "26" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": "import random\nrandom.Random().randint(1,100)\n" + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": true, + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": "from matplotlib import pyplot as plt\nimport numpy as np\n%matplotlib inline\n\n# Data for plotting\nt \u003d np.arange(0.0, 2.0, 0.01)\ns \u003d 1 + np.sin(2 * np.pi * t)\n\nfig, ax \u003d plt.subplots()\nax.plot(t, s)\n\nax.set(xlabel\u003d\u0027time (s)\u0027, ylabel\u003d\u0027voltage (mV)\u0027,\n title\u003d\u0027About as simple as it gets, folks\u0027)\nax.grid()\n\nfig.savefig(\"test.png\")\nplt.show()" + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "pycharm": {} + }, + "outputs": [], + "source": "# change to R kernel\n#library(ggplot2)\n#qplot(wt,mpg,data\u003dmtcars)" + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "pycharm": {} + }, + "outputs": [ + { + "data": { + "image/png": "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\nQIAAAQK1JyAg1V6fqTEBAgQIECBAgAABAjkJCEg5wSqWAAECBAgQIECAAIHaExCQaq/P1JgA\nAQIECBAgQIAAgZwEBKScYBVLgAABAgQIECBAgEDtCQhItddnakyAAAECBAgQIECAQE4CAlJO\nsIolQIAAAQIECBAgQKD2BASk2uszNSZAgAABAgQIECBAICcBASknWMUSIECAAAECBAgQIFB7\nAgJS7fWZGhMgQIAAAQIECBAgkJOAgJQTrGIJECBAgAABAgQIEKg9AQGp9vpMjQkQIECAAAEC\nBAgQyElAQMoJVrEECBAgQIAAAQIECNSegIBUe32mxgQIECBAgAABAgQI5CQgIOUEq1gCBAgQ\nIECAAAECBGpPoLH2qlx7NV69enU89thj0dDQEHvssUcMHDiw14145pln4pVXXomddtopxo4d\n2+tyPJEAAQIECBAgQIAAgY4CAlJHk7LOue222+L000+PVatWZeUOHTo0vv71r8fUqVN7tJ2/\n/vWvceqpp8bvf//7aGxsjKampjjhhBPiK1/5yiYFrh5VwsoECBAgQIAAAQIECi7gFLscO/jX\nv/51nHLKKbF8+fJoaWnJbsuWLYsZM2bEb3/7225vubm5OY477rh48sknY+3atVk4Sk++4447\n4l/+5V+6XY4VCRAgQIAAAQIECBDYsICAtGGfTVr6zW9+Mws0nRVy1VVXdTa703n33HNPpCNI\nKWStO61ZsyZuuummeP3119ed7T4BAgQIECBAgAABAr0UEJB6Cdedpz399NOdBqTW1tb44x//\n2J0isnX+/Oc/R79+nXdVKuv555/vdllWJECAAAECBAgQIECga4HOP3V3vb4lPRDYbrvtulx7\nQ8vWf9LWW2+9/qx2j9/2tre1e+wBAQIECBAgQIAAAQK9ExCQeufWrWel3xr179+/w7rpaFBa\n1t3pyCOPjGHDhmWj4K37nAEDBsR73/veGD169Lqz3SdAgAABAgQIECBAoJcCAlIv4brztBRe\nvvSlL2Wnxw0ePDjSLQWmNLDC4Ycf3p0isnXSyHe33HJLjBkzJlIoGjJkSFbOPvvsk42I1+2C\nrEiAAAECBAgQIECAwAYFDPO9QZ5NX/j5z38+G9J77ty5WWEHH3xwjBs3rscF77777vHQQw/F\n/fffH4sWLYqdd9459t9//x6X4wkECBAgQIAAAQIECHQtICB1bVO2Jek3RNOmTdvk8gYNGhTv\nec97NrkcBRAgQIAAAQIECBAg0LmAU+w6dzGXAAECBAgQIECAAIE6FKiKI0ivvfZazJkzJxsS\n+8ADD4z1R2VL1/959NFHswul7rrrrnHAAQfUYVdpMgECBAgQIECAAAECeQtU/AjSL3/5yzj2\n2GPjV7/6Vdx3333x0Y9+NB5++OG2dqdw9IlPfCIuuOCC7GKpF110UVxxxRVty90hQIAAAQIE\nCBAgQIBAuQQqegSpqakprrnmmvj4xz8eJ5xwQtamyy67LL7zne+0DUBw2223xRtvvBG33npr\nNtT1X/7ylzj55JPjqKOOil122aVcDsohQIAAAQIECBAgQIBAVPQIUjo6NHPmzPjABz7Q1hWj\nRo2KJUuWtD1+4IEH4ogjjsjCUZq5ww47RBrRbfbs2W3ruEOAAAECBAgQIECAAIFyCFT0CFK6\nLtDkyZOzdixevDgbxvpHP/pRfOxjH2tr24IFCyKNArfulB6noa7Xn9Iw2MuWLWubPXLkyNhx\nxx3bHlfiTkNDQ6TR51pbWyux+brYZrrwbprSNaaStSk/gWScrsWV9mtTvgJpv7Y/52vc2NiY\n/faVc77OpdcLzvk6p9dm74P5GqfSS585Bg4c6LNdjtzJufQZupybKb0ebazMigakdSuXfls0\nf/78LAwdeuih2aLm5uZ49dVXY/PNN1931ezx008/3W5eenDJJZfEU0891TY/XSfopptuantc\nqTspqJnyF0hvvt6A+8Y5/63YQvrwvsUWW4DoA4Fhw4b1wVZswv7cN/uA98G+cfbZrm+cy/26\nsWbNmm5VvGoC0pVXXhlpNLv0+6P0G6Pbb789C0IpQaagtO6UHnf2hpael45ElaY0Gt7rr79e\neliRv6meK1asyL6lrEgF6mCjaR8ZPnx4pJ1+1apVddDiyjUxHfVN///W/z9ZuRoVc8ubbbZZ\n9s3k8uXLi9nAKmlV+gY4Td19w6ySatdcNdL7YHqdXvcMj5prRA1UOH2pkm7eB/PtrCFDhmRn\nUqT9ee3atflurI5LT0d6knX6DF3OKfVZ6bV/Q+VWTUBKlUxpfMaMGXHnnXfGvHnz4r3vfW/2\nDer6L6op9IwbN65Du9JoeOtP6RS9Sk6lznWKXX69kE4pSAEpfWj3gTI/51RyevNduXKlD5T5\nMkcKSOk3mvbnnKHfLD69WZb7DTj/WtfWFtL7YApI9ud8+y0dOUpfYnHO1zmdyphu6b0wvU6b\n8hFIrxlpny73/pw+M3ZnquggDc8991xMmzYtXnrppba6pm8+0g5XSuVvf/vb44knnmhbnu48\n+eSTsc0227Sb5wEBAgQIECBAgAABAgQ2VaCiAWn8+PGx1VZbZUN9L126NF5++eW4+uqrY8SI\nETFx4sSsbemo0D333JOFohSa0ql36XSIqVOnbmrbPZ8AAQIECBAgQIAAAQLtBCp+it1ZZ50V\nF154YRxzzDHZOfdpGO9Zs2ZFGu47TSkopWsknXnmmdkhzXTk6Pzzz89OqWrXEg8IECBAgAAB\nAgQIECCwiQIVD0gTJkzIRppLw3Z3NWrTqaeeGieddFI24MKYMWM2scmeToAAAQIECBAgQIAA\ngc4FKh6QStUaO3Zs6W6nf9OIE8JRpzRmEiBAgAABAgQIECBQJoGK/gapTG1QDAECBAgQIECA\nAAECBMoiICCVhVEhBAgQIECAAAECBAgUQUBAKkIvagMBAgQIECBAgAABAmUREJDKwqgQAgQI\nECBAgAABAgSKICAgFaEXtYEAAQIECBAgQIAAgbIICEhlYVQIAQIECBAgQIAAAQJFEBCQitCL\n2kCAAAECBAgQIECAQFkEBKSyMCqEAAECBAgQIECAAIEiCAhIRehFbSBAgAABAgQIECBAoCwC\nAlJZGBVCgAABAgQIECBAgEARBASkIvSiNhAgQIAAAQIECBAgUBYBAaksjAohQIAAAQIECBAg\nQKAIAgJSEXpRGwgQIECAAAECBAgQKIuAgFQWRoUQIECAAAECBAgQIFAEAQGpCL2oDQQIECBA\ngAABAgQIlEVAQCoLo0IIECBAgAABAgQIECiCgIBUhF7UBgIECBAgQIAAAQIEyiIgIJWFUSEE\nCBAgQIAAAQIECBRBQEAqQi9qAwECBAgQIECAAAECZREQkMrCqBACBAgQIECAAAECBIogICAV\noRe1gQABAgQIECBAgACBsggISGVhVAgBAgQIECBAgAABAkUQEJCK0IvaQIAAAQIECBAgQIBA\nWQQEpLIwKoQAAQIECBAgQIAAgSIICEhF6EVtIECAAAECBAgQIECgLAICUlkYFUKAAAECBAgQ\nIECAQBEEBKQi9KI2ECBAgAABAgQIECBQFgEBqSyMCiFAgAABAgQIECBAoAgCAlIRelEbCBAg\nQIAAAQIECBAoi4CAVBZGhRAgQIAAAQIECBAgUAQBAakIvagNBAgQIECAAAECBAiURUBAKguj\n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\nCBAgQIBAvQkISPXW49pLgAABAgQIECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYS\nIECAAAECBAgQINClgIDUJY0FBAgQIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1\nSWMBAQIECBAgQIAAAQL1JiAg1VuPay8BAgQIECBAgAABAl0KCEhd0lhAgAABAgQIECBAgEC9\nCQhI9dbj2kuAAAECBAgQIECAQJcCAlKXNBYQIECAAAECBAgQIFBvAgJSvfW49hIgQIAAAQIE\nCBAg0KWAgNQljQUECBAgQIAAAQIECNSbgIBUbz2uvQQIECBAgAABAgQIdCkgIHVJYwEBAgQI\nECBAgAABAvUmICDVW49rLwECBAgQIECAAAECXQoISF3SWECAAAECBAgQIECAQL0JCEj11uPa\nS4AAAQIECBAgQIBAlwICUpc0FhAgQIAAAQIECBAgUG8CAlK99bj2EiBAgAABAgQIECDQpYCA\n1CWNBQQIECBAgAABAgQI1JuAgFRvPa69BAgQIECAAAECBAh0KSAgdUljAQECBAgQIECAAAEC\n9SYgINVbj2svAQIECBAgQIAAAQJdCghIXdJYQIAAAQIECBAgQIBAvQkISPXW49pLgAABAgQI\nECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYSIECAAAECBAgQINClgIDUJY0FBAgQ\nIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1SWMBAQIECBAgQIAAAQL1JiAg1VuP\nay8BAgQIECBAgAABAl0KCEhd0lhAoDoEWltb4+qrr4799tsvxo8fH1OmTIm77rqrOiqnFjUr\n8Oc//zlOPvnk2GmnnWKXXXaJT3/60/Hqq6/WbHtUnAABAgQIlEtAQCqXpHII5CRw1llnxVe/\n+tVYsGBBrFmzJv74xz/GjBkz4pZbbslpi4otusBzzz0XRx55ZNx3332xYsWKWLZsWfz4xz+O\nf/iHf4ilS5cWvfnaR4AAAQIENiggIG2Qx0IClRV44okn4vbbb4+mpqZ2FWlpaYl/+Zd/yQJT\nuwUeEOiGwGWXXRarV6+OtB+Vpubm5li8eHF85zvfKc3ylwABAgQI1KWAgFSX3a7RtSLw61//\nOgYOHNhpddM3/+lokolATwUefPDBduGo9Px0hPK//uu/Sg/9JUCAAAECdSkgINVlt2t0rQgM\n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\npo4CG3PZ2PKOJZpDgAABAgSqW0BAqu7+UTsCfSqwxx57xJVXXtmn2+yrjaXrOv3rv/5rh82l\no2R77713pBHNTB0Fdtxxx+x6dy+++GKHhatXr44pU6Z0mG8GAQIECBCoZQGn2NVy76k7AQLd\nFthvv/3in/7pn7JTB0tPSkc/0umFX//610uz/O1E4N/+7d+y36ilEQ3TlI7Epdv/9//9fzF+\n/Phsnn8IECBAgEBRBBxBKkpPagcBAhsVSBfCnTRpUtx6663x6quvxoEHHhinn356pOsOmboW\nSIN43HffffGtb30rHn/88dhmm23i5JNPjsmTJ3f9JEsIECBAgECNCghINdpxqk2AQO8Epk6d\nGulm6plAOlL01a9+tWdPsjYBAgQIEKhBAafY1WCnqTIBAgQIECBAgAABAvkICEj5uCqVAAEC\nBAgQIECAAIEaFBCQarDTVJkAAQIECBAgQIAAgXwEBKR8XJVKgEA3BO6444448sgjIw0vfvTR\nR8e9997bjWdVfpUf/OAH8fd///dZvadNmxbz5s2rfKXUgAABAgQIECiLgIBUFkaFECDQU4HL\nL788PvOZz8Tvf//7WLx4cfzmN7/JRkZLI8xV83T++efHueeeG3/4wx+yev/qV7+K4447Ln76\n059Wc7XVjQABAgQIEOimgIDUTSirESBQPoF00dFvfvOb0dLS0q7Q1tbW7No6K1eubDe/Wh48\n/fTT8e///u/R3NzcVqW1a9dGqvfnPve5dvPbVnCHAAECBAgQqCkBAammuktlCRRDIB11GThw\nYKeNaWpqivnz53e6rNIz586dG4MGDeq0Gq+//nqkAGUiQIAAAQIEaltAQKrt/lN7AjUp0L9/\n/y7rnY7INDZW5yXaNlSvVO8BAwZ02S4LCBAgQIAAgdoQEJBqo5/UkkChBA499NAuT0cbPnx4\n7LnnnlXZ3sMOOyzWrFnTad222mqr2GmnnTpdZiYBAgQIECBQOwICUu30lZoSKIzAmDFj4pJL\nLomGhobslhqWjiql27/+679W7ZGY7bffPvuNVKp3aUp1TkeO/u3f/q2tLaVl/hIgQIAAAQK1\nJ1Cd57HUnqMaEyDQQ4GTTz45JkyYENdff3385S9/iV122SU++clPxjve8Y4eltS3q59xxhlZ\nHf/jP/4j0mATu+++e1bv1BYTAQIECBAgUPsCAlLt96EWEKhZgYkTJ0a61dr07ne/O9LNRIAA\n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\nZcvSww8/nOLv/vvvnz7xiU9swbvq85L169enxx9/PL322mtp5513Tp/+9KfT6NGj61N4zqVI\nkHIGVjwBAgQIECBAgACB/hZ47LHH0syZMzurbW9vTwceeGD69a9/nXuismTJkjRjxoz01ltv\npYED/3fCWktLS7r55pvToYce2tmmZp1xil2z9ox2ESBAgAABAgQIENgGgYULF6azzjorvf/+\n+52PSJCef/75dOGFF25DiVv3llmzZqU333wzrV27Nq1ZsyZ7rFq1Kp1xxhkp/jb7JEFq9h7S\nPgIECBAgQIAAAQJbIXD33XenAQMGbPaOSFhiXWtr62br6rVg0aJF6cknn0yRkG06tbW1pYce\nemjTxU33XILUdF2iQQQIECBAgAABAgS2XSCSlK4SlChx3bp1acWKFdteeC/vXLx4cbeviKQt\n2tbskwSp2XtI+wgQIECAAAECBAhshcC+++6bBg0a1OU7Ro4cmXbaaacu19Vj4Z577tlt3ZGc\nfeADH6hHNbmWIUHKlVfhBAgQIECAAAECBPpX4MQTT0w77rjjZonK4MGD0/nnn7/Z8nq2LhKw\ns88+Ow0ZMmSjYqPuffbZJx155JEbLW/GJxKkZuwVbSJAgAABAgQIECCwjQLDhg1Ld955ZzZq\nXUcRMYrcBRdckL7yla90LMrt70UXXZSNoFd7FOvwww9Pt99+e+eodrlVXoeCDfNdB0RFECBA\ngAABAgQIEGgmgV133TXdc889acGCBWn58uVpr732SsOHD++XJkZi9K1vfSs7WjVv3rzslL44\nolWUSYJUlJ7STgIECBAgQIAAAQJbKTBx4sQUj0ZMcbrdlClTGlF1n+p0il2f+LyZAAECBAgQ\nIECAAIEyCTTVEaQnnngiu7PvQQcdtJFxjHjx3HPPpZdffjlNnjw5feQjH9lovScECBAgQIAA\nAQIECBCoh0DTHEGKBOjb3/52lgTVBhbJ0TnnnJO+853vpH//+9/p0ksvTVdffXXtS8wTIECA\nAAECBAgQIECgLgINP4IUN7G6+eabs0dXd/yN0S5Wr16dbrvtthTnMc6fPz+dccYZ6YQTTkgx\nxruJAAECBAgQIECAAAEC9RJo+BGk+++/P913333psssuS7vttttmcT311FPpmGOOyZKjWLnH\nHnuk/fffPz388MObvdYCAgQIECBAgAABAgQI9EWg4UeQPvaxj6Xjjz8+xc2jrr/++s1iiaEJ\n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\u003d\u003d", + "text/plain": [ + "plot without title" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": "" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/test_jupyter.ipynb b/test_jupyter.ipynb deleted file mode 100644 index 04a3fb9..0000000 --- a/test_jupyter.ipynb +++ /dev/null @@ -1,97 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "pycharm": {} - }, - "outputs": [ - { - "data": { - "text/plain": [ - "26" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": "import random\nrandom.Random().randint(1,100)\n" - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true, - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "data": { - "text/plain": "\u003cFigure size 432x288 with 1 Axes\u003e", - "image/png": "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\n" - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": "from matplotlib import pyplot as plt\nimport numpy as np\n%matplotlib inline\n\n# Data for plotting\nt \u003d np.arange(0.0, 2.0, 0.01)\ns \u003d 1 + np.sin(2 * np.pi * t)\n\nfig, ax \u003d plt.subplots()\nax.plot(t, s)\n\nax.set(xlabel\u003d\u0027time (s)\u0027, ylabel\u003d\u0027voltage (mV)\u0027,\n title\u003d\u0027About as simple as it gets, folks\u0027)\nax.grid()\n\nfig.savefig(\"test.png\")\nplt.show()" - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "pycharm": {} - }, - "outputs": [], - "source": "# change to R kernel\n#library(ggplot2)\n#qplot(wt,mpg,data\u003dmtcars)" - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "pycharm": {} - }, - "outputs": [ - { - "data": { - "image/png": "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\nQIAAAQK1JyAg1V6fqTEBAgQIECBAgAABAjkJCEg5wSqWAAECBAgQIECAAIHaExCQaq/P1JgA\nAQIECBAgQIAAgZwEBKScYBVLgAABAgQIECBAgEDtCQhItddnakyAAAECBAgQIECAQE4CAlJO\nsIolQIAAAQIECBAgQKD2BASk2uszNSZAgAABAgQIECBAICcBASknWMUSIECAAAECBAgQIFB7\nAgJS7fWZGhMgQIAAAQIECBAgkJOAgJQTrGIJECBAgAABAgQIEKg9AQGp9vpMjQkQIECAAAEC\nBAgQyElAQMoJVrEECBAgQIAAAQIECNSegIBUe32mxgQIECBAgAABAgQI5CQgIOUEq1gCBAgQ\nIECAAAECBGpPoLH2qlx7NV69enU89thj0dDQEHvssUcMHDiw14145pln4pVXXomddtopxo4d\n2+tyPJEAAQIECBAgQIAAgY4CAlJHk7LOue222+L000+PVatWZeUOHTo0vv71r8fUqVN7tJ2/\n/vWvceqpp8bvf//7aGxsjKampjjhhBPiK1/5yiYFrh5VwsoECBAgQIAAAQIECi7gFLscO/jX\nv/51nHLKKbF8+fJoaWnJbsuWLYsZM2bEb3/7225vubm5OY477rh48sknY+3atVk4Sk++4447\n4l/+5V+6XY4VCRAgQIAAAQIECBDYsICAtGGfTVr6zW9+Mws0nRVy1VVXdTa703n33HNPpCNI\nKWStO61ZsyZuuummeP3119ed7T4BAgQIECBAgAABAr0UEJB6Cdedpz399NOdBqTW1tb44x//\n2J0isnX+/Oc/R79+nXdVKuv555/vdllWJECAAAECBAgQIECga4HOP3V3vb4lPRDYbrvtulx7\nQ8vWf9LWW2+9/qx2j9/2tre1e+wBAQIECBAgQIAAAQK9ExCQeufWrWel3xr179+/w7rpaFBa\n1t3pyCOPjGHDhmWj4K37nAEDBsR73/veGD169Lqz3SdAgAABAgQIECBAoJcCAlIv4brztBRe\nvvSlL2Wnxw0ePDjSLQWmNLDC4Ycf3p0isnXSyHe33HJLjBkzJlIoGjJkSFbOPvvsk42I1+2C\nrEiAAAECBAgQIECAwAYFDPO9QZ5NX/j5z38+G9J77ty5WWEHH3xwjBs3rscF77777vHQQw/F\n/fffH4sWLYqdd9459t9//x6X4wkECBAgQIAAAQIECHQtICB1bVO2Jek3RNOmTdvk8gYNGhTv\nec97NrkcBRAgQIAAAQIECBAg0LmAU+w6dzGXAAECBAgQIECAAIE6FKiKI0ivvfZazJkzJxsS\n+8ADD4z1R2VL1/959NFHswul7rrrrnHAAQfUYVdpMgECBAgQIECAAAECeQtU/AjSL3/5yzj2\n2GPjV7/6Vdx3333x0Y9+NB5++OG2dqdw9IlPfCIuuOCC7GKpF110UVxxxRVty90hQIAAAQIE\nCBAgQIBAuQQqegSpqakprrnmmvj4xz8eJ5xwQtamyy67LL7zne+0DUBw2223xRtvvBG33npr\nNtT1X/7ylzj55JPjqKOOil122aVcDsohQIAAAQIECBAgQIBAVPQIUjo6NHPmzPjABz7Q1hWj\nRo2KJUuWtD1+4IEH4ogjjsjCUZq5ww47RBrRbfbs2W3ruEOAAAECBAgQIECAAIFyCFT0CFK6\nLtDkyZOzdixevDgbxvpHP/pRfOxjH2tr24IFCyKNArfulB6noa7Xn9Iw2MuWLWubPXLkyNhx\nxx3bHlfiTkNDQ6TR51pbWyux+brYZrrwbprSNaaStSk/gWScrsWV9mtTvgJpv7Y/52vc2NiY\n/faVc77OpdcLzvk6p9dm74P5GqfSS585Bg4c6LNdjtzJufQZupybKb0ebazMigakdSuXfls0\nf/78LAwdeuih2aLm5uZ49dVXY/PNN1931ezx008/3W5eenDJJZfEU0891TY/XSfopptuantc\nqTspqJnyF0hvvt6A+8Y5/63YQvrwvsUWW4DoA4Fhw4b1wVZswv7cN/uA98G+cfbZrm+cy/26\nsWbNmm5VvGoC0pVXXhlpNLv0+6P0G6Pbb789C0IpQaagtO6UHnf2hpael45ElaY0Gt7rr79e\neliRv6meK1asyL6lrEgF6mCjaR8ZPnx4pJ1+1apVddDiyjUxHfVN///W/z9ZuRoVc8ubbbZZ\n9s3k8uXLi9nAKmlV+gY4Td19w6ySatdcNdL7YHqdXvcMj5prRA1UOH2pkm7eB/PtrCFDhmRn\nUqT9ee3atflurI5LT0d6knX6DF3OKfVZ6bV/Q+VWTUBKlUxpfMaMGXHnnXfGvHnz4r3vfW/2\nDer6L6op9IwbN65Du9JoeOtP6RS9Sk6lznWKXX69kE4pSAEpfWj3gTI/51RyevNduXKlD5T5\nMkcKSOk3mvbnnKHfLD69WZb7DTj/WtfWFtL7YApI9ud8+y0dOUpfYnHO1zmdyphu6b0wvU6b\n8hFIrxlpny73/pw+M3ZnquggDc8991xMmzYtXnrppba6pm8+0g5XSuVvf/vb44knnmhbnu48\n+eSTsc0227Sb5wEBAgQIECBAgAABAgQ2VaCiAWn8+PGx1VZbZUN9L126NF5++eW4+uqrY8SI\nETFx4sSsbemo0D333JOFohSa0ql36XSIqVOnbmrbPZ8AAQIECBAgQIAAAQLtBCp+it1ZZ50V\nF154YRxzzDHZOfdpGO9Zs2ZFGu47TSkopWsknXnmmdkhzXTk6Pzzz89OqWrXEg8IECBAgAAB\nAgQIECCwiQIVD0gTJkzIRppLw3Z3NWrTqaeeGieddFI24MKYMWM2scmeToAAAQIECBAgQIAA\ngc4FKh6QStUaO3Zs6W6nf9OIE8JRpzRmEiBAgAABAgQIECBQJoGK/gapTG1QDAECBAgQIECA\nAAECBMoiICCVhVEhBAgQIECAAAECBAgUQUBAKkIvagMBAgQIECBAgAABAmUREJDKwqgQAgQI\nECBAgAABAgSKICAgFaEXtYEAAQIECBAgQIAAgbIICEhlYVQIAQIECBAgQIAAAQJFEBCQitCL\n2kCAAAECBAgQIECAQFkEBKSyMCqEAAECBAgQIECAAIEiCAhIRehFbSBAgAABAgQIECBAoCwC\nAlJZGBVCgAABAgQIECBAgEARBASkIvSiNhAgQIAAAQIECBAgUBYBAaksjAohQIAAAQIECBAg\nQKAIAgJSEXpRGwgQIECAAAECBAgQKIuAgFQWRoUQIECAAAECBAgQIFAEAQGpCL2oDQQIECBA\ngAABAgQIlEVAQCoLo0IIECBAgAABAgQIECiCgIBUhF7UBgIECBAgQIAAAQIEyiIgIJWFUSEE\nCBAgQIAAAQIECBRBQEAqQi9qAwECBAgQIECAAAECZREQkMrCqBACBAgQIECAAAECBIogICAV\noRe1gQABAgQIECBAgACBsggISGVhVAgBAgQIECBAgAABAkUQEJCK0IvaQIAAAQIECBAgQIBA\nWQQEpLIwKoQAAQIECBAgQIAAgSIICEhF6EVtIECAAAECBAgQIECgLAICUlkYFUKAAAECBAgQ\nIECAQBEEBKQi9KI2ECBAgAABAgQIECBQFgEBqSyMCiFAgAABAgQIECBAoAgCAlIRelEbCBAg\nQIAAAQIECBAoi4CAVBZGhRAgQIAAAQIECBAgUAQBAakIvagNBAgQIECAAAECBAiURUBAKguj\n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\nCBAgQIBAvQkISPXW49pLgAABAgQIECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYS\nIECAAAECBAgQINClgIDUJY0FBAgQIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1\nSWMBAQIECBAgQIAAAQL1JiAg1VuPay8BAgQIECBAgAABAl0KCEhd0lhAgAABAgQIECBAgEC9\nCQhI9dbj2kuAAAECBAgQIECAQJcCAlKXNBYQIECAAAECBAgQIFBvAgJSvfW49hIgQIAAAQIE\nCBAg0KWAgNQljQUECBAgQIAAAQIECNSbgIBUbz2uvQQIECBAgAABAgQIdCkgIHVJYwEBAgQI\nECBAgAABAvUmICDVW49rLwECBAgQIECAAAECXQoISF3SWECAAAECBAgQIECAQL0JCEj11uPa\nS4AAAQIECBAgQIBAlwICUpc0FhAgQIAAAQIECBAgUG8CAlK99bj2EiBAgAABAgQIECDQpYCA\n1CWNBQQIECBAgAABAgQI1JuAgFRvPa69BAgQIECAAAECBAh0KSAgdUljAQECBAgQIECAAAEC\n9SYgINVbj2svAQIECBAgQIAAAQJdCghIXdJYQIAAAQIECBAgQIBAvQkISPXW49pLgAABAgQI\nECBAgECXAgJSlzQWECBAgAABAgQIECBQbwICUr31uPYSIECAAAECBAgQINClgIDUJY0FBAgQ\nIECAAAECBAjUm4CAVG89rr0ECBAgQIAAAQIECHQpICB1SWMBAQIECBAgQIAAAQL1JiAg1VuP\nay8BAgQIECBAgAABAl0KCEhd0lhAoDoEWltb4+qrr4799tsvxo8fH1OmTIm77rqrOiqnFjUr\n8Oc//zlOPvnk2GmnnWKXXXaJT3/60/Hqq6/WbHtUnAABAgQIlEtAQCqXpHII5CRw1llnxVe/\n+tVYsGBBrFmzJv74xz/GjBkz4pZbbslpi4otusBzzz0XRx55ZNx3332xYsWKWLZsWfz4xz+O\nf/iHf4ilS5cWvfnaR4AAAQIENiggIG2Qx0IClRV44okn4vbbb4+mpqZ2FWlpaYl/+Zd/yQJT\nuwUeEOiGwGWXXRarV6+OtB+Vpubm5li8eHF85zvfKc3ylwABAgQI1KWAgFSX3a7RtSLw61//\nOgYOHNhpddM3/+lokolATwUefPDBduGo9Px0hPK//uu/Sg/9JUCAAAECdSkgINVlt2t0rQgM\nHjy4y6quXbs2NrS8yydaUPcCgwYN6tJg2LBhXS6zgAABAgQI1IOAgFQPvayNNStw+OGHdzi9\nLjWmoaEhtttuu5gwYULNtk3FKydw9NFHx4ABAzpUoLGxMdIyEwECBAgQqGcBAamee1/bq15g\n3Lhx8ZWvfCULRP3798/qmz7YpiNH11xzTdXXXwWrU+Czn/1sNnrduqdvpnB02GGHxfHHH1+d\nlVYrAgQIECDQRwKNPd3Ol7/85bjkkku6fFr6ZjudojFmzJg49NBDs9G3tthiiy7Xt4AAgQ0L\nTJ8+Pd75znfGTTfdFC+++GLsvvvu8dGPfjS22WabDT/RUgJdCKTX6DvvvDNuvvnm+OUvfxnp\nlLv3ve99ccwxx0S/fr4364LNbAIECBCoE4EeB6SDDz449tprr3jooYdi7733jn333TeGDBkS\n6Zoas2fPzk7bmDx5cixZsiSuv/76+M1vfhP33HNPFpjqxFQzCZRdIP1fSzcTgXIJpFCUgna6\nmQgQIECAAIG3BHr8VWE6GvT444/Ht7/97fjd736XhaCrrroq+zYyzR8+fHh2LY10fY05c+Zk\nwenGG298a4vuESBAgAABAgQIECBAoEoFehyQ0mk+6ahRulDl+tOuu+4a6aKWKTCl6ZBDDokp\nU6bEvHnz1l/VYwIECBAgQIAAAQIECFSdQI8D0sKFCzd4utzIkSPjhRdeaGtoGmUr/W7CRIAA\nAQIECBAgQIAAgWoX6PFvkP7+7/8+PvWpT8XTTz8dO++8c7v2NTU1xXe/+93sN0qlBemig+k5\nlZo233zzSm062276wXM67dCUn0AaGCRNaXS3Svd3fq2sjpKTcfJ2/aX8+yONWmh/ztc57c/p\nemJpBD9TfgKlETjtz/kZp5KTs9eNfI1T6el1I03ps116/TDlI5A+a+SxP7e2tnarwj1+Vzjq\nqKPiggsuiIkTJ2ZBKf1wPA0VmwZpSL9Leuqpp+KnP/1ppAqkUZEefvjhmDVrVrcqk8dK6crw\nlZzSD6FTcPSfKL9eKI26lfa5Svd3fq2sjpLTB8nm5ubsVh01KmYthg4dmr1m2J/z7d/Slyuc\n83VO74Ppgw7nfJ3T63Papznn61wKSOmzXXc/bOdbo2KWnvbllC8qtT/3OCBtueWWWeg54YQT\n4qKLLmrXK+PHj49bbrklG6Thueeei7lz58bZZ58daVS7Sk2rVq2q1Kaz7aZvGFavXu0/UY69\nkN5409TS0hKV7u8cm1kVRacPOunFqlIvWFWB0EeVSG+89ud8sdNrR/ryinO+zqWzKDjn61wK\nopzzdS6dQZE+26XPHaZ8BNKX3+nLwnLvz6XPjBurdY8DUiowhaRf/OIX8eqrr2Yj2S1atCi7\n6OA+++yTpb20znbbbRfLli3Lvs1Ij00ECBAgQIAAAQIECBCodoFeBaTUqPSt22uvvZbdVq5c\n2XZOZqnB3U1opfX9JUCAAAECBAgQIECAQKUFehWQ0ulzH/zgB+PRRx9tV/90wdh0cdgTTzyx\n3XwPCBAgQIAAAQIECBAgUAsCPQ5If/3rX2O//faLYcOGxRVXXBF77rlnpGD0/PPPx3/8x3/E\n9OnTY/HixTFz5sxaaL86EiBAgAABAgQIECBAoE2gxwHp//yf/xPph4C/+c1vYquttmoraNKk\nSZEGbjjjjDPi61//uoDUJuMOAQIECBAgQIAAAQK1ItDjC8XOmTMnpk6d2i4crdvY008/PRvy\nOw37bSJAgAABAgQIECBAgEAtCfQ4IE2YMCH++Mc/dtnGBQsWZBfdGzduXJfrWECAAAECBAgQ\nIECAAIFqFOhxQDr11FPjT3/6U5xzzjmxfPnydm36wx/+EJ/+9Kez0+zS2OUmAgQIECBAgAAB\nAgQI1JJAj3+D9Otf/zrGjh0bX/va17IR697xjnfEqFGj4sUXX4z58+dnF0RNVxnea6+92hzS\nKXmXXXZZ22N3CBAgQIAAAQIECBAgUI0CPQ5IS5cuzS4Ge8ABB2TtWbNmTbz88svZdZDS6Had\nTSkwmQgQIECAAAECBAgQIFDtAj0OSDNmzIh0MxEgQIAAAQIECBAgQKBoAj3+DVLRALSHAAEC\nBAgQIECAAAECJYEeH0EqPTH9TReEbW5uXndW2/11r5HUNtMdAgQIECBAgAABAgQIVLFAjwPS\n2rVrs5Hq/v3f/73DKHbrtjOtZyJAgAABAgQIECBAgEAtCfQ4IM2dOzeuuuqqSAMyHHzwwbH5\n5pvXUnvVlQABAgQIECBAgAABAl0K9Dgg/eAHP4gdd9wx5s2bl41c12XJFhAgQIAAAQIECBAg\nQKDGBHo8SMPgwYNj5MiRwlGNdbTqEiBAgAABAgQIECCwcYEeB6TjjjsuHn/88Xj44Yc3Xro1\nCBAgQIAAAQIECBAgUEMCPT7F7qCDDoprr702Dj/88Dj++ONj/Pjx0djYsZgvfOELNcSgqgQI\nECBAgAABAgQIEIjomGw2ovLCCy/E//pf/yuWLVsW1113XZdrC0hd0lhAgAABAgQIECBAgECV\nCvQ4IH3/+9+PJ554Is4///yYOnVqbLnlllXaNNUiQIAAAQIECBAgQIBAzwR6HJAee+yx2GOP\nPeLLX/5yz7ZkbQIECBAgQIAAAQIECFS5QI8Hadh33303eIHYKm+v6hEgQIAAAQIECBAgQKBL\ngR4HpFNOOSXWrl0b55xzTqxatarLgi0gQIAAAQIECBAgQIBArQn0OCA98MADsfXWW8fXvva1\nGDp0aGy77bax5557xl577dXuVmsQ6kuAQMRPfvKTOPLII2O33XaLI444Iv73//7fWAgQIECA\nAAECdSXQ498gLVmyJNasWRMHHHBAXUFpLIGiC3z729+Oiy++OFpaWrKmLl26NGbOnBlp5Mr0\n10SAAAECBAgQqAeBhjdPl1tb5IYuWLCgos0bM2ZMpFDZ2tpa0XoUeeP9+/ePsWPHxooVKyJ9\nqDf1XOBvf/tbdgS4ubm5w5OT7+9+97tI+/KIESNi5cqV2ZckHVY0o2wC48aNi6ampli8eHHZ\nylRQR4Fhw4Zlp4yn1w5TfgLptSNdL3HhwoX5bUTJMWjQoBg8eLD3wZz3hZEjR8aQIUNi0aJF\nbV8o5rzJuiy+X79+MWrUqLK/D5Y+M24Mtcen2G2sQMsJEKg9gUceeSTSi1FnU/pg85vf/Kaz\nRTU3LwXAq666KtIFr9/5znfGRz7ykZg/f37NtaMSFX7wwQfjmGOOiXe84x1x2GGHxXe/+90s\nXFSiLrZJgAABAgTyFOjxKXZ5VkbZBAhURmDAgAFdfthNB5kHDhxYmYqVeasf/ehH4/7778+O\nzqSi58yZE+l3lbfddltMnDixzFsrTnF33nlnzJgxo+1I+GuvvRZf/OIXs2vizZo1qzgN1RIC\nBAgQIPCmQOdfGaMhQKCuBNJvCrsKQelw9Lve9a6a97j33nuzQJROXStN6dTXdFQpjcpp6lwg\n/SYt+ax/mnByu/nmm7OQ1PkzzSVAgAABArUpICDVZr+pNYGyCqQRKb/xjW9kp9mlQJSm9Ded\ndnfFFVfE8OHDy7q9ShSWjhR1Nf3pT3+KdFTE1FEg2aTfqHU2pVA9d+7czhaZR4AAAQIEalbA\nKXY123UqTqC8AkcddVTcddddcd1118Wzzz4bb3/72+O0007LhvEv75YqU1o6jbChoaHLjafl\npo4CG3PZ2PKOJZpDgAABAgSqW0BAqu7+UTsCfSqwxx57xJVXXtmn2+yrjaXrOv3rv/5rh82l\no2R77713pBHNTB0Fdtxxx+x6dy+++GKHhatXr44pU6Z0mG8GAQIECBCoZQGn2NVy76k7AQLd\nFthvv/3in/7pn7JTB0tPSkc/0umFX//610uz/O1E4N/+7d+y36ilEQ3TlI7Epdv/9//9fzF+\n/Phsnn8IECBAgEBRBBxBKkpPagcBAhsVSBfCnTRpUtx6663x6quvxoEHHhinn356pOsOmboW\nSIN43HffffGtb30rHn/88dhmm23i5JNPjsmTJ3f9JEsIECBAgECNCghINdpxqk2AQO8Epk6d\nGulm6plAOlL01a9+tWdPsjYBAgQIEKhBAafY1WCnqTIBAgQIECBAgAABAvkICEj5uCqVAAEC\nBAgQIECAAIEaFBCQarDTVJkAAQIECBAgQIAAgXwEBKR8XJVKgEA3BO6444448sgjIw0vfvTR\nR8e9997bjWdVfpUf/OAH8fd///dZvadNmxbz5s2rfKXUgAABAgQIECiLgIBUFkaFECDQU4HL\nL788PvOZz8Tvf//7WLx4cfzmN7/JRkZLI8xV83T++efHueeeG3/4wx+yev/qV7+K4447Ln76\n059Wc7XVjQABAgQIEOimgIDUTSirESBQPoF00dFvfvOb0dLS0q7Q1tbW7No6K1eubDe/Wh48\n/fTT8e///u/R3NzcVqW1a9dGqvfnPve5dvPbVnCHAAECBAgQqCkBAammuktlCRRDIB11GThw\nYKeNaWpqivnz53e6rNIz586dG4MGDeq0Gq+//nqkAGUiQIAAAQIEaltAQKrt/lN7AjUp0L9/\n/y7rnY7INDZW5yXaNlSvVO8BAwZ02S4LCBAgQIAAgdoQEJBqo5/UkkChBA499NAuT0cbPnx4\n7LnnnlXZ3sMOOyzWrFnTad222mqr2GmnnTpdZiYBAgQIECBQOwICUu30lZoSKIzAmDFj4pJL\nLomGhobslhqWjiql27/+679W7ZGY7bffPvuNVKp3aUp1TkeO/u3f/q2tLaVl/hIgQIAAAQK1\nJ1Cd57HUnqMaEyDQQ4GTTz45JkyYENdff3385S9/iV122SU++clPxjve8Y4eltS3q59xxhlZ\nHf/jP/4j0mATu+++e1bv1BYTAQIECBAgUPsCAlLt96EWEKhZgYkTJ0a61dr07ne/O9LNRIAA\n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\nZcvSww8/nOLv/vvvnz7xiU9swbvq85L169enxx9/PL322mtp5513Tp/+9KfT6NGj61N4zqVI\nkHIGVjwBAgQIECBAgACB/hZ47LHH0syZMzurbW9vTwceeGD69a9/nXuismTJkjRjxoz01ltv\npYED/3fCWktLS7r55pvToYce2tmmZp1xil2z9ox2ESBAgAABAgQIENgGgYULF6azzjorvf/+\n+52PSJCef/75dOGFF25DiVv3llmzZqU333wzrV27Nq1ZsyZ7rFq1Kp1xxhkp/jb7JEFq9h7S\nPgIECBAgQIAAAQJbIXD33XenAQMGbPaOSFhiXWtr62br6rVg0aJF6cknn0yRkG06tbW1pYce\nemjTxU33XILUdF2iQQQIECBAgAABAgS2XSCSlK4SlChx3bp1acWKFdteeC/vXLx4cbeviKQt\n2tbskwSp2XtI+wgQIECAAAECBAhshcC+++6bBg0a1OU7Ro4cmXbaaacu19Vj4Z577tlt3ZGc\nfeADH6hHNbmWIUHKlVfhBAgQIECAAAECBPpX4MQTT0w77rjjZonK4MGD0/nnn7/Z8nq2LhKw\ns88+Ow0ZMmSjYqPuffbZJx155JEbLW/GJxKkZuwVbSJAgAABAgQIECCwjQLDhg1Ld955ZzZq\nXUcRMYrcBRdckL7yla90LMrt70UXXZSNoFd7FOvwww9Pt99+e+eodrlVXoeCDfNdB0RFECBA\ngAABAgQIEGgmgV133TXdc889acGCBWn58uVpr732SsOHD++XJkZi9K1vfSs7WjVv3rzslL44\nolWUSYJUlJ7STgIECBAgQIAAAQJbKTBx4sQUj0ZMcbrdlClTGlF1n+p0il2f+LyZAAECBAgQ\nIECAAIEyCTTVEaQnnngiu7PvQQcdtJFxjHjx3HPPpZdffjlNnjw5feQjH9lovScECBAgQIAA\nAQIECBCoh0DTHEGKBOjb3/52lgTVBhbJ0TnnnJO+853vpH//+9/p0ksvTVdffXXtS8wTIECA\nAAECBAgQIECgLgINP4IUN7G6+eabs0dXd/yN0S5Wr16dbrvtthTnMc6fPz+dccYZ6YQTTkgx\nxruJAAECBAgQIECAAAEC9RJo+BGk+++/P913333psssuS7vttttmcT311FPpmGOOyZKjWLnH\nHnuk/fffPz388MObvdYCAgQIECBAgAABAgQI9EWg4UeQPvaxj6Xjjz8+xc2jrr/++s1iiaEJ\n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\u003d\u003d", - "text/plain": [ - "plot without title" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": "" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file