I currently have a vector containing a cell array of predefined values. The number and content of these values should be able to vary:
names = {'r1','r2','r3'};
Furthermore, I have a Matrix, that should serve as an index Matrix. It looks like the following example, however, should also be variable in its size.
mat = [1 3 3; 2 1 3; 1 1 1];
Delivering:
1 3 3
2 1 3
1 1 1
I would now like to create a matrix containing the respective values of the array in the same matrix format. Hence, whereever mat contains a 1 the output should contain the first value of names and so on. The final result should then look like:
r1 r3 r3
r2 r1 r3
r1 r1 r1
Just to avoid missunderstandings: The content of names simply serves as an example here. Later specific names should be matched and it cannot be solved by simply adding an r infront of every index value.
Many thanks for your help!
That's simple:
result = names(mat);
The only caveat is that every numeric element in mat must be integer and between 1 and the number of elements in names.
Explanation: The mat works as a linear index. The general rule when indexing linearly is that the values are taken from the source array in column order (as it is normal), but the shape is the same as the shape of the index array.
Later Edit, thanks to Luis Mendo: this rule is valid except for the singleton dimensions of the index array. To enforce the rule for this corner case, one may use the slightly more elaborate (and more time-consuming) form:
result = reshape(names(mat), size(mat));
Related
Excel 365 allows to multiply ranges to get an array as a result.
Example:
#
A
B
C
1
1
0
1
2
0
1
1
Entering in A3
= A1:C1 * A2:C2
will evaluate to {1,0,1} * {0,1,1}
and return an array {0,0,1} spilling in A3:C3
#
A
B
C
3
0
0
1
This operation can also be used in formulas, especially useful in FILTER(), SUMPRODUCT() etc.
Is there a formula in Excel 365 that can take as arguments an arbitrary number of 1-D ranges, multiply them, and return a 1-D array in the same way as above?
For what I found out so far, SUMPRODUCT() and MMULT() can return only a single value, not a 1-D array.
Alternatively, I can write a LAMBDA, but would like to avoid it, if there is a ready-made formula for it.
I am not 100% what do you mean, I would assume you want to multiply all rows of the same column and return a row array with the result per column. You can achieve it in cell E1 using the following formula:
=BYCOL(A1:C3, LAMBDA(col, PRODUCT(col)))
and here is the output:
If you have only positives numbers, then you can use MMULT, based on the following mathematical properties:
Putting in excel terms using EXP/LN functions in our case it would be:
=EXP(MMULT(TOROW(ROW(A1:C3)/ROW(A1:C3)), LN(A1:C3)))
or using LET to avoid repetitions:
=LET(rng, A1:C3, rows, ROW(rng), u, TOROW(rows/rows), EXP(MMULT(u, LN(rng))))
You get the same result.
Note: rows/rows just returns the unit vector with the same number of rows as A1:C3.
I have a cell array A Mx3 in size where each entry contains a further cell-array Nx1 in size, for example when M=9 and N=5:
All data contained within in any given cell array is in vector format and of equal length. For example, A{1,1} contains 5 vectors 1x93 in size whilst A{1,2} contains 5 vectors 1x100 in size:
I wish to carry out this procedure on each of the 27 cells:
B = transpose(cell2mat(A{1,1}));
B = sort(B);
C = std(B,0,2); %Calculate standard deviation
Ultimately, the desired outcome would be, for the above example, 27 columns (9x3) containing the standard deviation results (padded with 0 or NaNs to handle differing lengths) printed in the order A{1,1}, A{1,2}, A{1,3}, A{2,1}, A{2,2}, A{2,3} and so forth.
I can do this by wrapping the above code into a loop to iterate over each one of the 27 cells in the correct order however, I was wondering if there was a clever cellfun or more succinct method to accomplish this particularly without the use of a loop?
You should probably realize that cellfun is essentially a glorified for loop over cells. There's simply extra error checking and all that to ensure that the whole thing works. In any case, yes it's possible to do what you're asking in a single cellfun call. Note that I am simply going to apply the same logic as you would have in a for loop with cellfun. Also note that because you're using cell arrays, you have no choice but to iterate over the entire master cell array. However, what you'll want to do is pad each resulting column vector in each output in the final cell array so that they all share the same length. We can do that with another two cellfun calls - one to determine the largest vector length and another to perform the padding operation.
Something like this could work:
% Step #1 - Sort the vectors in each cell array, then find row-wise std
B = cellfun(#(x) std(sort(cell2mat(x).'), 0, 2), A, 'un', 0);
% Step #2 - Determine the largest length vector and pad
sizes = cellfun(#numel, B);
B = cellfun(#(x) [x; nan(max(sizes(:)) - numel(x), 1)], B, 'un', 0);
The first line of code takes each element in A, converts each cell element into a N x 5 column matrix (i.e. cell2mat(x).'), we then sort each column individually with sort, then take the standard deviation row-wise. Because the output is ultimately a vector, we must make sure that the 'UniformOutput' flag is 0, or 'un=0'. Once we complete the standard deviation calculation, we determine the total number of elements for each resulting column vector for all cell elements, determine the largest size then use another cellfun call to pad these vectors so they all match the same size.
To finally get your desired output, you need to transpose the cell array, then unroll the elements in column major order. Remember that MATLAB accesses things in column major, so a common trick to get things in row-major (what you want) as opposed to column major is to first transpose, then unroll in column-major fashion to perform a row-major readout. Doing this in one line is tricky, so you'll need to not only transpose the cell array, you must use reshape to ensure that the elements are read out in row major format, but then ensuring that the result is placed in a row of cells, then call cell2mat so you can piece these vectors together. The final result should be a 27 column matrix where we have pieced all of these vectors together in a single row-wise fashion:
C = cell2mat(reshape(B.', 1, []));
I have three column vectors, then I want to creat matrix from this column victors
A1(:);
A2(:);
A3(:)
each column vectors has 25 element then the new matrix C will be a matrix with 3x25
I want to make A1(:) the first column of matrix c
A2(:) second column
A3(:) third column
Use cat to concatenate along dimension 1 or 2 depending on how you input those three vectors.
Thus, you can use -
C = cat(2,A1(:),A2(:),A3(:)).'
Or
C = cat(1,A1(:).',A2(:).',A3(:).')
Of course, you can skip (:)'s, if you know that all those are column vectors.
The above two approaches assumes that you intend to get an output of size 3 x N, where is N is the number of elements in the column vectors. If you were looking to get an output of size N x 3 , i.e. where each column is formed from the elements of column vectors A1, A2 and so on, just drop the transpose from the first of the two approaches mentioned above. Thus, use this -
C = cat(2,A1(:),A2(:),A3(:))
i have a matrix B of N*3 dim. I want to find the indices of B whose column 3 has value 1.
I used the command [~,id]=ismember(1,B(:,3)). id returns only value 1 even though there are many rows in the matrix which has the column 3 with value 1. Can any one point out what is wrong in the command?
Rather do:
id = find(B(:,3)==1)
but as an aside, to use ismember you should swap your input [~,id]=ismember(B(:,3),1).
I have a 60,000-by-2 array. The first column is data 1 and second column is data 2; both of equal length. I'm not sure how to properly write the syntax to compare data 1 to data 2, and if data 1 is larger than data 2 then write that to the third column. Or vice versa if data 2 is larger than data 1. I have begun constructing a for loop, but I'm having syntax issues comparing the columns.
No loops are needed. If you simply want to create a vector containing the largest element in each row of your 60,000-by-2 matrix you can use the max function:
A = rand(6e4,2); % Random demo data
B = max(A,[],2);
Or if you then want to put the result directly in a third column of A:
A(:,3) = max(A,[],2);
Read the documentation for max. You'll see that the 2 in the third argument applied the max function across each row of the input, A.