Calculating a mean matrix from a large number of matrices
Ältere Kommentare anzeigen
I have been trying to calculate an average matrix from 50 matrices. Using squeeze and cat, i have calculated the mean to two matrices. My question was; how is it possible to get the mean of 50 matrices. I have a code to open the files from a folder and reformat and bin them.
myFolder = uigetdir('C:\Users\c13459232\Documents\MATLAB');
if ~isdir(myFolder)
errorMessage = sprintf('Error: the following folder does not exist: \n%s', myFolder);
uiwait(warndlg(errorMessage));
return;
end
outFolder = fullfile(myFolder, 'output');
mkdir(outFolder);
filePattern = fullfile(myFolder, '*.asc');
Files = dir(filePattern);
for k = 1 : length(Files)
baseFileName = Files(k).name;
FileName = fullfile(myFolder, baseFileName);
fprintf(1, 'Now reading %s\n', FileName);
fid = fopen(FileName);
Cell = textscan( fid, '%d', 'delimiter', ';')
fclose(fid);
Data = cell2mat(Cell);
N = 1024;
skip = 2;
Finish0 = reshape(Data, N, [])';
Finish1 = Finish0(1:skip:end, 1:skip:end);
newFileName = fullfile(outFolder, ['finish_' sprintf('%03d', k) '.txt']);
dlmwrite(newFileName, Finish0, ';');
eval(['finish_' sprintf('%03d', k) ' = Finish1;']);
disp([':: Now writing ' newFileName]);
end
Where could i insert squeeze(cat()) to average all of these matrices. The example I found to get the mean of two matrices is:
c2 = squeeze(mean(cat(3,finish_002,finish_004), 3));
Would you suggest a variation on this code or is there a better way to get an average matrix?
9 Kommentare
Why not read and learn from the answers to your earlier questions, which told you that using awful eval will make your code slow, buggy, difficult to understand, and difficult to debug:
A much simpler, faster, and easier alternative is to use indexing. If you cannot load all of the data at once, then here are some alternatives:
- load each file in turn, use indexing to extract a subset of the loaded matrix, store this in an ND array, once all have been extracted take the mean. Then repeat for the next subset.
- use tall arrays to access data directly from the harddrive, use indexing to extract a subset of the loaded matrix, store this in an ND array, once all have been extracted take the mean. Then repeat for the next subset.
Whatever you do avoid eval: it will not make your life better or easier trying to solve this problem.
Rather than using cat, you can use indexing into a preallocated array. Then calculate the mean. Rinse and repeat.
Aaron Smith
am 13 Mär. 2017
@Aaron Smith: you did not much information in your question, but I assumed that:
- you cannot load all matrices simultaneously.
- you wish to calculate the mean along the third dimension (i.e. as if the matrices were concatenated along the third dimension) giving you one single matrix result with the same size as all of your input matrices.
- all input matrices have the same size.
Are these correct?
Tall arrays were added in 2016b. If you are using an earlier version then you can use indexing, as my earlier comment suggests. Of course this will be slow.
Aaron Smith
am 14 Mär. 2017
If you can load all of the matrices into memory at once then you can load them into one ND array or cell array (using indexing). Then your task would be quite simple to solve (perhaps just one command).
Why make your life more difficult by using eval when simple indexing would make this trivially easy?
You picked a slow, buggy, obfuscated way to write code (and obviously did not read any of the links I have given you advising to avoid this awful way to write code), and you are now finding out how difficult it is to do anything with fifty separate variables in your workspace.
Two options:
- load your data into one array using indexing, then your question can be resolved with perhaps just one command.
- Continue writing pointlessly complicated code using eval, which makes accessing data difficult, and your code slow and hard to debug.
Which would you prefer?
Aaron Smith
am 14 Mär. 2017
Aaron Smith
am 14 Mär. 2017
Bearbeitet: Aaron Smith
am 14 Mär. 2017
Stephen23
am 14 Mär. 2017
@Aaron Smith: using indexing is going to be much easier to work with.
If you want to know why, read that link I gave you.
"You see, when each full matrix is saved as a single cell in a cell array, I'm not sure if this will give me the freedom i need to plot each one individually and to bin each one individually"
It's the exact opposite. Having all the matrices as cells of a cell array gives you the freedom to treat each them individually any way you want. Use a fixed index in your cell array, and the freedom to operate on all them at once. Having individually named matrices you sacrifice the latter and don't gain anything in return.
As a rule, if you're numbering variables you're doing something wrong. These numbered variables are obviously related so they should be stored together in a container of some sort (matrix, cell array, containers.map, whatever).
This would make your question dead easy to solve:
%finish: cell array of matrices
meanofallmatrices = mean(cat(3, finish{:}), 3); %no need for squeeze
And since all the matrices are obviously the same size, you could store them directly as a 3D array instead of cell array (with again no loss of freedom)
Stephen is right, eval is completely the wrong approach. Here be dragons!
Antworten (1)
In the for-loop, you can just use
if k == 1,
M = 1/length(Files)*Data;
else
M = M + 1/length(Files)*Data;
end
Then after the loop, M is the mean of the matrices.
10 Kommentare
Aaron Smith
am 14 Mär. 2017
Thorsten
am 14 Mär. 2017
The i is the running index of the for loop, so here if should be k. I corrected it above. Place the code in the loop after you have determined "Data".
Stephen23
am 14 Mär. 2017
@Aaron Smith: this is a simple method that avoids needing to load all of the matrices at once (or use eval). You should use this method.
Aaron Smith
am 15 Mär. 2017
Bearbeitet: Aaron Smith
am 15 Mär. 2017
finishCell = cell(length(Files), k);
for k = ...
You use the variable k before you create it. If your code is a script, it would have worked before if you had a leftover k from previous runs. If the code is a function, it would never have worked.
In any case, I don't see the purpose of the k in the offending line. You only want one column anyway, so:
finishCell = cell(length(Files), 1); %And I would use numel everywhere instead of length
%or possibly better:
finishCell = cell(size(Files));
And since you're now storing the matrices in a cell array, I wouldn't bother calculating the mean iteratively in the loop. I would calculate it after the loop. This will be more accurate, you'll get accumulation errors with your loop approach. As per my comment to the question, getting the mean after the loop is a one-liner:
M = mean(cat(3, finishCell{:}), 3);
Aaron Smith
am 15 Mär. 2017
Bearbeitet: Aaron Smith
am 15 Mär. 2017
Guillaume
am 15 Mär. 2017
if you have N files, cell(length(Files)) will create a NxN cell array, of which you will only fill the first row. It's either:
finishCell = cell(length(Files), 1);
%or
finishCell = cell(numel(Files), 1);
%or
finishCell = cell(size(Files));
to create a Nx1 cell array.
I can't see anything wrong with the if block (which is not a loop) other than it's inefficient and introduces accumulation error as previously stated. It will produce more or less the correct result. If you really insist on calculating the mean iteratively, I would at least perform the division only once, at the end.
To see what I mean about accumulation error:
>>v = ones(1, 30); %the mean of this is obviously 1
>>meanyourway = sum(v/numel(v)); %each element is divided by the count and then summed
>>meantheproperway = sum(v)/numel(v); %sum each element then divide at the end, or simply use the mean function
>>1 - meantheproperway
ans =
0
>>1 - meanyourway
ans =
1.1102e-16
Aaron Smith
am 15 Mär. 2017
Bearbeitet: Aaron Smith
am 15 Mär. 2017
You've got a closing bracket in the wrong location, the second 3 is an argument to mean, not cat.
mean(cat(3, finishCell{:}), 3);
%bracket goes here ------^
That second 3 tells mean to average across pages instead of the default across rows as you saw.
Aaron Smith
am 15 Mär. 2017
Kategorien
Mehr zu MATLAB Production Server finden Sie in Hilfe-Center und File Exchange
Produkte
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!