How can I vectorize this code? - arrays

First of all I should say that I couldn't find the appropriate title for my question so I would appreciate anyone who will edit the title!
Suppose that I have a 18432x1472 matrix and I want to convert it to a 3072x1472 one ( 18432/6 = 3072 ) in this form:
the mean of elements (1,6),(2,6),...,(6,6) of the old matrix will go to the element (1,1) of the new one
the mean of elements (7,6),(8,6),...,(12,6) of the old matrix will go to the element (2,1) of the new one and so on
Up to now I have written this code:
function Out = MultiLooking( In )
MatrixIn = double(In);
m = size(In,1);
InTranspose = MatrixIn';
A = zeros(m,m/6);
for i = 1:(m/6)
A(6*(i-1)+1,i) = 1;
A(6*(i-1)+2,i) = 1;
A(6*(i-1)+3,i) = 1;
A(6*(i-1)+4,i) = 1;
A(6*(i-1)+5,i) = 1;
A(6*(i-1)+6,i) = 1;
end
X = (InTranspose*A)/6;
Out1 = X';
Out = uint8(Out1);
end
But it is alittle slow and for my polarimetric SAR data, computer gets hanged out for a while when running this code so I need the code to run faster!
Can anyone suggest me a faster code for doing this purpose???

An alternative to Divakar's nice answer: use blockproc (Image Processing Toolbox):
blockproc(MatrixIn, [6 size(MatrixIn,2)], #(x) mean(x.data))

Try this -
%// Assuming MatrixIn is your input matrix
reshape(mean(reshape(MatrixIn,6,[])),size(MatrixIn,1)/6,[])
Alternative Solution using cell arrays (performance improvement over previous code is doubtful though) -
c1 = cellfun(#mean,mat2cell(MatrixIn,6.*ones(1,size(MatrixIn,1)/6),size(MatrixIn,2)),'uni',0)
out = vertcat(c1{:})

Related

Get Matrix 2D from Matrix 3D with a given choice of the third dimension corresponding to the first dimension

I have:
A matrix 3D: A = (m, n, k).
An array of choices for the third dimension corresponding to each index of the first dimension. idn = (m, 1) (wherein the value of any idn is a random integer in [1,k].
I need to capture the 2D matrix B (m,n) wherein the referred third dimension to A is taken from the corresponding choice. For example:
idn(1) = 1;
idn(2) = k;
idn(j) = k-1;
Then:
B(1,:) = A(1,:,idn(1)) = A(1,:,1);
B(2,:) = A(2,:,idn(2)) = A(2,:,k);
B(j,:) = A(j,:,idn(j)) = A(j,:,k-1);
Since idn is not constant, a simple squeeze could not help.
I have also tried the below code, but it does not work either.
B = A(:,:,idn(:));
It is very much appreciated if anyone could give me a solution.
This could be done with sub2ind and permute, but the simplest way I can think of is using linear indexing manually:
A = rand(3, 4, 5); % example data
idn = [5; 1; 2]; % example data
ind = (1:size(A,1)).' + size(A,1)*size(A,2)*(idn(:)-1); % 1st and 3rd dimensions
ind = ind + size(A,1)*(0:size(A,2)-1); % include 2nd dimension using implicit expansion
B = A(ind); % index into A to get result

Index Subset of Array in For Loop in MATLAB

I have a question regarding indexing and loops in MATLAB. I have a vector of length n (named data in the code below). I want to examine this vector 4 elements at a time inside of a for loop. How can I do this? My attempt included below does not work because it will exceed the array dimensions at the end of the loop.
for k = 1:length(data)
index = k:k+3;
cur_data = data(index);
pre_q_data1 = cur_data(1);
pre_q_data2 = cur_data(2);
% Interweaving the data
q = [pre_q_data1; pre_q_data2];
qdata = q(:)';
pre_i_data1 = cur_data(3);
pre_i_data2 = cur_data(4);
i = [pre_i_data1; pre_i_data2];
idata = i(:)';
end
You shouldn't have k go all the way to length(data) if you're planning on indexing up to k+3.
I've also taken the liberty of greatly simplifying your code, but feel free to ignore that!
for k = 1:length(data)-3
% maximum k = length(data)-3, so maximum index = length(data)-3+3=length(data)
index = k:k+3;
cur_data = data(k:k+3);
% Interweaving the data
q = cur_data(1:2); % transpose at end of line here if need be
i = cur_data(3:4); % could just use data(k+2:k+3) and not use cur_data
end

Sort array elements by the frequency of its elements

Is it possible in matlab/octave to use the sort function to sort an array based on the relative frequency of their elements?
For example the array
m= [4,4,4,10,10,10,4,4,5]
should result in this array:
[5,10,10,10,4,4,4,4,4]
5 is the less frequent element and is on the top while 4 is the most frequent and it's on bottom.
Should one use the indices provided by histcount?
The following code first calculates how often each element occurs and then uses runLengthDecode to expand the unique elements.
m = [4,4,4,10,10,10,4,4,5];
u_m = unique(m);
elem_count = histc(m,u_m);
[elem_count, idx] = sort(elem_count);
m_sorted = runLengthDecode(elem_count, u_m(idx));
The definition of runLengthDecode is copied from this answer:
For MATLAB R2015a+:
function V = runLengthDecode(runLengths, values)
if nargin<2
values = 1:numel(runLengths);
end
V = repelem(values, runLengths);
end
For versions before R2015a:
function V = runLengthDecode(runLengths, values)
%// Actual computation using column vectors
V = cumsum(accumarray(cumsum([1; runLengths(:)]), 1));
V = V(1:end-1);
%// In case of second argument
if nargin>1
V = reshape(values(V),[],1);
end
%// If original was a row vector, transpose
if size(runLengths,2)>1
V = V.'; %'
end
end
One way would be to use accumarray to find the count of each number (I suspect you can use histcounts(m,max(m))) but then you have to clear all the 0s).
m = [4,4,4,10,10,10,4,4,5];
[~,~,subs]=unique(m);
freq = accumarray(subs,subs,[],#numel);
[~,i2] = sort(freq(subs),'descend');
m(i2)
By combinging my approach with that of m.s. you can get a simpler solution:
m = [4,4,4,10,10,10,4,4,5];
[U,~,i1]=unique(m);
freq= histc(m,U);
[~,i2] = sort(freq(i1),'descend');
m(i2)
You could count the number of repetitions with bsxfun, sort that, and apply that sorting to m:
[~, ind] = sort(sum(bsxfun(#eq,m,m.')));
result = m(ind);

How to concatenate arrays from cell arrays in Matlab

I am new to Matlab and was trying to concatenate array from cell arrays. I have done it as shown below.
S = load('input_file.mat');
c = struct2cell(S);
v = cell2mat(c(1,1));
temp = v(1:500,1:600);
v = cell2mat(c(3,1));
temp1 = v(1:500,1:600);
v = cell2mat(c(2,1));
temp2 = v(1:500,1:600);
v = cell2mat(c(4,1));
temp3 = v(1:500,1:600);
array1 = vertcat(temp,temp1);
array2 = vertcat(temp2,temp3);
But i guess there should be a better way or a direct function call which can get me the same result as i am getting from the code shown?
This is a very specific task, not very general, unless I'm missing the pattern. Starting after struct2cell:
C3 = cellfun(#(x)x(1:500,1:600),c,'uni',0);
array1 = vertcat(C3{[1 3]});
array2 = vertcat(C3{[2 4]});
Although, you could probably get rid of your initial structfun if you replace cellfun above with structfun, taking s as an input. It simply operates on each field.

In MATLAB, For Looping with String Array

A similar question has been asked, but still I'm looking for a solution.
In MATLAB, I have an array of states s:
s = {'Indiana', 'Texas', 'Alabama'}
Time is a column vector: [120 30 20 40 50]'
Tornadoes is a column vector: [5 5 3 5 5]'
And I need to for loop through this array s for the following code below while placing each string in s in the first line.
index = strcmpi(States,s)
Time = Time(index)
Tornadoes = Tornadoes(index)
h = scatter(Time,Tornadoes)
So how can I write the code to push each state in s to generate a plot for each plot.
Could it be as simple as this?
for ii = 1:numel(s)
index = strcmpi(States, s{ii})
Time = Time(index)
Tornadoes = Tornadoes(index)
figure % make sure you start a new figure each time...
h = scatter(Time,Tornadoes)
title(['Tornadoes in ' s{ii}])
end
If you are wanting to loop through each entry in s, you could do
j = length(s)
for i = 1:j
x = Time(i)
y = Tornadoes(i)
h = scatter(x, y)
end

Resources