Skip to content
mortonne edited this page Jul 24, 2015 · 3 revisions

Introduction

The toolbox supports both univariate analysis (e.g. ANOVA) and multivariate pattern analysis. These different types of statistics are specified using a common language for defining different classes of events in an experiment.

Events

Information about events in the experiment must be stored in an events structure. This is a vector structure that can have any number of different fields to specify different things about an experiment. Each element of the events structure gives information about one event. See Events for details. To run a statistical analysis, specific information must be extracted from the events structure using regressor definitions (generally referred to in the toolbox as reg_defs or event_bins).

Regressors

Information about factors used in statistical tests are stored in regressors. A regressor is a vector, where each element is either an integer (from 1 to N, where N is the number of different conditions) or NaN (to indicate events where that regressor is undefined). For example, if you have two conditions that alternate, and there are ten events, your regressor for those conditions would be:

reg = [1 2 1 2 1 2 1 2 1 2];

This simply labels each event as belonging to one of two different conditions.

Simple Regressor Definitions

The toolbox contains functions for creating regressor vectors from events structures. Generally, statistical analysis functions call make_event_index to create regressors. This function takes a number of different types of input to create regressors in different ways. The simplest way to make a regressor is by giving the name of a field of the events structure; this will simply use that field as the regressor. The field must contain numeric, logical, or char data. It will be translated into sequential integers, which label each unique value of the field. For example:

>> events = struct('condition', {'A' 'B' 'B' 'A' 'A' 'A' 'B'});
>> [index, levels] = make_event_index(events, 'condition')

index =

     1
     2
     2
     1
     1
     1
     2

levels = 

     'A'
     'B'

The 'A' and 'B' conditions are translated into 1 and 2 in the output regressor, here referred to as an "index". The levels output gives the original label for each condition.

Event Filters

The above method works well for simple regressor definitions, where you already have a field on the events structure corresponding to the factor of interest. However, sometimes it is helpful to define more complex conditions on the fly, without creating a new field. make_event_index also allows one to create regressors using arbitrary logical expressions.

Specifying Event Filters

An event filter is an expression that can operate on any field in the events struct (as long as the values of the field are all of the same type), and must produce a logical value for each event. It is specified as a string, and will be evaluated on each element of the event structure to determine which events will be included. inStruct is used to evaluate event filters. Typically, event fields used must have the same type for every element of the events structure, so that the field can be placed in a numeric array or a cell array of strings. Then the filter is evaluated, giving a logical array the same length as events; elements that are true specify events that should be included in the filter. For example, if I want to include only condition A events:

>> events = struct('condition', {'A' 'B' 'B' 'A' 'A' 'A' 'B'});                            
>> inStruct(events, 'strcmp(condition, ''A'')')

    ans =

      1     0     0     1     1     1     0

The expression, 'strcmp(condition, ''A'')', is evaluated for each event. The output of inStruct is a logical array that is true for events that matched the expression.

What inStruct is doing internally is similar to the following:

>> conditions = {events.condition}; % get a cell array of strings with condition labels
>> strcmp(conditions, 'A') % get events for which condition is "A"

    ans =

     1     0     0     1     1     1     0

Event filters are often used to grab subsets of an events structure, using filterStruct. The next section illustrates how to use event filters to create a regressor.

Using Filters to Create a Regressor

Say I want to compare condition A and B events, but I only want to include correct events:

>> events = struct('condition', {'A' 'B' 'B' 'A' 'A' 'A' 'B'}, 'correct', {1 1 0 0 1 1 0});
>> disp_events(events)
	condition correct 
	A         1
	B         1
	B         0
	A         0
	A         1
	A         1
	B         0

>> reg_def = {'strcmp(condition, ''A'') & correct==1', 'strcmp(condition, ''B'') & correct==1'};
>> [index, levels] = make_event_index(events, reg_def)

    index =

       1
       2
     NaN
     NaN
       1
       1
     NaN

levels = 

       'strcmp(condition, 'A') & correct==1'
       'strcmp(condition, 'B') & correct==1'

Here, reg_def is a cell array, where each cell contains an event filter. The events for which reg_def{1} is true correspond to condition 1, and the events for which reg_def{2} is true correspond to condition 2. All the other events are given a NaN, since they belong to none of the conditions. In this case, the levels correspond to the filter strings specified by the user. Some functions include an event_labels input that allows one to specify other labels for the different conditions.

Note that, because in the regressor each event only gets one label, the two event filters must not overlap. If they do, make_event_index will throw an error.

Multi-factor Regressors

The above examples work for most cases where one is working with a single factor. However, often for statistical tests, one is interested in the interactions of multiple factors (for example, when running a two-way ANOVA). For example, I might be interested in a 2X2 design, looking at condition A and B, crossed with whether the trial was correct or not. To create this regressor, I would simply specify the list of fields, and make_event_index will label each combination of the two fields:

>> events = struct('condition', {'A' 'B' 'B' 'A' 'A' 'A' 'B'}, 'correct', {1 1 0 0 1 1 0});
>> disp_events(events)
	condition correct 
	A         1       
	B         1       
	B         0       
	A         0       
	A         1       
	A         1       
	B         0       

>> [index, levels] = make_event_index(events, {'condition' 'correct'})

index =
        2
	4
	3
	1
	2
	2
	3

levels = 
    'A'    [0]
    'A'    [1]
    'B'    [0]
    'B'    [1]

make_event_index automatically finds events corresponding to each conjunction of the two conditions (A-incorrect, A-correct, B-incorrect, B-correct). In the regressor, each of these conditions is given a label from 1-4. The order in which conditions are labeled is arbitrary, though it's generally sensible (alphabetic order for factor 1, then for factor 2). To determine the original label for an event, look at the row of levels corresponding to the number for that event in index. levels{:,1} corresponds to factor 1 (i.e. the first field specified), and levels{:,2} corresponds to factor 2.