How to restructure histcounts for using with a 2d-matrix - matlab

I have a 250000x2-matrix in matlab, where in the first row I have a degree (int, 0-360°), and in the second a float-value corresponding to this value. My target is to count each occurence of a degree-value-pair (e.g. a row), and write the result in a nx3-matrix. n corresponds here with the number unique rows.
Thus my first step was to get all unique values (using unique(M, 'rows')) which works. But now I want to count all unique values. This was done by the following approach:
uniqu_val = unique(values, 'rows');
instance = histcounts(values(:), uniqu_val);
Here I have to enter a vector as second element, and not a matrix (uniqu_val is a nx2-dim-matrix). But I want to get the number of occurence for each unique row, therefore I can not use only one column of the matrix uniqu_val. In short: I want to use histcounts not only for a 1D-matrix as edge-value, but for a 2D-matrix. How can I solve this problem?

You can use the third output from unique and then use histcounts like so -
%// Find the unique rows and keep the order with 'stable' option
[uniq_val,~,row_labels] = unique(values, 'rows','stable')
%// Find the counts/instances
instances = histcounts(row_labels, max(row_labels))
%// OR with HISTC: instances = histc(row_labels, 1:max(row_labels))
%// Output the unique rows alongwith the counts
out = [uniq_val instances(:)]
Sample run -
>> values
values =
2 1
3 1
2 3
3 3
1 2
3 3
1 3
3 1
3 2
1 2
>> out
out =
2 1 1
3 1 2
2 3 1
3 3 2
1 2 2
1 3 1
3 2 1

Related

Can I get 2 set of random number array in matlab?

idx=randperm(5)
idx=[1,3,4,2,5]
I know this works like that but I'm curious about is there anyway to get something like this.
idx=[1,3,4,2,5,5,3,2,4,1]
adding one set of array after one array
Is there any way to make that?
One vectorized way would be to create a random array of size (m,n), sort it along each row and get the argsort indices. Each row of those indices would represent a group of randperm values. Here, m would be the number of groups needed and n being the number of elements in each group.
Thus, the implementation would look something like this -
[~,idx] = sort(rand(2,5),2);
out = reshape(idx.',1,[])
Sample run -
>> [~,idx] = sort(rand(2,5),2);
>> idx
idx =
5 1 3 2 4
4 3 2 5 1
>> out = reshape(idx.',1,[])
out =
5 1 3 2 4 4 3 2 5 1
You can use the modulo operation:
n = 5 %maximum value
r = 2 %each element are repeated r times.
res = mod(randperm(r*n),n)+1

What is the easiest/ computationally efficient way to find the indexes at particular locations?

I have a matrix
m =
2 2 1
3 2 1
0 4 1
0 4 1
5 4 1
0 5 2
1 2 2
1 3 2
1 4 2
1 1 3
0 2 3
0 3 4
0 3 4
that is potentially of N x 3, where N can be very large.
I want to find the index in the first column (1-13) where i have zeros but only if there are duplicate rows or the rows are unique. I don't want rows that the 2nd and 3rd column are the same but the first column is other than zero. In other words, if there is a zero at the first column but its corresponding number in the second and third column are the same with another one that has a different number other than zero in the first column, then ignore the index of that zero. So, in the example above, i want to return only the indices 6, 11,12, 13. Index 3,4 should not be return because they violate the rule that there is a row similar to that (2nd and 3rd column) but the first column is different, as we can see below:
0 4 1
0 4 1
5 4 1
One slow solution would be to find the indices of the rows that the first column is 0 indm=m(:,1)==0 and then iterate over the rows of the matrix checking whether any other row exists in matrix (m) that has identical 2nd and 3rd columns but different 1st column. If such case does not exist then add the index of the row to the list to be returned by the program.
However, this method, would require "for loops" going over large matrices.
One way to solve this (assuming that a row is bad if there is any other row with the same columns 2 and 3) is to find all the different rows, and then checking whether the first column is the same everywhere.
%# uIdx is the same for sets of rows where m(i,2:3) is equal
[~,~,uIdx] = unique(m(:,2:3),'rows');
%# allZeros is true if all entries in the first column of m
%# corresponding to a set are the zero
allZeros = accumarray(uIdx,m(:,1),[],#(x)all(x==0));
%# a good row belongs to a set of rows from m(:,2:3)
%# where all corresponding entries in the first column are zeros
%# use allZeros(uIdx) to expand allZeros to size(m,1)
goodRowIndices = find(allZeros(uIdx) == true)
goodRowIndices =
6
11
12
13
Here is my solution:
mm = m(:,1)==0;
imm = find(mm);
[mu,~, imu] = unique(m(mm,2:3),'rows','stable');
[~,ia] = setdiff(mu,m(~mm,2:3),'rows');
X = imm(ismember(imu,ia));
Line 3 extract the unique lines beginning with 0; line 4 keeps only the lines that does not appear in the lines not beginning by 0, and line 5 get back the indexes of the lines to keep.
Not sure its the most efficient way, because of it involves two sorts.

MATLAB: Creating a matrix with all possible group combinations

I'm running an experiment with lots of conditions, and particular numbers of groups in each condition.
A. 3 groups
B. 3 groups
C. 2 groups
D. 3 groups
E. 3 groups
I've worked out that there are 3×3×2×3×3 = 162 possible combinations of groups.
I want to create a MATLAB matrix with 162 rows and 5 columns. That is, one row for each combination and one column to indicate the value for each group.
So, for instance, the first row would be [1 1 1 1 1], indicating that this combination is group 1 for all conditions. The second row would be [1 1 1 1 2], indicating that it's group 1 for all conditions except for the last which is group 2. The 162nd and final row would be [3 3 2 3 3].
M = 1 1 1 1 1
1 1 1 1 2
.........
3 3 2 3 3
What's the most efficient way to achieve this? I realise I could use a loop, but feel sure there's a better way. I thought maybe the perms function would work but I can't see how.
You can use combvec (see last line, the rest is only generating test data):
% A. 3 groups
% B. 3 groups
% C. 2 groups
% D. 3 groups
% E. 3 groups
ngroups = zeros(5, 1);
ngroups(1) = 3;
ngroups(2) = 3;
ngroups(3) = 2;
ngroups(4) = 3;
ngroups(5) = 3;
v = {};
for i = 1:length(ngroups)
v{i} = 1:ngroups(i) % generate a vector of valid group indices
end
% get all possible combinations
x = combvec( v{:} )
As this will return a 5 x 162 double you need to transpose the resulting matrix x:
x.'

Counting Different unique numbers in matlab

I want to count the number of different numbers in the matrix other than -1. For example the different numbers in the following matrix are 6 as the different numbers are 8 9 3 5 2 1
-1 -1 8 9
3 5 -1 3
2 3 3 1
How can I do that with MATLAB ?
I. Using unique
Use unique with its 'stable' option to keep the order -
A1 = reshape(A.',1,[]) %// A is your input matrix
out = unique(A1(A1~=-1),'stable') %// out is your desired output
Output -
out =
8 9 3 5 2 1
If you don't care about keeping the order of the unique numbers, you can use unique without the 'stable' option -
A1 = unique(A)
out = A1(A1~=-1)
which can be converted to a dense one-liner if you are into those -
out = nonzeros(unique(A).*(unique(A)~=-1))
II. Using setdiff
Use setdiff with 'stable' option to keep the order -
A1 = reshape(A.',1,[]) %// A is your input matrix
out = setdiff(A1,-1,'stable') %// out is your desired output
One-liner using default version of setdiff, if you don't care about the order -
out = setdiff(A,-1)
Finally, you can get the count of those unique numbers with numel(out).

MATLAB Combine matrices of different dimensions, filling values of corresponding indices

I have two matrices, 22007x3 and 352x2. The first column in each is an index, most (but not all) of which are shared (i.e. x1 contains indices that aren't in x2).
I would like to combine the two matrices into a 22007x4 matrix, such that column 4 is filled in with the values that correspond to particular indices in both original matrices.
For example:
x1 =
1 1 5
1 2 4
1 3 5
2 1 1
2 2 1
2 3 2
x2 =
1 15.5
2 -5.6
becomes
x3 =
1 1 5 15.5
1 2 4 15.5
1 3 5 15.5
2 1 1 -5.6
2 2 1 -5.6
2 3 2 -5.6
I've tried something along the lines of
x3(1:numel(x1),1:3)=x1;
x3(1:numel(x2(:,2)),4)=x2(:,2);
but firstly I get the error
??? Subscripted assignment dimension mismatch.
and then I can't figure out I would fill the rest of it.
An important point is that there are not necessarily an equal number of rows per index in my data.
How might I make this work?
Taking Amro's answer from here
[~, loc] = ismember(x1(:,1), x2(:,1));
ismember's second argument returns the location in x2 where each element of x1 can be found (or 0 if it can't)
a = x2(loc(loc > 0), 2);
get the relevant values using these row indices but excluding the zeros, hence the loc > 0 mask. You have to exclude these as 1, they are not in x2 and 2 you can't index with 0.
Make a new column of default values to stick on the end of x1. I think NaN() is probably better but zeros() is also fine maybe
newCol = NaN(size(x1,1),1)
Now use logical indexing to get the locations of the non zero elements and put a in those locations
newCol(loc > 0) = a
Finnaly stick it on the end
x3 = [x1, newCol]