Finding and counting numbers from one matrix in another
6 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Meghan Rochford
el 15 de Mzo. de 2017
Comentada: dpb
el 16 de Mzo. de 2017
Hello all
I have a question, which seems complex to me but probably isn't.
I have two matrices and I am trying to find and count each number from one matrix in another.
For example: Lets say I have two matrices A and B. A is a list of nodes (mx1) and B is a list of triangles that contain those nodes (nx3).
I need to find all the nodes from A that are in B, count how many times they appear and in which triangles they appear.
So in the end I will get two new matrices, C=[nodeID, No. of times it appears in all columns in B] and D=[node ID, list of triangles (1:9) that contain that node (will contain 0s for nodes that few elements attached].
I have tried to use find and ismember but they don't see to do exactly what I want.
I hope I've explained that well enough. Help is very much appreciated.
Meghan
0 comentarios
Respuesta aceptada
dpb
el 15 de Mzo. de 2017
Is fairly simple, yes, but have to think about it a while to find "the Matlab way"... :)
There's always another way, but what came to me first...
>> A=[1:13].'; % Assume total of 13 nodes
>> B=randi(20,20,3) % Random set of triangles that include more nodes than in the list
B =
2 2 19
11 5 4
16 19 6
19 4 3
3 17 3
12 11 18
10 20 12
1 2 11
7 9 3
4 3 18
16 20 13
7 1 8
11 16 11
4 17 9
13 18 2
6 2 5
14 8 3
14 6 4
15 17 5
10 9 9
>> [n,bin]=histc(B(:),A); % count how many of each and locate where they are
>> C=[A n] % 'C' is now easy-peasy...
C =
1 2
2 5
3 6
4 5
5 3
6 3
7 2
8 2
9 4
10 2
11 5
12 2
13 2
>>
D takes a little thinking...first reshape bin to match the shape of B so can get the row corresponding to position...
>> bin=reshape(bin,[],3);
>> D=zeros(length(A),length(B)); % preallocate for all possible locations
>> for i=1:length(A) % for each node in A
[r c]=find(bin==A(i)) % get row where located
r=unique(r); % save only the unique rows for repeated; probably not needed
t(i,r)=r; % and populate array at those locations with the value
end
>> D=[n t]
D =
2 0 0 0 0 0 0 0 8 0 0 0 12 0 0 0 0 0 0 0 0
5 1 0 0 0 0 0 0 8 0 0 0 0 0 0 15 16 0 0 0 0
6 0 0 0 4 5 0 0 0 9 10 0 0 0 0 0 0 17 0 0 0
5 0 2 0 4 0 0 0 0 0 10 0 0 0 14 0 0 0 18 0 0
3 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 19 0
3 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 16 0 18 0 0
2 0 0 0 0 0 0 0 0 9 0 0 12 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0 12 0 0 0 0 17 0 0 0
4 0 0 0 0 0 0 0 0 9 0 0 0 0 14 0 0 0 0 0 20
2 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 20
5 0 2 0 0 0 6 0 8 0 0 0 0 13 0 0 0 0 0 0 0
2 0 0 0 0 0 6 7 0 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 11 0 0 0 15 0 0 0 0 0
>>
The duplicated nodes not possible in a real dataset I'd presume; I just added so could use the randomized array w/o having to clean it up here.
Oh, above assumes the row is the same as the node in assigning r as the row, that needs to be the elements of A for the corresponding index if the array of nodes isn't 1:N.
2 comentarios
Meghan Rochford
el 16 de Mzo. de 2017
Editada: Meghan Rochford
el 16 de Mzo. de 2017
dpb
el 16 de Mzo. de 2017
Editada: dpb
el 16 de Mzo. de 2017
Yes, I mentioned above that if A has missing values there's an issue. I've a conflicting engagement here in just a few minutes but the size length(A) is still correct for row dimension; the dimension I used was maximum possible, for usage not accounting for some external constraints (like, what happens if somebody goofs and there are more than 9 connections? was what I figured the code was for, perhaps).
Use
t(A(i),1:length(r))=r; % (*)
should, I think, give you the result you're looking for...gotta' run, sorry.
(*) Which is Guillaume's loop below with the correction in my rush to make appointment I forgot the length() expression for column position and, of course, I later appended t to the first column whereas he's storing beginning with column 2.
Más respuestas (1)
Guillaume
el 16 de Mzo. de 2017
Editada: Guillaume
el 16 de Mzo. de 2017
Another method of obtaining the result, which works regardless of the values of the node ids, and whether or not a node is present in any triangle
%A: column vector of ids
[~, id] = ismember(B(:), A);
C = [A, accumarray(nonzeros(id), 1)]; %nonzero not required if all nodes are sure to be found in triangles
trigids = repmat((1:size(B, 1))', 1, size(B, 2));
triglist = accumarray(nonzeros(id), trigid(find(id)), [], @(list) {[list.', nan(1, 9-numel(list))]}); %again nonzeros and find(id) not needed if all nodes are sure to be found
triglist(cellfun(@isempty, triglist)) = {nan(1, 9)};
D = [A, cell2mat(triglist)]
Alternatively, D could be generated with a loop:
D = [A, nan(numel(A), 9)];
for rowid = 1:numel(A)
[trigid, ~] = find(B == A(rowid));
D(rowid, 2:numel(trigid)+1) = trigid;
end
4 comentarios
dpb
el 16 de Mzo. de 2017
"...why I then offered the loop option which may actually be faster, and certainly easier to understand."
Indeed, it dawned on me that the loop over the bins was equivalent to a direct loop over the array while writing the posted answer but had it tested and with the time constraint of an appointment in town decided better just leave good-enough alone.
Ver también
Categorías
Más información sobre Creating and Concatenating Matrices en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!