I'm trying to get to grips with matlab, so this question is more about syntax than anything else.
I want to create a vector (1xn) of matrices. The matrices are all possibly of different dimensions eg. matrix 1 = 4 x 5, matrix 2 = 5 x 6 etc.
I tried using a for loop, but I had the following error:
Subscripted assignment dimension mismatch.
You can store an array of matrices of different sizes as a cell array of matrices. Often you'll want to create these cell arrays dynamically using the arrayfun function which will do this for you if you set the UniformOutput option to 0.
Example:
cols = [4 5 6];
rows = [1 2 3];
A = arrayfun(#(i) zeros(rows(i),cols(i)),1:3,'UniformOutput',0);
A{:}
Outputs:
ans =
0 0 0 0
ans =
0 0 0 0 0
0 0 0 0 0
ans =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Related
I am creating a Matlab program to handle an array of data that contains finite integers (not necessary to be consecutive). Let says my data array is A, I need to find the unique values of A first, that forms a vector B, and I have to count the number of occurrence of each unique value in A, that gives another vector C. Finally, I need a vector E which has the same length of A but with the value of the ith element of E computed as E(i) = C(k) with k = A(i)
I have the code to create B and C as follows:
A=[5 5 1 1 3 1 3 11 9 6 -2];
[B, ia, ic]=unique(A);
C = accumarray(ic,1);
A could be a large vector and the elements of A could be very different and in a wide range, I wonder if there is any vectorize approach to generate the array E instead of the following loop method
E = zeros(size(A));
for n=1:length(E)
k=find(B==A(n));
E(n) = C(k);
end
As you say, to calculate the values for E, you need to calculate the indices in B which correspond to each element in A, informally where A == B. This obviously won't work because A and B are different sizes. But we can get what we want by thinking about things as a 2D grid. Transpose one of the vectors and equate them.
A == B.'
% or for older versions of MATLAB (won't implicitly expand the different sized variables)
bsxfun(#eq, A, B.')
ans =
7×11 logical array
0 0 0 0 0 0 0 0 0 0 1
0 0 1 1 0 1 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0
1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0 0 0
% to help visualise
% A = [5 5 1 1 3 1 3 11 9 6 -2];
% B = [-2 1 3 5 6 9 11];
You can see that, for each column, the position of the 1 tells us the where we can find that element in A in vector B. We can use find to get the row indices of each 1, and use that to calculate E.
[indices, ~] = find(A == B.');
E = C(indices);
Final result
If you want to calculate this with one line of code, you can use do the following
A=[5 5 1 1 3 1 3 11 9 6 -2];
[B, ia, ic]=unique(A);
C = accumarray(ic,1);
E = C(mod(find(B.' == A)-1, length(B))+1).';
% or for older versions of MATLAB
E = C(mod(find(bsxfun(#eq, A, B.'))-1, length(B))+1).';
I would like to enter the same vector of numbers repeatedly to an existing matrix at specific (row) logical indices. This is like an extension of entering just a single number at all logical index positions (at least in my head).
I.e., it is possible to have
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]); %normally obtained from previous operation
mat(rowInd,1) = 15;
mat =
0 0 0
15 0 0
0 0 0
0 0 0
15 0 0
But I would like to do sth like this
mat(rowInd,:) = [15 6 3]; %rows 2 and 5 should be filled with these numbers
and get an assignment mismatch error.
I want to avoid for loops for the rows or assigning vector elements single file. I have the strong feeling there is an elementary matlab operation that should be able to do this? Thanks!
The problem is that your indexing picks two rows from the matrix and tries to assign a single row to them. You have to replicate the targeted row to fit your indexing:
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]);
mat(rowInd,:) = repmat([15 6 3],sum(rowInd),1)
This returns:
mat =
0 0 0
15 6 3
0 0 0
0 0 0
15 6 3
I have a 3D matrix A (size m*n*k) where m=latitude, n*longitude and k=time.
I want only specific values from first and second dimension, specified by a logical matrix B (size m*n), and I want only the timesteps specified by vector C (size k).
In the end this should become a 2D matrix D, since the first two dimesions will colapse to one.
What is the most easy approach to do this?
And also is it possible to combine logical with linear indizes here? For example B is logical and C is linear?
Sample code with rand:
A=rand(10,10,10);
B=randi([0 1], 10,10);
C=randi([0 1], 10,1);
D=A(B,C) %This would be my approach which doesnt work. The size of D should be sum(B)*sum(c)
Another example without rand:
A=reshape([1:27],3,3,3);
B=logical([1,0,0;1,0,0;0,0,0]);
C=(1,3); %get data from timestep 1 and 5
D=A(B,C);%What I want to do, but doesnÄt work that way
D=[1,19;2,20];%Result should look like this! First dimension is now all data from dimesion 1 and 2. New dimesion 2 is now the time.
A = rand(4,4,4);
B = randi([0 1], 4,4)
B =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
>> C = randi([0 1],1,1,4);
>> C(:)
ans =
0
1
1
0
Then use bsxfun or implicit expansion expansion whith .* if newer Matlab version to generate a matrix of logical for you given coordinates.
>> idx = logical(bsxfun(#times,B,C))
idx(:,:,1) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
idx(:,:,2) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,3) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,4) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Then your output is D = A(idx). However, note that this D is now an Nx1 array. Where N is number of true elements is B times number of true elements in C. 10x True in B and 2x True in C:
>> size(D)
ans =
20 1
An easy way to do it is to first reshape A into an m*n-by-k matrix, then do your indexing:
result = reshape(A, [], size(A, 3));
result = result(B, C);
In this case C can be either a logical vector or vector of indices.
I know that to generate a block-diagonal matrix in Matlab the command blkdiag generates such a matrix:
Now I am faced with generating the same block-diagonal matrix, but with also matrix elements B_1, B_2,..., B_{n-1} on the upper diagonal, zeros elsewhere:
I guess this can be hardcoded with loops, but I would like to find a more elegant solution. Any ideas on how to implement such a thing?
P.S. I diag command, that using diag(A,k) returns the kth diagonal. I need something for writing in the matrix, for k>0, and for block matrices, not only elements.
There is a submission on the File Exchange that can do this:
(Block) tri-diagonal matrices.
You provide the function with three 3D-arrays, each layer of the 3D array represents a block of the main, sub- or superdiagonal. (Which means that the blocks will have to be of the same size.) The result will be a sparse matrix, so it should be rather efficient in terms of memory.
An example usage would be:
As = bsxfun(#times,ones(3),permute(1:3,[3,1,2]));
Bs = bsxfun(#times,ones(3),permute(10:11,[3,1,2]));
M = blktridiag(As, zeros(size(Bs)), Bs);
where full(M) gives you:
1 1 1 10 10 10 0 0 0
1 1 1 10 10 10 0 0 0
1 1 1 10 10 10 0 0 0
0 0 0 2 2 2 11 11 11
0 0 0 2 2 2 11 11 11
0 0 0 2 2 2 11 11 11
0 0 0 0 0 0 3 3 3
0 0 0 0 0 0 3 3 3
0 0 0 0 0 0 3 3 3
This could be one approach based on kron, tril & triu -
%// Take all A1, A2, A3, etc in a cell array for easy access and same for B
A = {A1,A2,A3,A4}
B = {B1,B2,B3}
%// Setup output array with the A blocks at main diagonal
out = blkdiag(A{:})
%// logical array with 1s at places where kth diagonal elements are to be put
idx = kron(triu(true(numel(A)),k) & tril(true(numel(A)),k),ones(size(A{1})))>0
%// Put kth diagonal blocks using the logical mask
out(idx) = [B{1:numel(A)-k}]
Sample run with k = 1 for 2 x 2 sizes matrices -
>> A{:}
ans =
0.3467 0.7966
0.6228 0.7459
ans =
0.1255 0.0252
0.8224 0.4144
ans =
0.7314 0.3673
0.7814 0.7449
ans =
0.8923 0.1296
0.2426 0.2251
>> B{:}
ans =
0.3500 0.9275
0.2871 0.0513
ans =
0.5927 0.8384
0.1629 0.1676
ans =
0.5022 0.3554
0.9993 0.0471
>> out
out =
0.3467 0.7966 0.3500 0.9275 0 0 0 0
0.6228 0.7459 0.2871 0.0513 0 0 0 0
0 0 0.1255 0.0252 0.5927 0.8384 0 0
0 0 0.8224 0.4144 0.1629 0.1676 0 0
0 0 0 0 0.7314 0.3673 0.5022 0.3554
0 0 0 0 0.7814 0.7449 0.9993 0.0471
0 0 0 0 0 0 0.8923 0.1296
0 0 0 0 0 0 0.2426 0.2251
Can someone help me with the following problem in Matlab? I have a first vector containing the elements values. For example,
[2 8 4 9 3].
And a second one with the desired places in a second vector. For example,
[0 0 1 0 0 0 0 1 1 0 0 1 0 0 1].
Now I want to put the values from the first vector on the positions of the second one to end up with
[0 0 2 0 0 0 0 8 4 0 0 9 0 0 3].
What is the most efficient way of doing this when the size of the vector can be very large. (then thousands of elements)?
You can consider the y values as logical indicators, then use logical indexing to set those values to the values in x.
x = [2 8 4 9 3];
y = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
y(logical(y)) = x;
Alternatively, you could use
y(y==1) = x;
Use self-indexing:
% Your values:
V = [2 8 4 9 3];
% The desired locations of these values:
inds = [0 0 1 0 0 0 0 1 1 0 0 1 0 0 1];
% index the indices and assign
inds(inds>0) = V