Count frequencies of pairs in matrix matlab - matlab

I have matrix X , mX2, I want to result a matrix S of size
size(unique(X(:,2),1) X size(unique(X(:,2),1)
for each S(i,j) I want to count how many times i,j appeared together.
for example:
X = [1 11 ;
2 11;
3 11;
5 23;
6 23;
1 23;
9 24;
9 25;
3 23;
10 23]
unique(X(:,2))
11
23
24
25
S should be:
0 2 0 0
0 0 0 0
0 0 0 1
0 0 0 0
(I don't care about diagonals, and it could either have them or not, also,S could be symmetric).
S(1,2) = 2
because 11 and 23 (which are in position 1,2) appeared together twice (i.e with the same value in X(:,1)).
Thanks

This is one way of doing it:
[~, ~, n1] = unique(X(:,1));
[~, ~, n2] = unique(X(:,2));
B = accumarray([n2 n1],1);
S = B*B';
This gives the full matrix:
>> S
S =
3 2 0 0
2 5 0 0
0 0 1 1
0 0 1 1
To remove the diagonal and lower triangle you can use
S = triu(B*B',1);
which yields
>> S
S =
0 2 0 0
0 0 0 0
0 0 0 1
0 0 0 0

Try the following:
% convert each columns to indices starting from 1
[a,~,aa] = unique(X(:,1));
[b,~,bb] = unique(X(:,2));
% group occurences of col2 according to values of col1
C = accumarray(aa, bb, [], #(x){x});
% keep only occurences of two or more values
C = C(cellfun(#numel,C) > 1);
% in case of three or more values co-occured, generate all pairs
C = cellfun(#(v) nchoosek(v,2), C, 'UniformOutput',false);
% concatenate all pairs
C = cell2mat(C);
% build count matrix
C = sparse(C(:,[1 2]), C(:,[2 1]), 1);
C = full(C);
The result in this case (obviously a symmetric matrix):
>> C
C =
0 2 0 0
2 0 0 0
0 0 0 1
0 0 1 0
or pretty-printed with row/column headers:
>> [{[]} num2cell(b'); num2cell(b) num2cell(C)]
ans =
[] [11] [23] [24] [25]
[11] [ 0] [ 2] [ 0] [ 0]
[23] [ 2] [ 0] [ 0] [ 0]
[24] [ 0] [ 0] [ 0] [ 1]
[25] [ 0] [ 0] [ 1] [ 0]

Related

How to leave only the elements that appear once per specific row x column per page?

I have a 3D array. I need to remove any elements that are in the same row, column position but on the next page (3rd dimension), and only use the first occurrence at that position. So if all pages were to multiply the result would be 0.
Since the 3D array may be of any size, I can't hard code solutions like isMember. I also can't use unique because elements can be the same, just not share the same position.
For example, input:
A(:,:,1) = [ 1 0 2];
A(:,:,2) = [ 1 1 0];
A(:,:,3) = [ 0 1 0];
the desired output is:
A(:,:,1) = [ 1 0 2];
A(:,:,2) = [ 0 1 0];
A(:,:,3) = [ 0 0 0];
How can I accomplish this?
Not the most elegant, but at least it works.
A(:,:,1) = [ 1 0 2 ];
A(:,:,2) = [ 1 1 0 ];
A(:,:,3) = [ 0 1 0 ];
for ii = 1:size(A,1)
for jj = 1:size(A,2)
unique_el = unique(A(ii, jj, :)); % Grab unique elements
for kk = 1:numel(unique_el)
idx = find(A(ii,jj,:) == kk); % Contains indices of unique elements
if numel(idx) > 1 % If an element occurs more than once
A(ii, jj, idx(2:end)) = 0; % Set to 0
end
end
end
end
A
A(:,:,1) =
1 0 2
A(:,:,2) =
0 1 0
A(:,:,3) =
0 0 0
I loop over the first two dimensions of A (rows and columns), find any unique elements which occur on a certain row and column location through the third dimensions (pages). Then set all occurrences of a unique element after the first to 0.
Given a more elaborate 3D matrix this still works:
A(:,:,1) = [1 0 2 0; 2 1 3 0];
A(:,:,2) = [1 1 0 0; 2 2 1 0];
A(:,:,3) = [0 1 1 3; 1 2 2 4];
A(:,:,1) =
1 0 2 0
2 1 3 0
A(:,:,2) =
0 1 0 0
0 2 1 0
A(:,:,3) =
0 0 1 3
1 0 2 4
If you want the first non-zero element and discard any element occurring afterwards, simply get rid of the unique() call:
A(:,:,1) = [1 0 2 0; 2 1 3 0];
A(:,:,2) = [1 1 0 0; 2 2 1 0];
A(:,:,3) = [0 1 1 3; 1 2 2 4];
for ii = 1:size(A,1)
for jj = 1:size(A,2)
idx = find(A(ii,jj,:) ~= 0); % Contains indices of nonzero elements
if numel(idx) > 1 % If more than one element
A(ii, jj, idx(2:end)) = 0; % Set rest to 0
end
end
end
A(:,:,1) =
1 0 2 0
2 1 3 0
A(:,:,2) =
0 1 0 0
0 0 0 0
A(:,:,3) =
0 0 0 3
0 0 0 4
My solution assumes, that, for a given "position", EVERY value after the first occurence of any value is cleared. Some of the MATLAB regulars around here had some discussions on that, from there comes the "extended" example as also used in Adriaan's answer.
I use permute and reshape to rearrange the input, so that we have all "positions" as "page" columns in a 2D array. Then, we can use arrayfun to find the proper indices of the first occurence of a non-zero value (kudos to LuisMendo's answer here). Using this approach again, we find all indices to be set to 0.
Let's have a look at the following code:
A(:,:,1) = [1 0 2 0; 2 1 3 0];
A(:,:,2) = [1 1 0 0; 2 2 1 0];
A(:,:,3) = [0 1 1 3; 1 2 2 4]
[m, n, o] = size(A);
B = reshape(permute(A, [3 1 2]), o, m*n);
idx = arrayfun(#(x) find(B(:, x), 1, 'first'), 1:size(B, 2));
idx = arrayfun(#(x) find(B(idx(x)+1:end, x)) + idx(x) + 3*(x-1), 1:size(B, 2), 'UniformOutput', false);
idx = vertcat(idx{:});
B(idx) = 0;
B = permute(reshape(B, o, m , n), [2, 3, 1])
Definitely, it makes sense to have a look at the intermediate outputs to understand the functioning of my approach. (Of course, some lines can be combined, but I wanted to keep a certain degree of readability.)
And, here's the output:
A =
ans(:,:,1) =
1 0 2 0
2 1 3 0
ans(:,:,2) =
1 1 0 0
2 2 1 0
ans(:,:,3) =
0 1 1 3
1 2 2 4
B =
ans(:,:,1) =
1 0 2 0
2 1 3 0
ans(:,:,2) =
0 1 0 0
0 0 0 0
ans(:,:,3) =
0 0 0 3
0 0 0 4
As you can see, it's identical to Adriaan's second version.
Hope that helps!
A vectorized solution. You can use the second output of max to find the index of the first occurence of a nonzero value along the third dimension and then use sub2ind to convert that to linear index.
A(:,:,1) = [ 1 0 2];
A(:,:,2) = [ 1 1 0];
A(:,:,3) = [ 0 1 0];
[~, mi] =max(logical(A) ,[], 3);
sz=size(A) ;
[x, y] =ndgrid(1:sz(1),1:sz(2));
idx=sub2ind( sz, x,y,mi);
result=zeros(sz) ;
result(idx) =A(idx);

Indexing for a double in cell array matlab

I have a cell array called Event of 179X59 entries and each element is a <1X14> double
so for example Event{1,1} is a 14 bit binary number in it.. like 0 1 0 0 0 0 0 0 0 0 1 0 0 0 which is spread out through columns 1 to 14 so each columns has a bit.
Now my task is to index through each element of the cell array and get into the double and assign a particular alphabet say a for the first bit if I see 1.
So if my alphabets are A through N for a binary 1 1 1 1 1 1 1 1 1 1 1 1 1 1, need to get
A B C D E F G H I J K L M N instead of that binary number.
So for the example give in the second line 0 1 0 0 0 0 0 0 0 0 1 0 0 0 I need to get
0 B 0 0 0 0 0 0 0 0 K 0 0 0
and in the end should return B,K removing zeros.
I have tried assigning each element to a matrix and tried using strrep but its not helping me out.
Without removing zeros:
alphabet = [11:24]; %// numbers. Replace values as needed
resultzeros = bsxfun(#times, alphabet, vertcat(Event{:}));
resultzeros = reshape(mat2cell(resultzeros, ones(1, size(resultzeros,1))), size(Event));
If you then need to remove zeros:
result = cellfun(#(x) nonzeros(x).', resultzeros, 'uni', 0);
Or directly:
result = cellfun(#(x) alphabet(x~=0), Event, 'uni', 0);
Example:
>> Event = {[0 0 1 0], [1 1 1 1]; [1 1 0 0], [0 0 1 1]};
>> alphabet = [4 5 6 7];
gives
result{1,1} =
6
result{2,1} =
4 5
result{1,2} =
4 5 6 7
result{2,2} =
6 7
Code
cellfun(#(x) cellstr(char(nonzeros(x.*[65:65+numel(x)-1])))', Event,'uni',0)
Results
For a sample Event:
Event = {
[0 1 0 1 0 0 1] [0 1 0 1 0];
[0 1 1 1 0] [0 0 0 1 1 1 0 0 0 0 1 1 0 1]}
Output -
>> Event{:}
ans =
0 1 0 1 0 0 1
ans =
0 1 1 1 0
ans =
0 1 0 1 0
ans =
0 0 0 1 1 1
>> out{:}
ans =
'B' 'D' 'G'
ans =
'B' 'C' 'D'
ans =
'B' 'D'
ans =
'D' 'E' 'F'
Of course, the number of columns and rows in Event at its "upper level" are maintained with out -
>> Event
Event =
[1x7 double] [1x5 double]
[1x5 double] [1x14 double]
>> out
out =
{1x3 cell} {1x2 cell}
{1x3 cell} {1x6 cell}
I suppose that time is not critical, so you can at least loop. Rough sketch:
alphabet = {A, B, C, D, E...}
j= 0;
for i=1:nBit
if( Event{1,1}(i) == 1)
EventAlphabet{1,1}{j} = alpabet{i};
j = j + 1;
end
end
Your question is a little bit unclear, so my answer is a rough sketch that may help you nontheless.

Matlab, generate new matrix

How do you translate matrix of A [(N) x (N)] to matrix B [(2N) x (2N)], such that:
if A(i,j)>=0, then:
B(i,j) = [ A(i,j) 0
0 A(i,j)]
if A(i,j)<0, then:
B(i,j) = [ 0 A(i,j)
A(i,j) 0 ]
?
For example1 by:
1 2
3 4
I'm want to get:
1 0 2 0
0 1 0 2
3 0 4 0
0 3 0 4
For example2 by:
1 -2
3 -4
I'm want to get:
1 0 0 2
0 1 2 0
3 0 0 4
0 3 4 0
Use the Kronecker tensor product:
B = kron(A.*(A>=0), [1 0; 0 1]) + kron(A.*(A<0), [0 1; 1 0]);
Or maybe
B = kron(A.*(A>=0), [1 0; 0 1]) - kron(A.*(A<0), [0 1; 1 0]);
if you want all positive values (your examples and your original formulation don't agree on this)
very simple using logical conditions:
B=[A.*(A>=0), A.*(A<0) ; A.*(A<0), A.*(A>=0)];
for example,
A=[1 2 ; -3 4];
B =
1 2 0 0
0 4 -3 0
0 0 1 2
-3 0 0 4
Postscipt:
This answer was written to answer the question above in its initial forms:
How do you translate matrix of A [(N) x (N)] to matrix B [(2N) x (2N)], such that:
if A(i,j)>=0, then:
B(i,j) = [ A(i,j) 0
0 A(i,j)]
if A(i,j)<0, then:
B(i,j) = [ 0 A(i,j)
A(i,j) 0 ]
?
later the OP wrote down some examples that made clear what he\she were after.

Generate derived matrix from index vector in matlab

Consider an index vector consisting of ones and zeros:
I=[0 0 1 0 1 1 0 0 0];
How can I easily generate the following matrix in matlab:
J=[0 2;
1 1;
0 1;
1 2;
0 3];
Use diff:
I = [0 0 1 0 1 1 0 0 0];
d = diff(I);
ind = [1 find(d~=0)+1]; %// starting index of each new value
rep = diff([ind numel(I)+1]); %// number of repetitions of each new value
J = [ I(ind).' rep.' ];
Using strfind for a slightly bigger example -
I =[1 1 0 0 1 0 1 1 0 0 0 1 1 1 1 0 0]
zero_pos = ['0' num2str(bsxfun(#eq,I,0),'%1d') '0']
ind3 = [ strfind(zero_pos,'01') ; strfind(zero_pos,'10')]
counts = diff(ind3(:))
var = zeros(numel(counts),1);
var(2:2:end)=1;
J = [var counts];
if ind3(1,1)-1>0
J = [1 ind3(1,1)-1;J];
end
Output
J =
1 2
0 2
1 1
0 1
1 2
0 3
1 4
0 2

Split matrix in MATLAB using predefined numbers of submatrix rows

I have a matrix A
1 1 0 0
0 1 0 0
1 0 0 1
0 0 1 0
0 0 0 0
0 1 1 1
1 1 0 0
1 0 0 0
0 0 0 1
I want this matrix to be split according to user's input say d = [1 2 3].
for i=2:length(d)
d(i) = d(i) + d(i-1); % d = [1 3 6]
end
This gives d = [1 (1+2) (1+2+3)] = d[1 3 6]. There are 9 rows in this matrix, calculate ceil of [(1/6)*9], [(3/6)*9] and [(6/6)*9]. Hence this gives [2 5 9]. First split up is first two rows , 2nd split up is next (5-2=3) 3 rows and third split is (9-5=4) 4 rows.
The output should be like:
The split up is: 1st split up->
1 1 0 0 % first 2 rows in matrix A
0 1 0 0
2nd split up->
1 0 0 1 % next 3 rows
0 0 1 0
0 0 0 0
3rd split up->
0 1 1 1 % next 4 rows
1 1 0 0
1 0 0 0
0 0 0 1
You can use mat2cell with input d = [1 2 3] to store the final splits in separate cell arrays
B = mat2cell(A, d+1, size(A,2));
or, to adapt it to your computation of the split row sizes:
d = [1 2 3];
c = cumsum(d); % [1, 3, 6]
s = ceil(size(A,1)*c/c(end)); % [2, 5, 9]
n = [s(1) diff(s)]; % [2, 3, 4]
B = mat2cell(A, n, size(A,2));
To display the splits you can add a command similar to:
cellfun(#disp, B)