Matlab: Refer to multiple, non consecutive elements - arrays

In Matlab is there any way to refer to multiple, non consecutive elements in a 1 dimensional array in the same line, eg. something like:
mean(strength(1:4,17:20))
I want to calculate the mean of 1st to 4th elements and the 17th to 20th elements in an array called strength etc. Except obviously a comma wouldn't work, because that would be double indexing, as if it was a matrix, when it's 1D. Is there another symbol you could use in place of the comma to do this, or would you need another technique to do this?

Like Andras says in his comment, you need a vector of the indices you wish to include in the calculation of the mean:
Just as you would reference the ith value of a vector with strength(i), you can have a vector instead of i, which will give you all of the specified values as another vector:
indexVector = [1:4, 17:20];
values = strength(indexVector);
This will give you a 1D vector of length 8 containing values 1:4 and 17:20 of the original strength vector, which would allow you to use mean(strength).
You can bypass writing these to variables, and just use:
mean(strength([1:4, 17:20]))

Related

Match each element of one array with elements of other array without loops

I want to match each element of one array (lessnum) with elements of the other array say (cc). Then multiply with a number from the third array (gl). I am doing using loops. The length of arrays are very large therefore it takes couple of hours. Is it possible to do without loops or make it faster. Here is the code, I am doing,
uniquec=sort(unique(cc));
maxc=max(uniquec);
c35p=0.35*maxc;
lessnum=uniquec(uniquec<=c35p);
greaternum=uniquec(uniquec>c35p);
gl=linspace(1,2,length(lessnum));
gr=linspace(2,1,length(greaternum));
newC=zeros(size(cc));
for i=1:length(gl)
newC(cc==lessnum(i))= cc(cc==lessnum(i)).*gl(i);
end
for i=1:length(gr)
newC(cc==greaternum(i))= cc(cc==greaternum(i)).*gr(i);
end
What you need to do is instead of storing the values that are less than or greater than c35p in lessnum and greaternum, respectively, you should store the indices of these numbers. That way, you can directly access the newC variable using these indices and then multiply your linearly generated values.
Further modifications are explained in the code itself. If you have any confusion you can read the help for unique
Here is the modified code (I assume that cc is a one-dimensional array)
%randomly generate a cc vector
cc = randi(100, 1, 10);
% modified code below
[uniquec, ~, induniquec]=unique(cc, 'sorted'); % modified to explicitly specify the inbuilt sorting capability of unique and generate the indicies of unique values in the array
maxc=max(uniquec);
c35p=0.35*maxc;
lessnum=uniquec<=c35p; % instead of lessnum=uniquec(uniquec<=c35p);
greaternum=uniquec>c35p; % instead of greaternum=uniquec(uniquec>c35p);
gl=linspace(1,2,sum(lessnum));
gr=linspace(2,1,sum(greaternum));
% now there is no need for 'for' loops. We first modify the unique values as specified and then regenerate the required matrix using the indices obtained previously
newC=uniquec;
newC(lessnum) = newC(lessnum) .* gl;
newC(greaternum) = newC(greaternum) .* gr;
newC = newC(induniquec);
This new code will run much faster than the original one but is much more memory intensive depending on the number of unique values in your original array.

Matlab: How to combine two vectors in one

I have two vectors
A = [...] %size 1x320
B = [...] %size 1x192
I would like to combine the two vectors in one but the way I want to combine them is the following:
Take the first 5 elements of vector A then add 3 elements from vector B add the next 5 elements from vector A then add the next element from vector B and so on until the both vectors are combined in one. I think the process should be repeated 64 times since 320/5=64 and 192/3=64.
Is there any built-in Matlab function to do that?
I don't think that there is a built-in function that does exactly that, but the following will do what you want:
A=randi(10,1,320);
B=randi(10,1,192);
C=zeros(1,length(A)+length(B));
for i=1:5
C(i:8:end)=A(i:5:end);
end
for i=6:8
C(i:8:end)=B(i-5:3:end);
end
Then the array C is the combined array.
Edit: Another way to do that, without for loops:
A=randi(10,1,320);
B=randi(10,1,192);
A_new=reshape(A,5,[]);
B_new=reshape(B,3,[]);
C=[A_new;B_new];
C=reshape(C,[1,numel(C)]);
In this solution, by specifying the third parameter in reshape(A,5,[]) to be [], we allow it to adjust the number of columns according to the length of A, given that the number of rows in the reshaped array is 5. In addition, numel(C) is the total number of elements in the array C. So this solution can be easily generalized to higher number of arrays as well.

Calculating standard deviation on data stored in a cell array of cell arrays

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, []));

Indexing a cell array with variable number of dimensions with a vector

In MATLAB, have an N-dimensional cell C, where N is an integer only determined at runtime. How do I access a specific element of C with a vector variable id? For example, with N=3 and id=[1,5,2], how to programmatically get the content of c{1,5,2}? I cannot hard-code it as c{id(1),id(2),id(3)} since N is only fixed at runtime.
If id is a cell array, then you can use sub2ind for this by taking advantage of the comma separated list syntax ,i.e. {:}, to send a variable number of inputs to sub2ind
id = {1,5,2};
ind = sub2ind(size(C), id{:})
c{ind}
if id isn't a cell array (and for some reason can't be created as one), then use num2cell to convert it.

matlab rearrange (permute) string array

I have a string array:
size(entries)
ans =
1 19413
I would like to rearrange the array to 4853 rows and 4 columns:
output=permute(entries,[4853 4]);
but get following error:
Error using permute ORDER contains an invalid permutation index.
What is the (probably obvious thing) I am doing wrong? thanks
You currently have 19413 elements, yet you wish to reshape this into a 4853 x 4 matrix that consists of 4853 * 4 = 19412 elements. No function in the world will help you do this because the original and target amount of elements don't match - they're off by one element. If you remove one of the elements...say... the last one, then we're getting somewhere.
Supposing you made a mistake and included that extra element by accident, you don't use permute here, but you use reshape. The second argument to reshape is the amount of elements to spread out for each target dimension, and that's what you're looking for. First remove the extraneous element that appears at the end of the array, then reshape the matrix:
output = reshape(entries(1:end-1),[4853 4]);
I'm 3 years late, but here's to anyone still looking for an answer.
In your case as mentioned above, yes you should use reshape() while minding that you preserve the total number of elements.
You use permute() when you want to reorder the dimensionality of an n-dimensional (ND) matrix.
The ORDER parameter specifies the order of the columns.
For example, if matrix A is LxMxN, the following line would make it MxLxN.
A = permute(A,[2 1 3]);
Hope this clears things.

Resources