How to make cell array same length after padding zeros - matlab

This is data matrix having 2*159 cells
In the data matrix so many columns ( 2 vectors) having different length . I want to pad zeros which have the minimum length. Number of zeros should be
[max(length(Vector 1))-min(length(Vector 2))]
Now I want add zeros in the cell which have minimum length. and want to make length equal in each column if column have same length than no problem.

n = max(max(cellfun(#(x)size(x,2),data)))
cellfun(#(x)[x, zeros(1,n-numel(x))], data, 'uni', 0)
The above was finding one single max value to pad the cells to. I realise now that you actually want this max calculated on a per column basis:
n = max(cellfun(#(x)size(x,2),data))
cellfun(#(x,n)[x, zeros(1,n-numel(x))], data, repmat(num2cell(n),2,1), 'uni', 0)
At this point it might be more intuitive to just use a loop
for col = 1:size(data,2)
n = max(size(data{1,col},2),size(data{2,col},2));
for row = 1:2
x = data{row,col};
data{row,col} = [x, zeros(1,n-numel(x))];
end
end

Related

Create a submatrix using random columns and loop

I have a 102-by-102 matrix. I want to select square sub-matrices of orders from 2 up to 8 using random column numbers. Here is what I have done so far.
matt is the the original matrix of size 102-by-102.
ittr = 30
cols = 3;
for i = 1:ittr
rr = randi([2,102], cols,1);
mattsub = matt([rr(1) rr(2) rr(3)], [rr(1) rr(2) rr(3)]);
end
I have to extract matrices of different orders from 2 to 8. Using the above code I would have to change the mattsub line every time I change cols. I believe it is possible to do with another loop inside but cannot figure out how. How can I do this?
There is no need to extract elements of a vector and concatenate them, just use the vector to index a matrix.
Instead of :
mattsub = matt([rr(1) rr(2) rr(3)], [rr(1) rr(2) rr(3)]);
Use this:
mattsub = matt(rr, rr);
Defining a set of random sizes is pretty easy using the randi function. Once this is done, they can be projected along your iterations number N using arrayfun. Within the iterations, the randperm and sort functions can be used in order to build the random indexers to the original matrix M.
Here is the full code:
% Define the starting parameters...
M = rand(102);
N = 30;
% Retrieve the matrix rows and columns...
M_rows = size(M,1);
M_cols = size(M,2);
% Create a vector of random sizes between 2 and 8...
sizes = randi(7,N,1) + 1;
% Generate the random submatrices and insert them into a vector of cells...
subs = arrayfun(#(x)M(sort(randperm(M_rows,x)),sort(randperm(M_cols,x))),sizes,'UniformOutput',false);
This can work on any type of matrix, even non-squared ones.
You don't need another loop, one is enough. If you use randi to get a random integer as size of your submatrix, and then use those to get random column and row indices you can easily get a random submatrix. Do note that the ouput is a cell, as the submatrices won't all be of the same size.
N=102; % Or substitute with some size function
matt = rand(N); % Initial matrix, use your own
itr = 30; % Number of iterations
mattsub = cell(itr,1); % Cell for non-uniform output
for ii = 1:itr
X = randi(7)+1; % Get random integer between 2 and 7
colr = randi(N-X); % Random column
rowr = randi(N-X); % random row
mattsub{ii} = matt(rowr:(rowr+X-1),colr:(colr+X-1));
end

Matlab: construct a binary matrix satisfying horizontal and vertical constraints

I want to initiate a mxn binary matrix. The summation of each column of the matrix equals to a given value s(j), for j=1..n. In addition, the summation of each row of the matrix should be within the range of given bounds: lhs is dl(i) and rhs is du(i), for i=1..m.
Now I can only randomly generate binary columns, in each of which the sum of ones equals to s(j) of that column, such as the following codes.
xij = zeros(m,n);
for j=1:n
randRows=randperm(m); %a row vector containing a random permutation of the integers from 1 to m inclusive.
rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
xij(rowsWithOne,j)=1;
end
However, xij usually doesn't satisfy the horizontal constraints. I was thinking I should create a matrix first meets the row constraints lhs (lower bound) dl(i), then, column constraint s(j), and finally fill the offsets to meet rhs du(i), but I don't know how to implement it in Matlab. Is there any ideas to create xij?
Thanks in advance.
There are a couple things to first take into account, mainly if the problem can even be solved with the given constraints. First, you must check that the sum of s(j), sum(s) is greater than the sum of the lower bound constraints, sum(dl), and also less than the sum of the upper bound constraints, sum(du).
A simple if statement should be able to check this. After this has been done, the following code should be one solution to the problem, but given the nature of the problem, there will probably not be a unique solution.
%initialize counters
x = 1;
y = 1;
%make sure the lower bounds are first satisfied
for k = 1:nrows
while (dl(k) > 0)
if (s(y) > 0)
xij(k,y) = 1;
dl(k) = dl(k)-1;
du(k) = du(k)-1;
s(y) = s(y)-1;
end
y = y+1;
end
y = 1;
end
%make sure the columns all add to their specified values
for k = 1:ncols
while (s(k) > 0)
if (xij(x,k) == 0 && du(x) > 0)
xij(x,k) = 1;
du(x) = du(x)-1;
s(k) = s(k)-1;
end
x = x+1;
end
x = 1;
end
The first for loop adds 1s along the rows such that each row satisfies the minimum constraint. The next for loop adds 1s along the columns such that each column adds up to the desired value. The if statement in the first for loop ensures that a 1 isn't added if that column has already reached its desired value, and the if statement in the second for loop ensures that a 1 isn't added to a row that would put it over the maximum value of the row.
In order to keep track of the amount of ones, the du is lowered by 1 every time a 1 is added to the corresponding row, and likewise the desired value s(j) is subtracted by 1 every time a 1 is added to that column of the xij matrix.
%Create an initial xij matrix, each column of which consists of a random binary xij sequence, but sum of ones in each column equals to sj
Init_xij = zeros(nShift,nCombo);
for j=1:nCombo
randRows=randperm(nShift); %a row vector containing a random permutation of the integers from 1 to nShift inclusive.
rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
Init_xij(rowsWithOne,j)=1;
end
%Adjust the initial xij matrix to make it feasible, satisfying horizontal
%LHS (dli) and RHS (dui) constraints
Init_xij_Feasible=Init_xij;
k=1;
while k
RowSum=sum(Init_xij_Feasible,2); %create a column vector containing the sum of each row
CheckLB=lt(RowSum,dli); %if RowSum <dli, true
CheckUB=gt(RowSum,dui); %if RowSum >dui, true
if ~any(CheckLB)&&~any(CheckUB) %if any element in CheckLB and CheckUB is zero
break,
else
[~,RowIdxMin]=min(RowSum);
[~,RowIdxMax]=max(RowSum);
ColIdx=find(Init_xij_Feasible(RowIdxMax,:) & ~Init_xij_Feasible(RowIdxMin,:),1); % returns the first 1 column index corresponding to the nonzero elements in row RowIdxMax and zero elements in row RowIdxMin.
%swap the min and max elements
[Init_xij_Feasible(RowIdxMin,ColIdx),Init_xij_Feasible(RowIdxMax,ColIdx)]=deal(Init_xij_Feasible(RowIdxMax,ColIdx),Init_xij_Feasible(RowIdxMin,ColIdx));
end
k=k+1;
end

How to remove the unconnected nodes from an adjacency matrix?

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.

how to check the values of each variables from a resultant matrix in matlab?

I have sum of 3 cell arrays
A=72x1
B=72x720
C=72x90
resultant=A+B+C
size of resultant=72x64800
now when I find the minimum value with row and column indices I can locate the row element easily but how can I locate the column element in variables?
for example
after dong calculations for A,B,C I added them all and got a resultant in from of <72x(720x90)> or can say a matrix of integers of size <72x64800> then I found the minimum value of resultant with row and column index using the code below.
[minimumValue,ind]=min(resultant(:));
[row,col]=find(result== minimumValue);
then row got 14 and column got 6840 value..
now I can trace row 14 of all A,B,C variables easily but how can I know that the resultant column 6480 belongs to which combination of A,B,C?
Instead of using find, use the ind output from the min function. This is the linear index for minimumValue. To do that you can use ind2sub:
[r,c] = ind2sub(size(resultant),ind);
It is not quite clear what do you mean by resultant = A+B+C since you clearly don't sum them if you get a bigger array (72x64800), on the other hand, this is not a simple concatenation ([A B C]) since this would result in a 72x811 array.
However, assuming this is a concatenation you can do the following:
% get the 2nd dimension size of all matrices:
cols = cellfun(#(x) size(x,2),{A,B,C})
% create a vector with reapiting matrices names for all their columns:
mats = repelem(['A' 'B' 'C'],cols);
% get the relevant matrix for the c column:
mats(c)
so mats(c) will be the matrix with the minimum value.
EDIT:
From your comment I understand that your code looks something like this:
% arbitrary data:
A = rand(72,1);
B = rand(72,720);
C = rand(72,90);
% initializing:
K = size(B,2);
N = size(C,2);
counter = 1;
resultant = zeros(72,K*N);
% summing:
for k = 1:K
for n = 1:N
resultant(:,counter) = A + B(:,k) + C(:,n);
counter = counter+1;
end
end
% finding the minimum value:
[minimumValue,ind] = min(resultant(:))
and from the start of the answer you know that you can do this:
[r,c] = ind2sub(size(resultant),ind)
to get the row and column of minimumValue in resultant. So, in the same way you can do:
[Ccol,Bcol] = ind2sub([N,K],c)
where Bcol and Ccol is the column in B and C, respectively, so that:
minimumValue == A(r) + B(r,Bcol) + C(r,Ccol)
To see how it's working imagine that the loop above fills a matrix M with the value of counter, and M has a size of N-by-K. Because we fill M with a linear index, it will be filled in a column-major way, so the row will correspond to the n iterator, and the column will correspond to the k iterator. Now c corresponds to the counter where we got the minimum value, and the row and column of counter in M tells us the columns in B and C, so we can use ind2sub again to get the subscripts of the position of counter. Off course, we don't really need to create M, because the values within it are just the linear indices themselves.

delete certain columns of matrix when number of zero elements exceeds threshold avoiding loop

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))].