MATLAB: How to calculate (on) Submatrices without a loop - matlab

I want to split a matrix columnwise into 3 segments and do a calculation on it (mean()). Is there a way to get this without a for-loop, as I did in this provided sample?
M = [2 4 9; 50 50 200; 30 0 0];
M = [M 10*M]
N = length(M);
seg = 3 % split in lets say 3 parts
segLen = round(N/seg)
segBeg = (((1:seg)-1) * segLen)+1 % start indices
segEnd = segBeg + segLen -1 % end indices
for i = 1: length(segBeg)
mean(M(:,segBeg(i):segEnd(i)),2)
end
Thank you!

Think outside the box: use the 3rd dimension:
r=reshape(M,size(M,1),segLen,[])
squeeze(mean(r,2))
The first line produces a 3d array with the first matrix at r(:,:,1), the second at r(:,:,2), ... (use M(:,1:seg*segLen) instread of M if the number of columns is not divisible by segLen).
mean(r,2) produces a nrows-by-1-by-seg array, squeeze makes a nrows-by-seg matrix out of it again.

You can use arrayfun together with cell2mat
result = cell2mat(arrayfun(#(x,y) mean(M(:,x:y),2), segBeg, segEnd,...
'UniformOutput', false))
This results in
result =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
where each column represents the mean across one submatrix.
Another solution using blockproc (like suggested by #DennisJaheruddin in the comments) could look like this
myFun = #(x) mean(x.data,2);
result2 = blockproc(M, [N, segLen], myFun)
This also results in
result2 =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
Note that blockproc can take advantage of parallel processing if the flag 'UseParallel' is set to true, i.e., result2 = blockproc(M, [N, segLen], myFun, 'UseParallel', true)

You can do for your example case
mean1 = mean(M(:,1:segLen))
mean2 = mean(M(:,segLen+1:N-segLen-1))
mean3 = mean(M(:,N-segLen:end))

Related

Which one should I use for dimension reduction with PCA in MATLAB, pcacov or eigs?

I'm trying to reduce my training set dimension from 1296*70000 to 128*70000.
I wrote Below code:
A=DicH;
[M N]=size(A);
mu=mean(A,2);%mean of columns
Phi=zeros(M,N);
C=zeros(M,M);
for j=1:N
Phi(:,j)=A(:,j)-mu;
c=Phi(:,j)*(Phi(:,j))';
C=C+c;
end
C=C/N;%Covariance Dictionary
[V,landa] = eigs(C,128);%Eigen Vectors & Eigen Values
E=V'*Phi;%Reduced Dic
%*******************Using Pcacov*****************
%S=zeros(M,1);
%[U,landa] = pcacov(C);%Eigen Vectors & Eigen Values
% for k=1:128;
% S=V(:,k)+S;
% U(:,k)=S;
% end
%E=U'*Phi;%Reduced Dic
I get two different answers! Which one should I use "eigs" or "pcacov"??
You should take advantage of the built-in functions in Matlab, and use the pca function directly, or even the cov function if you want to compare eigs to pcaconv.
Now to answer your question, both return the same eigenvectors but not in the same order. See the following example:
>> load hald
>> covx = cov(ingredients);
>> [COEFF,latent] = pcacov(covx)
COEFF =
-0.0678 -0.6460 0.5673 0.5062
-0.6785 -0.0200 -0.5440 0.4933
0.0290 0.7553 0.4036 0.5156
0.7309 -0.1085 -0.4684 0.4844
latent =
517.7969
67.4964
12.4054
0.2372
>> [V, D] = eigs(covx)
V =
0.5062 0.5673 0.6460 -0.0678
0.4933 -0.5440 0.0200 -0.6785
0.5156 0.4036 -0.7553 0.0290
0.4844 -0.4684 0.1085 0.7309
D =
0.2372 0 0 0
0 12.4054 0 0
0 0 67.4964 0
0 0 0 517.7969
>>
In your code, you overwrite the result of pcavconv in the commented-out section with a transformation of the result of eigs so it is not clear what your are comparing at this point. When using pcacov, you just need to extract the 128 first columns of U.

matlab store multiple outputs of function from loop in matrix

i am trying to save the output of the following function (it gives two outputs for every iteration of input 1, the rest remains the same).
The function creates a stress testing for an interbank market, testing for the effects (output is capital_losses and defaulted_banks) of default of every bank in the sample, i.e. input1 must go from 1:(length(input2), 4 in the code provided here, 300+ in the final code, so i need a loop
here a sample of one iteration with bank 3 defaulting
input1 = 3; % default_bank
input2=[100000;200000;300000;400000]; % capital levels in the function
input3 = ...
[70000, 15000, 24000, 52453;
23420, 24252, 10000, 35354;
98763, 45666, 96555, 05000;
09800, 54444, 04336, 67520]; % interbank loans in the function
input4 = 1;
input5 = .35;
input6 = 1;
% function calls on above inputs
[capital_losses defaulted_banks] = interbank_model( ...
input1, input2, input3, input4, input5, input6)
this is the standard output for one iteration with default_bank=3, but I need this for 300+, so a loop would be helpful...
capital_losses3 =
1.0e+05 *
0.5857
0.2598
3.0000
0.0609
defaulted_banks3 =
0
0
1
0
I would like to get the output for every defaulted bank, i.e. default_bank=1:4 to be displayed by the for loop as follows:
capital_losses_all =
1.0e+05 *
1.0000 0.2320 0.5857 0.5857
0.2867 2.0000 0.2598 0.2598
1.0716 0.4917 3.0000 3.0000
0.2816 0.6682 0.0609 0.0609
defaulted_banks_all =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
This was manually generated, but how do i store the values in matrices?
Thanks for your help. (I had a similar question before but the editing and commenting got very confusing so here's my improved cry for help... )
Chris
Very general answer (adapt for your need):
valuesThatChange = [1 3 5 4 2]; % different for each iteration in the loop
% values that don't change:
a=1;
b=2;
c=3;
N = numel(valuesThatChange);
% create storage for results:
results = zeros(4, N);
% loop N times
for ii=1:N
results(:,ii) = functionCall(valuesThatChange(ii), a, b, c); % returns a 4 element result
end
Now you have the result from your function for each loop in a 4xN matrix.

mean time signals grouped by label

given a number of signals in a matrix, say m [T x N]
and a grouping variable g [ 1 x N ] with a number of labels L < N
is there an efficient, in-place way to compute mean time signals for every label?
A for loop
ml = zeros (T,L)
for i = 1:T
for j = 1:L
ml(i,j) = mean ( m(i,find(g==j)) )
end
end
is a straightforward way to do it, but could there be a faster/cleaner way, possibly using vectorised code? Just to (a) get rid of for-loops and (b) assign m = labelled_means(m, ...) in one go. I read about statarray, but that looks much less efficient even than this for loop.
Well you could get rid of your outer loop really easily:
for j = 1:L
ml(:,j) = mean(m(:,find(g==j)), 2)
end
You can use arrayfun. It will be cleaner, don't know if faster:
result = arrayfun(#(n) mean(A(:,find(g==n)),2),1:2,'UniformOutput',false);
result = reshape([result{:}],[],L)
For example, with data
A = [1 2 3 4;
5 6 7 8;
9 10 11 12];
L = 2;
g = [1 1 2 2];
this gives
result =
1.5000 3.5000
5.5000 7.5000
9.5000 11.5000
You can use accumarray
[X,Y] = ndgrid(1:size(A,1), g);
accumarray([X(:) Y(:)], A(:), [], #mean);

MATLAB - re-arrange matrix by vertically concatenating submatrices

I am having trouble with the following task:
Suppose a 3x6 matrix:
A =
0.2787 0.2948 0.4635 0.8388 0.0627 0.0435
0.6917 0.1185 0.3660 0.1867 0.2383 0.7577
0.6179 0.7425 0.0448 0.4009 0.9377 0.4821
What I would like to do is to divide the matrix into blocks, like this:
A =
0.2787 0.2948 | 0.4635 0.8388 | 0.0627 0.0435
0.6917 0.1185 | 0.3660 0.1867 | 0.2383 0.7577
0.6179 0.7425 | 0.0448 0.4009 | 0.9377 0.4821
and vertically concatenate these blocks to get the final result:
0.2787 0.2948
0.6917 0.1185
0.6179 0.7425
0.4635 0.8388
0.3660 0.1867
0.0448 0.4009
0.0627 0.0435
0.2383 0.7577
0.9377 0.4821
I think if I can get help with this, then I can perhaps
do it for arbitrary matrices A. I can solve the above
problem using for-loops, but I am looking for a vectorised solution.
Thanks in advance!
N.
Consider the following:
A = rand(3,6);
blkSz = 2;
C = mat2cell(A, size(A,1), blkSz*ones(1,size(A,2)/blkSz));
C = cat(1,C{:})
This assumes that size(A,2) is evenly divisible by blkSz
This works where your matrix is A and what you want is D
C = mat2cell(A,[3],[2 2 2])
D = cat(1,C{:})
It's possible to do it without cell2mat, (only with reshapes and permute) and thus a lot faster!
You need to use the "3rd dimension". It's similar to what is described in
split long 2D matrix into the third dimension.
Here is the solution for the above matrix:
A1 = reshape(A, 3, 2, []); % 3rd dimension is numel(A)/2/3
A2 = permute(A1, [2 1 3]); % transpose 1st and 2nd dimension
Ans= reshape(A2, 2, [])' ; % note the transpose
For a matrix of this size, the difference in running time is negligible. However, for a large matrix, the difference is more than an order of magnitude:
A=rand(3, 2*10000);
%% good method
tic
A1 = reshape(A, 3, 2, []); %3rd dimension is numel(A)/2/3
A2 = permute(A1, [2 1 3]);
A3 = reshape(A2, 2, [])' ; %note the transpose'
toc
%% mat2cell method
tic
blkSz = 2;
C = mat2cell(A, size(A,1), blkSz*ones(1,size(A,2)/blkSz));
B3 = cat(1,C{:});
toc
%% make sure the answer is the same:
assert(max(A3(:)-B3(:))==0)
output:
>> Elapsed time is 0.001202 seconds.
>> Elapsed time is 0.043115 seconds.
How about this:
width = 2;
m = length(A(:))/width;
fn = #(i) reshape(A(:, i:width:end), m, 1);
B = cell2mat(arrayfun(fn, 1:width, 'UniformOutput', false));
Just specify how many columns you want at a time in the width variable.
By concatenating vertically, matrix width divisible by 3 assumed:
B = [ A(:,1:(size(A,2)/3)); A(:,size(A,2)/3+1:size(A,2)/3*2); A(:,size(A,2)/3*2+1:end) ];

Saving different 'graycoprops' properties values on a matrix [MATLAB]

I've a picture. I create the co-occurrence matrix (graycomatrix) to extract different properties (contrast, correlation) etc on it (graycoprops)
x = []
for a lot of pictures, do the same:
imgB = imread('currentLoopImage.jpg')
contrast = graycoprops(graycomatrix(rgb2gray(imgB)), 'Contrast')
correlation = graycoprops(graycomatrix(rgb2gray(imgB)), 'Correlation')
energy = graycoprops(graycomatrix(rgb2gray(imgB)), 'Energy')
homogeneity = graycoprops(graycomatrix(rgb2gray(imgB)), 'Homogeneity')
x = [x;contrast;correlation;energy;homogeneity]
The thing is that I need to save all the values on that matrix X, but I get the following error:
CAT arguments are not consistent in structure field names.
As this is the output I get from each type:
homogeneity =
Homogeneity: 0.8587
There are different types, so I can't save them on the X matrix.
The output matrix X, should save only the numbers, and ignore that "Homogenity"
Can someone tell me who can I do this?
From the graycoprops() example:
>> GLCM = [0 1 2 3;1 1 2 3;1 0 2 0;0 0 0 3];
>> stats = graycoprops(GLCM)
stats =
Contrast: 2.8947
Correlation: 0.0783
Energy: 0.1191
Homogeneity: 0.5658
Then just do:
>> x = struct2array(stats)
ans =
2.8947 0.0783 0.1191 0.5658
Also note that you can include all your images in an m x n x p matrix and process them all at once, instead of using the for loop. For example:
>> GLCM(:,:,2) = GLCM;
>> cell2mat(struct2cell(stats))
ans =
2.8947 2.8947
0.0783 0.0783
0.1191 0.1191
0.5658 0.5658