I want to efficiently delete a lot of data from the beginning of a matrix of dimension 2*n. The matrix looks like this:
x1 x2
x3 x4
...
...
I want to delete all rows that have the the first element of a row that is smaller than some number and stop when a row isn't smaller (the elements are in numerical order)
What I do at the moment is slow:
while 1
if list{i}(1) <= someNumber
list{i}(1,:) = []
else
break;
end
end
There must be a neat way of doing this quickly in MATLAB?
Thank you.
One way is to just compare the entire first column in one go and then delete, i.e.
rows2delete = list{i}(:,1) <= someNumber; %# creates logical array with 1 for deletion
list{i}(rows2delete,:) = []; %# delete some rows, all corresponding cols
Related
I have an adjacency matrix(n*n) of 1's and 0's extracted from an unweighted and undirected graph, my goal is to remove all-zeros columns from this matrix and their corresponding rows which are not connected to any node from the graph.
I want to apply one algorithm by using this adjacency matrix but sadly NaN produces because of some columns in this matrix are all 0's. So, i only need the connected components.
fid= fopen('file.txt','rt');
format = repmat('%q',[1 2]);
filee= textscan(fid,format,'Delimiter', '\t');
fclose(fid);
AA2= [filee{:, 1} , filee{:, 2}];
[nodenames, ~, id] = unique(AA2(:));
Adjacency_Matrix= accumarray(reshape(id, size(AA2)), 1, [numel(nodenames), numel(nodenames)]);
Adjoint2 = sum(Adjacency_Matrix~=0,1);
https://drive.google.com/file/d/0B6u8fZadKIp2OFd2X1NrZEdIclU/view
By this command Adjoint2 = sum(Adjacency_Matrix3~=0,1); I can know how many 1's i have in every column. In this matrix, some columns had no 1's, and so don't want them.
As the matrix is (NN) i want to get a (mm) matrix with columns that has only the 1's.
You can use any function:
If the matrix is symmetric you can do this to remove both zero columns and rows:
idx = any(Adjacency_Matrix);
result = Adjacency_Matrix(idx,idx);
else you can generate indexes of both columns and rows:
idx_column = any(Adjacency_Matrix);
idx_row = any(Adjacency_Matrix,2);
Here you can remove both columns and rows
result = Adjacency_Matrix(idx_row, idx_column)
If you want to remove only columns use this:
result = Adjacency_Matrix(:, idx_column)
If you want to remove only rows use this:
result = Adjacency_Matrix(idx_row, :)
This is going to be a brute force solution, since you are using an adjacency matrix. You will have to loop through all of the rows of the matrix and determine which ones are empty, and create a new adjacency matrix from these rows, omitting the correct columns.
You can use the following code:
i = 1;
while(i<=length(A))
if(sum(A(i,:)) == 0 && sum(A(:,i)) == 0)
% node i is isolated
A(:,i) = []; % remove its related column
A(i,:) = []; % remove its related row
else
i = i + 1;
end
end
If sum of elements of a row and respected column is zero, it means this node is isolated. Therefore, you can remove its related row and column.
for i = 1:6
if data(i,1) == 1
disp(i)
m(i,:) = data(i,:)
end
end
The code above returns a matrix m, with rows of data from the data file.
However, data(i,1) == 1 is true 4 times for the particular data, however m has 6 rows. 2 of the rows of m are just full of 0's, but the if statement is only true 4 times.
Why is that happening?
In answer to "why is that happening", it is because your matrices are the same size, but you only assign values to the rows which satisfy a condition. Therefore leaving other rows as 0s.
You either need a way to build m row by row (see end of this post) or create it in another way (my answer).
You can do this with logical indexing
% For creating m
m = data(data(:, 1) == 1, :);
% For displaying which indices satisfy your condition, one call to disp
disp( find(data(:, 1) == 1) )
Breaking this down, m is assigned to the values of data, where the column 1 of data is equal to 1, and all of the columns.
find returns the index of any non-zero element. The logical indexing returns an array of 0s and 1s, so all elements which satisfy the condition (and are 1) will be indexed by find.
You could also create the logical index and use it twice, better for maintenance at a later date if your condition changes:
% create logical index
idx = ( data(:,1) == 1 );
% same as above but using idx
m = data(idx, :);
disp( find(idx) )
Documentation
Logical indexing - https://uk.mathworks.com/help/matlab/matlab_prog/find-array-elements-that-meet-a-condition.html
find - https://uk.mathworks.com/help/matlab/ref/find.html
#Ander's suggestion to append only certain rows will work, and demonstrates well how to build a matrix. However, in this case you do not need your loop and if condition at all.
This is standard MATLAB.
Lets assume data(1,1) and data(3,1) are 1.
Then m(1,:)=data(1,:) and later m(3,:)=data(3,:). But what about m(2,:) It has to exist, because you filled m(3,:). There is no 3 without 2!
If you want m to have only the ones where data(i,1) == 1 then do:
m=[]; %create empty matrix
for i = 1:6
if data(i,1) == 1
disp(i)
m= [m; data(i,:)]; % "append" to m
end
end
So this is my code:
in=-8:8;
%calculate z
[h,k,l]=meshgrid(in);
z = (h.^2 + k.^2 + l.^2);
%sort absolute values ascending, which allows to use unique
ac=sort(abs([h(:) k(:) l(:)]),2);
%use unique to identify duplicates
[f,g,p]=unique(ac,'rows');
%count
cnt=histc(p,1:max(p));
% create a matrix with all vectors
disp([h(g),k(g), l(g),z(g),cnt])
i just want to delete or terminate rows containing z>59, i can't used break because it only works in for loop or while loop, so what other command may i used? thanks.
I'd guess you want this:
%// your output matrix you want to filter
output = [h(g),k(g), l(g),z(g),cnt];
%// delete rows containing z > 59 (z is the 4th column)
filtered_output = output(output(:,4) <= 59,:)
I have a quite big (107 x n) matrix X. Within these n columns, each three columns belong to each other. So, the first three columns of matrix X build a block, then columns 4,5,6 and so on.
Within each block, the first 100 row elements of the first column are important X(1:100,1:3:end). Whenever in this first column the number of zeros or NaNs is greater or equal 20, it should delete the whole block.
Is there a way to do this without a loop?
Thanks for any advice!
Assuming the number of columns of the input to be a multiple of 3, there could be two approaches here.
Approach #1
%// parameters
rl = 100; %// row limit
cl = 20; %// count limit
X1 = X(1:rl,1:3:end) %// Important elements from input
match_mat = isnan(X1) | X1==0 %// binary array of matches
match_blk_id = find(sum(match_mat)>=cl) %// blocks that satisfy requirements
match_colstart = (match_blk_id-1).*3+1 %// start column indices that satisfy
all_col_ind = bsxfun(#plus,match_colstart,[0:2]') %//'columns indices to be removed
X(:,all_col_ind)=[] %// final output after removing to be removed columns
Or if you prefer "compact" codes -
X1 = X(1:rl,1:3:end);
X(:,bsxfun(#plus,(find(sum(isnan(X1) | X1==0)>=cl)-1).*3+1,[0:2]'))=[];
Approach #2
X1 = X(1:rl,1:3:end)
match_mat = isnan(X1) | X1==0 %// binary array of matches
X(:,repmat(sum(match_mat)>=cl,[3 1]))=[] %// Find matching blocks, replicate to
%// next two columns and remove them from X
Note: If X is not a multiple of 3, use this before using the codes - X = [X zeros(size(X,1) ,3 - mod(size(X,2),3))].
Hi I have problem with matrix..
I have many .txt files with different number of rows but have the same number of column (1 column)
e.g. s1.txt = 1234 rows
s2.txt = 1200 rows
s2.txt = 1100 rows
I wanted to combine the three files. Since its have different rows .. when I write it to a new file I got this error = Index exceeds matrix dimensions.
How I can solved this problem? .
You can combine three matrices simply by stacking them: Assuming that s1, etc are the matrices you read in, you can make a new one like this:
snew = [s1; s2; s3];
You could also use the [] style stacking without creating the new matrix variable if you only need to do it once.
You have provided far too little information for an accurate diagnosis of your problem. Perhaps you have loaded the data from your files into variables in your workspace. Perhaps s1 has 1 column and 1234 rows, etc. Then you can concatenate the variables into one column vector like this:
totalVector = [s1; s2; s3];
and write it out to a file with a save() statement.
Does that help ?
Let me make an assumption that this question is connecting with your another question, and you want to combine those matrices by columns, leaving empty values in columns with fewer data.
In this case this code should work:
BaseFile ='s';
n=3;
A = cell(1,n);
for k=1:n
A{k} = dlmread([BaseFile num2str(k) '.txt']);
end
% create cell array with maximum number of rows and n number of columns
B = cell(max(cellfun(#numel,A)),n);
% convert each matrix in A to cell array and store in B
for k=1:n
B(1:numel(A{k}),k) = num2cell(A{k});
end
% save the data
xlswrite('output.txt',B)
The code assumes you have one column in each file, otherwise it will not work.