I am looking for a way to delete empty matrices within a multidimensional array in MATLAB.
For example, I have a 4-D array such as:
N = 5;
Arr = zeros(2,2,4,N);
Lets assume only N = 2 and N = 4 have values (i.e the four 2x2 matrices in N = 1, 3 and 5 are zeros), how can I create another multidimensional array ArrFin(2,2,4,2) such that
ArrFin(2,2,4,1) = Arr(2,2,4,2);
ArrFin(2,2,4,2) = Arr(2,2,4,4);
I have tried to make the question quite general so that others can benefit from it as well but if I am not making much sense let me know.
Thanks in advance :)
Figured out quite a neat way to do it:
ArrFin = Arr(:,:,:,any(any(any(Arr,3))));
This picks out the non zero matrices and saves them into ArrFin.
Code
%%// Create data
Arr= rand(2,2,4,5);
Arr(:,:,:,[1 3 5]) = 0;
%%// Get new reduced matrix and check for its size
ArrFin = Arr(:,:,:,find(sum(reshape(sum(Arr,3),size(Arr,3),size(Arr,4)),1)));
size_check = size(ArrFin)
Output
size_check =
2 2 4 2
Related
Good evening! I have a 3D vector. It has the first dimension 1. For clarity, I set it exactly the same as used in my program. "с" is like a number of experiments, in this case there are three, so I calculate the correlation function three times and then add them up.
In fact, the number of experiments is 100. I have to calculate 100 correlation functions and add them.
Tell me how you can do it automatically. And if possible, then no cycles. Thank you.
And yes, in the beginning I set the 3D vector using a loop. Is it possible to set it without a loop as well? This is certainly not my main question, but I would also like to know the answer to it.
d = [1 2 3];
c = [4 2 6];
for i = 1: length(c)
D(1,:,i) = d.*c(i);
end
D
X1 = xcorr(D(:,:,1));
X2 = xcorr(D(:,:,2));
X3 = xcorr(D(:,:,3));
X = X1+X2+X3;
With the help of a loop, my solution looks like this:
d = [1 2 3];
c = [4 2 6];
for i = 1: length(c)
D(1,:,i) = d.*c(i);
x(:,:,i) = xcorr(D(:,:,i));
end
X = sum(x,3)
It seems to be correct. Is it possible to do this without a cycle?
You can easily set your first array D without any loop, even though I don't know why you want to keep the first singleton dimension...
D(1, :, :) = d'.*c;
As for the sum of the autocorrelations, I'm not sure you can do it without a loop. The only thing that you can perhaps do is to not use an array to store the correlation for each index (if memory consumption is a problem for you) and just update the sum:
X = zeros(1, 2*length(d)-1); % initialize the sum array
for i = 1:length(c)
X = X + xcorr(D(:, :, i)); % update the sum
end
I'm working in Matlab.
I have a two-dimensional matrix with two columns. Lets consider elements in the first column as labels. Labels may be repeated.
How to multiply all elements in the second column for every label?
Example:
matrix = [1,3,3,1,5; 2,3,7,8,3]'
I need to get:
a = [1,3,5; 16,21,3]'
Can you help me with doing it without for-while cycles?
I would use accumarray. The preprocessing with unique assigns integer indices 1:n to the values in the first row, which allow accumarray to work without creating unnecessary bins for 2 and 4. It also enables the support for negative numbers and floats.
[ulable,~,uindex]=unique(matrix(:,1))
r=accumarray(uindex,matrix(:,2),[],#prod)
r=[ulable,r]
/You can also use splitapply:
[ulable,~,uindex]=unique(matrix(:,1))
r=splitapply(#prod,matrix(:,2),uindex)
r=[ulable,r]
You can do it without loops using accumarray and the prod function:
clear
clc
matrix = [1,3,3,1,5; 2,3,7,8,3]';
A = unique(matrix,'rows');
group = A(:,1);
data = A(:,2);
indices = [group ones(size(group))];
prods = accumarray(indices, data,[],#prod); %// As mentionned by #Daniel. My previous answer had a function handle but there is no need for that here since prod is already defined in Matlab.
a = nonzeros(prods)
Out = [unique(group) a]
Out =
1 16
3 21
5 3
Check Lauren blog's post here, accumarray is quite interesting and powerful!
Try something like this, I'm sure it can be improved...
unValues = unique(matrix(:,1));
bb = ones(size(unValues));
for ii = 1:length(unValues)
bb(ii) = bb(ii)*prod(matrix(matrix(:, 1) == unValues(ii), 2));
end
a = [unValues bb];
I'm learning matlab. I'd like to create a smaller array from a larger one. I know how to do this with simple columns or rows, but I get lost in the nomenclature for m x n arrays / matrices.
Original matrix = 10 x 9
mat_original=ones(10,9) in fact, rather than use all ones.. this may make more sense.. lets use mat_original = magic(10)
How do I create a component matrix say with rows 5 to 8 (all columns)?
mat_rows5to8 = mat_original[5 thru 8; :]
How do I create a component matrix, say with columns 2 to 5, (all rows?)
mat_cols2to5 = mat_original[: ; 2 thru 5 ]
and finally how would I create a sub-component array... say rows 4 thru 7, and columns 5 thru 9 ?
mat_small = mat_original[ 4 thru 7; 5 thru 9 ]
How do you remember this stuff?
No need to remember things when you have Google: Matrix Indexing in MATLAB.
Answers to your questions:
mat_rows5to10 = mat_original(5:8,:)
mat_cols2to5 = mat_original(:,2:5)
mat_small = mat_original(4:7,5:9)
In other words:
output = input(<row_first>:<row_last>,<col_first>:<col_last>)
Leave any of the parameters out to include all.
I am trying to split an array of unknown length in Matlab into two arrays of random lengths. I think I was able to do it but it is a little clunky. I also would like to be able to save all of the possible combinations afterwards (a matrix for subarray 1 and a matrix for subarray 2), but I am having trouble doing this because it cant be saved in a matrix because they all have different lengths. Should I use cells instead?
Here is my code for splitting the arrays
Array = [1 2 4 5 6 2 3]
x = randi(length(Array))
newArray1 = Array(1:x)
newArray2 = Array(x+1:end)
Would like to run the above code a few times and save each combination of array1 and array 2 in its own matrix or cell like below
all_of_Array1 = [all_ofArray1:newArray1]
all_of_Array2 = [all_ofArray2:newArray2]
Thanks!
So you just want a loop?
%//Pre-allocation
n = 10;
newArray1{n} = [];
newArray2{n} = [];
for k = 1:n
%//Generate Array here if it changes at each iteration
Array = [1 2 4 5 6 2 3]
x = randi(length(Array)-1);
newArray1{k} = Array(1:x)
newArray2{k} = Array(x+1:end)
%//Or replace the 2 lines above with newArray{k,1}=... and newArray{k,2}=...
end
I have a 3 dimensional (or higher) array that I want to aggregate by another vector. The specific application is to take daily observations of spatial data and average them to get monthly values. So, I have an array with dimensions <Lat, Lon, Day> and I want to create an array with dimensions <Lat, Lon, Month>.
Here is a mock example of what I want. Currently, I can get the correct output using a loop, but in practice, my data is very large, so I was hoping for a more efficient solution than the second loop:
% Make the mock data
A = [1 2 3; 4 5 6];
X = zeros(2, 3, 9);
for j = 1:9
X(:, :, j) = A;
A = A + 1;
end
% Aggregate the X values in groups of 3 -- This is the part I would like help on
T = [1 1 1 2 2 2 3 3 3];
X_agg = zeros(2, 3, 3);
for i = 1:3
X_agg(:,:,i) = mean(X(:,:,T==i),3);
end
In 2 dimensions, I would use accumarray, but that does not accept higher dimension inputs.
Before getting to your answer let's first rewrite your code in a more general way:
ag = 3; % or agg_size
X_agg = zeros(size(X)./[1 1 ag]);
for i = 1:ag
X_agg(:,:,i) = mean(X(:,:,(i-1)*ag+1:i*ag), 3);
end
To avoid using the for loop one idea is to reshape your X matrix to something that you can use the mean function directly on.
splited_X = reshape(X(:), [size(X_agg), ag]);
So now splited_X(:,:,:,i) is the i-th part
that contains all the matrices that should be aggregated which is X(:,:,(i-1)*ag+1:i*ag)) (like above)
Now you just need to find the mean in the 3rd dimension of splited_X:
temp = mean(splited_X, 3);
However this results in a 4D matrix (where its 3rd dimension size is 1). You can again turn it into 3D matrix using reshape function:
X_agg = reshape(temp, size(X_agg))
I have not tried it to see how much more efficient it is, but it should do better for large matrices since it doesn't use for loops.