forked from mikexcohen/AnalyzingNeuralTimeSeries
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter04a.m
392 lines (294 loc) · 12.9 KB
/
chapter04a.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
%% Analyzing Neural Time Series Data
% Matlab code for Chapter 4 script A
% Mike X Cohen
%
% This code accompanies the book, titled "Analyzing Neural Time Series Data"
% (MIT Press). Using the code without following the book may lead to confusion,
% incorrect data analyses, and misinterpretations of results.
% Mike X Cohen assumes no responsibility for inappropriate or incorrect use of this code.
%% variables, part I
% Let's start with variables. A variable is a place-holder for
% information. To create a variable, you simply assign it information.
% For example,
mike = 10;
bob = 20;
% If you type these into the command window (or highlight them here and hit
% F9, or highlight them, right-click, and choose "Evaluate Selection"), you
% will create the variables.
% Because the variables refer to numbers, you can add them, multiple them,
% etc:
mike + bob; % Note: You can also put comments after code
(mike+bob)/(mike-bob)
% Notice that when the line ends with a semicolon, the output is suppressed,
% and when there is no semicolon, it outputs the results in the command window.
% variables can also be strings:
mike = 'mike';
% now we've re-assigned mike from a number to a character array. Type
% 'whos' into the matlab command.
whos
% You can also assign matrices to variables:
a_simple_matrix=[ 3 4 5; 1 2 3; 9 8 7 ];
% type this into the command to see how the semicolon was used to delineate
% separate lines.
% Square brackets concatinate:
mikes_full_name = [ mike ' cohen' ];
mikes_two_fav_numbers = [ 7 23 ];
% type whos in the command to see the properties of our variables. Note the
% difference between double and char (character), and note the sizes of different variables.
%% Variables, part II
% Variables can be more sophisticated. Variables can be cells, which
% are like blocks that may contain different kinds of information.
var1{1} = [ 1 2 3 4 5 6 7 ];
var1{2} = 'hello world';
var1{3} = [ 1 3 6 7 4 3 5 6 7 87 76 43 4 5 6 767 ];
var1
var1{2}
% The most flexible type of variable is a structure. Structures contain fields that
% are used for different kinds of data. For example:
ANTS.name = 'mike'; % ANTS = Analyzing Neural Time Series
ANTS.position = 'author';
ANTS.favorite_toothpaste_flavor = 'cinnamon';
ANTS.number_of_watches = 18;
ANTS.favorite_color = [ .8 .1 .8 ]; % RGB values
% You can also have an array of structures
ANTS(2).name = 'Your name here';
ANTS(2).position = 'reader';
ANTS(2).favorite_toothpaste_flavor = 'bratworst'; % gross, but true
ANTS(2).number_of_watches = 1;
ANTS(2).favorite_color = [ 1 1 1 ];
% now you can get information about all fields from one specific element of
% the structure:
ANTS(1)
% or information about one field within one member:
ANTS(1).number_of_watches
% or information about one field from all members:
ANTS.favorite_toothpaste_flavor
% note that this last result came out as two separate answers. If you want
% to combine them into a single output (e.g., a cell array), use curly
% brackets:
{ANTS.favorite_toothpaste_flavor}
%% functions
% functions are modular pieces of code stored in a separate file. Most
% functions can be opened and you can see/modify the code. Some functions
% are compiled and not viewable or editable.
% Functions may take inputs:
randperm(4) % randperm is a function that randomly permutes integers. 4 is the input.
% or a vector:
mean([1 3 2 4 3 5 4 6])
% to see the guts of this function, highlight "mean" and right-click,
% Open File (or type "edit mean" in the command, or highlight and Ctrl-D)
% IMPORTANT! Do not modify matlab functions unless you really know what
% you're doing! A better idea is to copy the function into a different file
% and use a different name.
% Most functions also give outputs:
permuted_integers = randperm(4); % now the output of the function is stored in a new variable
whos permuted_in* % Note that you can also use the * character for whos
% some functions can have multiple inputs:
random_number_matrix = rand(4,6); % Here, we asked for a 4 x 6 matrix of random numbers
% some functions have multiple outputs:
[max_value max_value_index] = max([1 2 3 9 8 7 6]);
% This also shows matrix indexing, which we'll get to soon.
% IMPORTANT: You can use the output of one function as the input to another
% function. This is a powerful way to make your matlab programming fast and
% efficient. On the other hand, if you embed functions to an extreme you
% might unreadable code.
[max_value max_value_index] = max( randperm( round( rand(1)*10 ) ) );
% Note that when you put the cursor on a parenthesis, it underlines the
% corresponding other parenthesis.
% type 'help <function_name>' in the matlab command to
% read about a function.
help max % also try: doc max
%% indexing
% Indexing is a powerful tool in matlab to access particular parts of a
% variable. Indexing is very simple: Imagine you have 100 twinkies arranged
% in a 10 x 10 square:
twinkies = rand(10,10)
% If you wanted to eat the twinkie in the 4th row, 8th column, you write:
the_twinkie_i_will_eat = twinkies(4,8);
%% The colon operator
% By default, the colon operator increments in integer units from the
% first to the second number. Observe:
1:10
% You can also increment by a certain amount:
1:2:10
count2ten=1:.23956:10;
% the colon operator is also useful when indexing. Let's say you want to
% eat several twinkies:
twinkies_i_will_eat = twinkies(4:8,2:7);
% Question: How big should the variable twinkies_i_will_eat be?
whos twin* % answer
% To count backwards, you must specify that you want to skip with a negative number:
rookie_mistake = 10:1;
how_the_pros_do_it = 10:-1:1;
%% determining the sizes of variables
% You can see variable sizes using whos, but there are also ways
% to output matrix sizes into variables, which will be useful in many situations.
length(random_number_matrix)
% important! "length" returns the length of the longest dimension, regardless of how many dimensions there are!
% you can use size to find the sizes of all dimensions:
size(twinkies)
size(twinkies,1) % or only specific dimensions...
numel(twinkies) % numel stands for 'total number of elements'
% these functions also produce outputs:
twinkie_array_size = size(twinkies);
prod(twinkie_array_size) % prod returns the product of input numbers
% of course, these functions work on non-numeric variables, e.g.,
length(ANTS)
%% for-loops
% A for-loop is a way to iterate repeatedly:
for counting_variable = 1:10
disp(counting_variable); % disp stands for display, which prints information in the command window
end
% another example:
for counting_variable = 1:2:10
disp([ 'The ' num2str(counting_variable) 'th iteration value times 2 divided by 3 and added to 7 is ' num2str(counting_variable*2/3+7) '.' ])
end
% You can embed loops within loops
for i = 1:5
for j = 3:7
product_matrix(i,j) = i*j; % Matlab produces a warning here because product_matrix is not initialized. See text in Chapter 4.
end
end
% Two important things to note here: (1) You can use the same numbers as
% indices AND as variables; (2) Unspecified elements in a matrix are
% automatically created and set to zero.
number_rows = 5; % having many spaces is allowed and facilitates code aesthetics
number_columns = 7;
% initialize matrix with zeros
product_matrix = zeros(number_rows,number_columns);
for i=1:number_rows
for j=1:number_columns
product_matrix(i,j)=i*j;
end % end j-loop
end % end i-loop
% note the comments following end-statements. When you have multiple long
% loops, this kind of commenting will be helpful. Also note that when you
% click on one of the "for" or "end" statements, its pair will be underlined.
%% if-statements
% Exactly how it sounds
if 4>5
disp('Something has gone awry in the universe')
end
if 4>5
disp('Something is still very wrong')
else
disp('Whew! Everything''s normal.') % note the two single-parenthesis marks inside the string
end
% the 'switch/case' statement is similar to 'if/else'
for counting_variable = 1:2:10
switch counting_variable
case 1 % compares 'counting_variable' to '1'
disp([ 'The ' num2str(counting_variable) 'st iteration value times 2 divided by 3 and added to 7 is ' num2str(counting_variable*2/3+7) '.' ])
case 2
disp([ 'The ' num2str(counting_variable) 'nd iteration value times 2 divided by 3 and added to 7 is ' num2str(counting_variable*2/3+7) '.' ])
case 3
disp([ 'The ' num2str(counting_variable) 'rd iteration value times 2 divided by 3 and added to 7 is ' num2str(counting_variable*2/3+7) '.' ])
otherwise
disp([ 'The ' num2str(counting_variable) 'th iteration value times 2 divided by 3 and added to 7 is ' num2str(counting_variable*2/3+7) '.' ])
end % end switch
end
%% boolean (true/false)
% sometimes, it's useful to know if a statement is TRUE or FALSE.
% You can use a double-equals sign:
5==5
% The answer is '1', which in this case means 'true'. The oppose of true (1) is false (0):
5==4
% You can assign these answers to variables:
fourIsFive = 4==5; % see below for disambiguating = and ==
whos fourIsFive
% note that 'fourIsFive' is type "logical", or boolean.
% Other related useful functions:
matrix0 = false(10,3);
matrix1 = true(4,12);
% you can use the tilde "~" to negate a statement:
~(1==1) % false because the negation of 1==1 is false
~(4>3) % also false because the negation of 4>3 is false
~(4<3) % true because it is false (~) that 4 is greater than 3. Tricky!
% things can sometimes get tricky:
truthtest = 1 == 2;
% Remember:
% One equals sign is a statement ("you have this value").
% Two equals signs means you are asking a question ("are these the same?").
% Mnemonic: "Say with one (=), ask with two (==), then you know just who is who!"
% (I didn't say it was a good mnemonic...)
%% repmat
% repmat is short for "replicate matrix." It is a handy function that
% is often used in analyses. The problem that repmat solves is matrix
% operations with other matrices. First, consider that adding a scalar
% (a single number) to a matrix is no problem.
mat = rand(4);
mat+23
% Now imagine that mat is EEG data with 4 electrodes and 10 time points:
mat = rand(4,10);
% now you want to subtract the mean over time:
meanOverTime = mean(mat,2); % second input to mean function is the dimension along which to compute the mean
mat = mat - meanOverTime;
% the previous line crashes because the matrices are of unequal size
whos mat meanOverTime
% repmat will help:
meanOverTimeRepmat = repmat(meanOverTime,1,size(mat,2));
whos mat meanOverTime*
% repmat takes 3 inputs: the matrix you want to replicate, the number of
% times to replicate it over rows, and the number of times to replicate it
% over columns (you can also input more dimensions). We want to replicate
% this matrix only over time points (the size of the second dimension of
% mat). Now the subtraction works:
matmean = mat - meanOverTimeRepmat;
% Other examples of repmat:
mat = [1 2 3; 10 20 30];
repmat(mat,1,1)
repmat(mat,1,2)
repmat(mat,2,1)
%% bsxfun
% bsxfun is a useful function for fast and easy array and matrix manipulations.
% It was introduced to Matlab fairly recently, so older versions of Matlab
% do not have this utility.
% for example, the following function will add 4 to a random matrix:
bsxfun(@plus,randn(10),4)
% this might not seem any better than "randn(10)+4" and for this small
% case, it isn't. bsxfun is more useful because it performs
% singleton-expansion, which means you may be able to avoid using repmat.
% For example, imagine a dataset with 100 channels and 100,000 time points:
a = rand(100,100000);
% To subtract the mean of the entire time series:
am = a - repmat(mean(a,2),1,size(a,2));
% Notice that the repmat is necessary:
am = a - mean(a,2);
% The previous line crashes because the sizes of a and its mean are not the
% same. However, bsxfun expands this automatically
am = bsxfun(@minus,a,mean(a,2));
% let's do a timing test...
tic
for i=1:100
am = a - repmat(mean(a,2),1,size(a,2));
end
t(1)=toc;
tic
for i=1:100
am = bsxfun(@minus,a,mean(a,2));
end
t(2)=toc;
figure
bar(t)
set(gca,'xtick',1:2,'xticklabel',{'repmat';'bsxfun'},'xlim',[.5 2.5])
title([ 'bsxfun took ' num2str(100*t(2)/t(1)) '% of the computation time.' ])
% you'll learn more about the above lines in part B of this code
% Thus, bsxfun is a bit faster but also more convenient to use, and more elegant.
% There are other similar functions to bsxfun, including arrayfun and cellfun.
% In addition to speed, the *fun functions allow you to avoid using loops.
% For example, let's say you want to know the length of items in a cell array.
% create cell array whose elements have variable lengths
c = cell(1,40);
for i=1:length(c)
c{i} = randn(1,round(rand*100));
end
% now you want to know how many elements are in each cell.
% Normally you need a loop:
cell_lengths = zeros(size(c));
for i=1:length(c)
cell_lengths(i) = numel(c{i});
end
% But cellfun is more efficient:
cell_lengths = cellfun(@length,c);
%% end
% continue on the part b of this code...