Inserting zero rows and columns into matrix efficiently
2 views (last 30 days)
Show older comments
I'm currently working on a project where I have a large set of matrices of varying size. Each matrix, A, has a vector, pointer, which corresponds to location information. I'm trying to get all the matrices into the same "space"; to achieve this, I am looking to create a "master" matrix, M, which has all the elements of A expanded to the larger matrix, which has location data for all matrices in the set. I have already created a master pointer, pointer_master, which contains the locations found in all matrices.
I'm trying to create two matrices using the original matrix, A, pointer, and pointer_master. The first matrix is the "occurrence" matrix, O, which shows you what elements from A appear in the large matrix M. I have already done this by using the function setdiff to find the missing elements
Code:
% This code compares pointer_master to pointer and creates
% a logical matrix O which sets all missing indices to 0.
pointer_master = 1:25;
pointer = [1 4 8 10 11 12 13 14 15 17 21 23 25];
[~, pointer_missingIndex] = setdiff(pointer_master,pointer);
O = true(length(pointer_master));
O(:,pointer_missingIndex) = false;
O(pointer_missingIndex,:) = false;
Here we have a pointer that is missing 12 elements from the master pointer. The code above creates a new large matrix O, with 0 in place of these missing elements. When this process is complete, I intend to sum these matrices to get the frequency of each element (I also want to average across elements using this matrix).
I'm having trouble figuring out how to create the master matrix. Unlike the occurence matrix, I need the elements of A to appear in M with all its elements. I can do this inefficiently, but I'm sure there is a better way to do this than what I have right now.
Code:
M = A;
for ii = 1:length(pointer_master)
X = find(pointer==pointer_master(ii), 1);
if(isempty(X))
column_insert = zeros(size(M,2),1); %#ok<NASGU>
row_insert = zeros(1,size(M,2)+1); %#ok<NASGU>
if(pointer_master(ii)<min(pointer))
column_insert = zeros(size(M,2),1);
row_insert = zeros(1,size(M,2)+1);
M = [logical(column_insert) M]; %#ok<AGROW>
M = [logical(row_insert); M]; %#ok<AGROW>
elseif(pointer_master(ii)>max(pointer))
column_insert = zeros(size(M,2),1);
row_insert = zeros(1,size(M,2)+1);
M = [logical(column_insert) M]; %#ok<AGROW>
M = [logical(row_insert); M]; %#ok<AGROW>
else
column_insert = zeros(size(M,2),1);
row_insert = zeros(1,size(M,2)+1);
M = [M(:,1:N) logical(column_insert) M(:,N+1:end)];
M = [M(1:N,:); logical(row_insert); M(N+1:end,:)];
end
else
N = ii;
end
end
I know this method is very inefficient, especially for matrices with 20,000+ elements, so I'm trying to figure out how to do this faster. I can use ismember to output a vector that tells you where pointer falls in pointer_master. but I don't know how to get the elements from A into M.
Code:
[~,X] = ismember(pointer_master,pointer);
Does anyone have any experience with this? Thanks.
For example:
A = [1 2 3; 4 5 6; 7 8 9];
pointer = [1 3 4];
pointer_master = 1:5;
My occurrence matrix would be:
O = [1 0 1 1 0; 0 0 0 0 0; 1 0 1 1 0; 1 0 1 1 0; 0 0 0 0 0];
My master matrix M would be:
M = [1 0 2 3 0; 0 0 0 0 0; 4 0 5 6 0; 7 0 8 9 0; 0 0 0 0 0];
3 Comments
Accepted Answer
Andrei Bobrov
on 7 May 2012
A = [1 2 3; 4 5 6; 7 8 9];
pointer = [1 3 4];
pointer_master = 1:5;
p = ismember(pointer_master,pointer);
M = bsxfun(@and,p,p')+0;
M(M~=0)=A;
0 Comments
More Answers (3)
Richard Brown
on 7 May 2012
Perhaps I'm misunderstanding, but your example can be generated from the following
M = zeros(numel(pointer_master));
M(pointer,pointer) = A;
If the number of elements in pointer is much fewer than the number of elements of pointer_master, you may well want to use a sparse matrix:
n = numel(pointer_master);
[I, J] = ndgrid(pointer);
M = sparse(I, J, A, n, n);
Jan
on 7 May 2012
I do not understand what you are looking for. But I have a general advice when I see "%#ok<AGROW>". Don't do this. Either pre-allocate the required size and fill in the data afterwards. Or pre-allocate to much memory and cut off the unneeded part at the end.
This wastes time also:
column_insert = zeros(size(M,2),1);
row_insert = zeros(1,size(M,2)+1);
M = [M(:,1:N) logical(column_insert) M(:,N+1:end)];
At first "false()" is faster than "logical(zeros())". But I assume this would be even faster:
M(:, N+2:end+1) = M(:,N+1:end);
M(:, N+1) = 0;
I have the impression that you mix DOUBLEs and LOGICALs in the matrix M. If so, don't do it.
0 Comments
Effrom
on 7 May 2012
2 Comments
Richard Brown
on 8 May 2012
Glad to hear you got it sorted. I'm puzzled as to why the bsxfun version works differently for you - on my system both methods use exactly the same amount of memory (the amount of memory required to store both A and M as doubles).
See Also
Categories
Find more on Operating on Diagonal Matrices in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!