Finding and counting numbers from one matrix in another
5 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
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 commentaires
Réponse acceptée
dpb
le 15 Mar 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 commentaires
Meghan Rochford
le 16 Mar 2017
Modifié(e) : Meghan Rochford
le 16 Mar 2017
dpb
le 16 Mar 2017
Modifié(e) : dpb
le 16 Mar 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.
Plus de réponses (1)
Guillaume
le 16 Mar 2017
Modifié(e) : Guillaume
le 16 Mar 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 commentaires
dpb
le 16 Mar 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.
Voir également
Catégories
En savoir plus sur Creating and Concatenating Matrices dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!