Matlab: command to get counts of elements in a list - matlab

I need the counts of each element in the list. Is there some ready command for this?
>> [1 1 5 5 10 12 12 2 2 2]
ans =
1 1 5 5 10 12 12 2 2 2
Goal: getting counts like this
>> [1, 2; 5, 2; 10, 1; 12, 2]
ans =
1 2
2 3
5 2
10 1
12 2

I'm not sure if the formatting of the result is important to you, but the following link might come in handy. How can I count the occurrences of each element in a vector in MATLAB?
It's an answer to a similar question on the MathWorks website by their support team. They say there is no single function for it, but they provide 3 options.

Related

Alter number sort / number sequence

I have an array / number sequence a=[1,2,3,4,5] and I'm trying
to create an array / number sequence that looks like a_new below:
The columns represent the orders / index the numbers should go in.
a_new=...
[1,2,3,4,5;
2,1,2,3,4;
3,3,1,2,3;
4,4,4,1,2;
5,5,5,5,1]
My thoughts where to use circshift but quickly found out that would not work.
a=[1,2,3,4,5];
for n=1:5
a_wrong(:,n)=circshift(a(:)',[0 n])(:)
end
produces
a_wrong=[
5 4 3 2 1
1 5 4 3 2
2 1 5 4 3
3 2 1 5 4
4 3 2 1 5]
Any thoughts? It doesn't need to use circshift if that won't work.
PS: I'm using Octave 4.2 which is similar to Matlab
There are probably quite a few different ways to generate this matrix. Here's one using the functions repmat, toeplitz, tril, and triu:
>> a_new = tril(repmat(a.', 1, numel(a)), -1)+triu(toeplitz(a))
a_new =
1 2 3 4 5
2 1 2 3 4
3 3 1 2 3
4 4 4 1 2
5 5 5 5 1
I'm not sure about a built-in function, but this should work;
a=[1,2,3,4,5];
a_out = ones(length(a), length(a))
for n=1:5
a_out(n,:) = [n*ones(n-1),a(n:end)]
end
I do not have Octave or MATLAB installed on my computer, so I cannot test it. This may have a silly error, forgive me for that!
You can use spdiags to generate the matrix:
n = numel(a);
a_new = spdiags([repmat(flip(a).',1,n); repmat(a,n-1,1)],(1-n):0);

matlab: dividing vector into overlapping chunks of fixed size

I've a vector that I would like to split into overlapping subvectors of size cs in shifts of sh. Imagine the input vector is:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
given a chunksize of 4 (cs=4) and shift of 2 (sh=2), the result should look like:
[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]
note that the input vector is not necessarily divisible by the chunksize and therefore some subvectors are discarded. Is there any fast way to compute that, without the need of using e.g. a for loop?
In a related post I found how to do that but when considering non-overlapping subvectors.
You can use the function bsxfun in the following manner:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
A = v(bsxfun(#plus,(1:cs),(0:sh:length(v)-cs)'));
Here is how it works. bsxfun applies some basic functions on 2 arrays and performs some repmat-like if the sizes of inputs do not fit. In this case, I generate the indexes of the first chunk, and add the offset of each chunck. As one input is a row-vector and the other is a column-vector, the result is a matrix. Finally, when indexing a vector with a matrix, the result is a matrix, that is precisely what you expect.
And it is a one-liner, (almost) always fun :).
Do you have the signal processing toolbox? Then the command is buffer. First look at the bare output:
buffer(v, 4, 2)
ans =
0 1 3 5 7 9 11
0 2 4 6 8 10 12
1 3 5 7 9 11 13
2 4 6 8 10 12 0
That's clearly the right idea, with only a little tuning necessary to give you exactly the output you want:
[y z] = buffer(v, 4, 2, 'nodelay');
y.'
ans =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
That said, consider leaving the vectors columnwise, as that better matches most use cases. For example, the mean of each window is just mean of the matrix, as columnwise is the default.
I suppose the simplest way is actually with a loop.
A vectorizes solution can be faster, but if the result is properly preallocated the loop should perform decently as well.
v = 1:13
cs = 4;
sh = 2;
myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;
for t = cs:sh:numel(v)
count = count+1;
myMat(count,:) = v(t-cs+1:t);
end
You can accomplish this with ndgrid:
>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
The nice thing about the second syntax of the colon operator (j:i:k) is that you don't have to calculate k exactly (e.g. 1:2:6 gives [1 3 5]) if you plan to discard the extra entries, as in this problem. It automatically goes to j+m*i, where m = fix((k-j)/i);
Different test:
>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
And a new row will form with v=1:17. Does this handle all cases as needed?
What about this? First I generate the starting-indices based on cs and sh for slicing the single vectors out of the full-length vector, then I delete all indices for which idx+cs would exceed the vector length and then I'm slicing out the single sub-vectors via arrayfun and afterwards converting them into a matrix:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(#(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')
E.g. for cs=5; sh=3; this would give:
idx =
1 3 5 7
ans =
1 2 3 4 5
3 4 5 6 7
5 6 7 8 9
7 8 9 10 11
Depending on where the values cs; sh come from, you'd probably want to introduce a simple error-check so that cs > 0; as well as sh < cs. sh < 0 would be possible theoretically if you'd want to leave some values out in between.
EDIT: Fixed a very small bug, should be running for different combinations of sh and cs now.

getting all possibilities from 2 matrix

I'm trying to get all possible outcome from 2 different dimension matrix.
say,
A=[1 2 3 4;2 3 4 5]
and
B=[11 12; 13 14; 15 16]
with the output of
C=[1 2 3 4 11 12; 1 2 3 4 13 14; 1 2 3 4 15 16; 2 3 4 5 11 12; 2 3 4 5 13 14; 2 3 4 5 15 16]
I have tried using for loop method but I find it very inefficient and would therefore like to have a better approach to it.
Thanks.
If the repetition of matrix A is always a the number of rows of matrix B and repetition of matrix B is always the number of rows of A. Then, you can use the functions kron and repmat to achieve what you wanted. So, in this example, C can be obtained with a single line as
[kron(A, ones(size(B, 1), 1)) repmat(B, [size(A, 1) 1])]
You can use indexing to achieve this by
C=[A(repmat(1:size(A,1), 1, size(B,1)), :) B(repmat(1:size(B,1), 1, size(A,1)), :)];
A more readable version is
[X,Y]=meshgrid(1:size(A,1), 1:size(B,1));
C=[A(X(:),:) B(Y(:),:)];

Ranges with different step size for odd and even steps in MATLAB

What is the fastest and the simplest way to generate an array like
[0, 1, 3, 4, 6, 7, 9, 10, ...]
in MATLAB?
You can obtain the cumulative sum of the vector of steps (in your case it is [1 2 1 2 1 2 1 2 ...]). For example:
x = cumsum([0, repmat([1 2], 1, 4)])
x =
0 1 3 4 6 7 9 10 12
You can generate matrix with two rows: top row for odd array elements, bottom row for even elements. Than transform matrix into array with reshape.
>> a=[0:3:15; 1:3:16]
a =
0 3 6 9 12 15
1 4 7 10 13 16
>> a=reshape(a,1,12)
a =
0 1 3 4 6 7 9 10 12 13 15 16
Not one line but will work for either an odd or even number of total elements, and could be expanded if you wanted more than two different steps:
a = zeros(1,8);
a(1:2:end) = 0:3:10;
a(2:2:end) = 1:3:10;
Here is a simple and compact way:
A = 0:20;
A(3:3:end) = []

Matlab - a command to sort variables into groups and output the group indices

I have a vector, for example: a = [1 1 2 2 7 7 7 10 10 10 10 11 15]. It can be unsorted, but here I'm writing it as sorted. I am looking for a Matlab command that will convert the above to [1 1 2 2 3 3 3 4 4 4 4 5 6]. Is there a good way to do this?
There's at least two ways to do this
(1) use the third output of unique:
[~,~,out] = unique(a)
(2) use grp2idx from the statistics toolbox
out = grp2idx(a)
I'm not sure if it's possible to do the conversion with only one command, but this is one way to do it:
a = [1 1 2 2 7 7 7 10 10 10 10 11 15];
a = sort(a);
UniqVector = unique(a);
for i = 1:size(UniqVector, 2)
a(a == UniqVector(i)) = i;
end