Removing columns from a Matrix MatLab - matlab

[1 2 3 4 5 6 7 8 9 ;
9 8 7 6 5 4 3 2 1 ;
1 2 0 0 1 0 0 0 1 ]
The last row has five columns with zeros. I would like to keep only one column per zero crossing.
like this
[1 2 3 5 8 9 ;
9 8 7 5 2 1 ;
1 2 0 1 0 1 ]
Is this possible with fast Matlab functions or do I have to write some slow complicated for loop ?

You can create a logical array many different ways to find the columns to remove. Something like this would work
% Find the zeros that are not the first zero
cols_to_remove = data(end,:) == 0 & ~diff([false, data(end,:) == 0]) == 1;
% Now remove them
data(:, cols_to_remove) = [];

Related

What algorithm is used when rows in tables are sorted?

Let's assume that we have a table with two columns. The table contains data and our goal is to sort that table.
Assume our data looks like this, where y1 and y2 are the data in the columns.
You can produce that plot with MATLAB or GNU Octave.
% Simulate the model
[t,y] = ode45(#odefunc,[0 20],[1; -2]);
% Plot the simulation
close all
plot(t,y(:,1),'-r',t,y(:,2),'-b')
title('Solution of van der Pol Equation (\mu = 1) with ODE45');
xlabel('Time t');
ylabel('Solution y');
legend('y_1','y_2')
grid on
function dydt = odefunc(t,y)
dydt = [y(2); (1-0.1*y(1)^2)*y(2)-y(1) + 1];
end
If we look above the plot, we are going to se the data like this:
You can create that plot with this code:
% Plot 3D bar
figure
imagesc(y)
colorbar
Here we can see that the plot have a very much like a "table-look". My question is what algorithm is used when sorting the rows in the table so every row that looks almost the same, have it's own unique position in the table.
For example, if we have a table like this.
0 2 4
1 3 5
2 4 6
3 5 7
4 6 8
5 7 9
0 2 4
1 3 5
2 4 6
3 5 7
4 6 8
5 7 9
0 2 4
1 3 5
2 4 6
3 5 7
4 6 8
5 7 9
0 2 4
1 3 5
The code if you want to create that table.
j = 0;
rows = 20;
for i = 1:rows
disp(sprintf("%i %i %i", j, j+2, j+4))
j = j + 1;
if(j + 4 >= 10)
j = 0;
end
end
We can see that there are four rows of 0 2 4 and three rows of 5 7 9.
I want all rows 0 2 4 close to each other and all rows 5 7 9 close to each other. And.... 0 2 4 cannot be after 5 7 9 because then the plot would look terrible.
For example, assume that we begining with row 1, the first row 0 2 4. Then we are looking for the same rows of 0 2 4 and let's say we found four rows 0 2 4. Then we sort them.
0 2 4
0 2 4
0 2 4
0 2 4
Now next row would be 1 3 5 and we find two rows of 1 3 5. We sorting them.
0 2 4
0 2 4
0 2 4
0 2 4
1 3 5
1 3 5
After we have sorted for a while, we are going to have a table like this.
0 2 4
0 2 4
0 2 4
0 2 4
1 3 5
1 3 5
2 4 6
2 4 6
2 4 6
2 4 6
3 5 7
3 5 7
3 5 7
.
.
.
.
5 7 9
5 7 9
5 7 9
And now, we found 1 2 4, which is very similar to 0 2 4. So we need to place 1 2 4 close to 0 2 4, perhaps between 0 2 4 or 1 3 5 or after 0 2 4 or before 0 2 4. How do I even know that 1 2 4 should be placed close to 0 2 4? That's the issue!!!.
How can I sort that?
I need to do that in C-programming language because speed is most important here, but I think I will start to do it in GNU Octave. I'm pretty sure that there is a SQL-sorting algorithm I'm looking for.
Notice in practice, there are numbers, integers, 10-bit e.g values between 0-1023.

Bin interaction frequencies

I have 10 bins, and each bin contains a specific number of observations, e.g.:
a = [0,0,1,0,0,2,0,0,0,2]
I'd like to subsequently tally how many times any given pair of (non-zero) bins co-occur - based on the number of observations.
Given the above example, bin#3 = 1, bin#6 = 2 and bin#10 = 2.
This means that bin 3 and 6 co-occurred once, bin 3 and 10 co-occurred once, and bin 6 and 10 co-occurred twice (the minimum value of the pair is taken).
My desired output is a full matrix, listing every possible bin combination (columns 1-2) and the tally of what was observed (column 3):
1 2 0
1 3 0
1 4 0
1 5 0
1 6 0
1 7 0
1 8 0
1 9 0
1 10 0
2 3 0
2 4 0
2 5 0
2 6 0
2 7 0
2 8 0
2 9 0
2 10 0
3 4 0
3 5 0
3 6 1
3 7 0
3 8 0
3 9 0
3 10 1
4 5 0
4 6 0
4 7 0
4 8 0
4 9 0
4 10 0
5 6 0
5 7 0
5 8 0
5 9 0
5 10 0
6 7 0
6 8 0
6 9 0
6 10 2
7 8 0
7 9 0
7 10 0
8 9 0
8 10 0
9 10 0
Is there a short and/or fast way of doing this?
You can get all combinations of the bin numbers in many ways. I'll use combvec for ease.
Then it's relatively simple to vectorise this using min...
a = [0,0,1,0,0,2,0,0,0,2];
n = 1:numel(a);
% Use unique and sort to get rid of duplicate pairs when order doesn't matter
M = unique( sort( combvec( n, n ).', 2 ), 'rows' );
% Get rid of rows where columns 1 and 2 are equal
M( M(:,1) == M(:,2), : ) = [];
% Get the overlap count for bins
M( :, 3 ) = min( a(M), [], 2 );
Try this.
bin_output = [....];
bin_matrix = [0,0,1,0,0,2,0,0,0,2];
bin_nonzero = find(bin_matrix);
for j = 1:length(bin_nonzero);
if isequal(j,length(bin_nonzero))
break;
end
for k = (j+1):(length(bin_nonzero))
for m = 1:length(bin_output)
if isequal(bin_output(m,1),j) && isequal(bin_output(m,2),k)
bin_output(m,3) = bin_output(m,3) + min([bin_matrix(1,bin_nonzero(1,j)),bin_matrix(1,bin_nonzero(1,k))]);
end
end
end
end

Dividing a vector to form different matrices

I have a two long vector. Vector one contains values of 0,1,2,3,4's, 0 represent no action, 1 represent action 1 and 2 represent the second action and so on. Each action is 720 sample point which means that you could find 720 consecutive twos then 720 consecutive 4s for example. Vector two contains raw data corresponding to each action. I need to create a matrix for each action ( 1, 2, 3 and 4) which contains the corresponding data of the second vector. For example matrix 1 should has all the data (vector 2 data) which occurred at the same indices of action 1. Any Help??
Example on small amount of data:
Vector 1: 0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2
Vector 2: 6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0
Result:
Matrix 1:
5 6 4
0 5 6
Matrix 2:
9 8 7
5 8 0
Here is one approach. I used a cell array to store the output matrices, hard-coding names for such variables isn't a good plan.
V1=[0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2]
V2=[6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0]
%// Find length of sequences of 1's/2's
len=find(diff(V1(find(diff(V1)~=0,1)+1:end))~=0,1)
I=unique(V1(V1>0)); %// This just finds how many matrices to make, 1 and 2 in this case
C=bsxfun(#eq,V1,I.'); %// The i-th row of C contains 1's where there are i's in V1
%// Now pick out the elements of V2 based on C, and store them in cell arrays
Matrix=arrayfun(#(m) reshape(V2(C(m,:)),len,[]).',I,'uni',0);
%// Note, the reshape converts from a vector to a matrix
%// Display results
Matrix{1}
Matrix{2}
Since, there is a regular pattern in the lengths of groups within Vector 1, that could be exploited to vectorize many things while proposing a solution. Here's one such implementation -
%// Form new vectors out of input vectors for non-zero elements in vec1
vec1n = vec1(vec1~=0)
vec2n = vec2(vec1~=0)
%// Find positions of group shifts and length of groups
df1 = diff(vec1n)~=0
grp_change = [true df1]
grplen = find(df1,1)
%// Reshape vec2n, so that we end up with N x grplen sized array
vec2nr = reshape(vec2n,grplen,[]).' %//'
%// ID/tag each group change based on their unique vector 2 values
[R,C] = sort(vec1n(grp_change))
%// Re-arrange rows of reshaped vector2, s.t. same ID rows are grouped succesively
vec2nrs = vec2nr(C,:)
%// Find extents of each group & use those extents to have final cell array output
grp_extent = diff(find([1 diff(R) 1]))
out = mat2cell(vec2nrs,grp_extent,grplen)
Sample run for the given inputs -
>> vec1
vec1 =
0 0 1 1 1 0 0 2 2 2 ...
0 0 1 1 1 0 0 2 2 2
>> vec2
vec2 =
6 7 5 6 4 6 5 9 8 7 ...
9 7 0 5 6 4 1 5 8 0
>> celldisp(out)
out{1} =
5 6 4
0 5 6
out{2} =
9 8 7
5 8 0
Here is another solution:
v1 = [0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2];
v2 = [6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0];
m1 = reshape(v2(v1 == 1), 3, [])'
m2 = reshape(v2(v1 == 2), 3, [])'
EDIT: David's solution is more flexible and probably more efficient.

matlab adjacency list to adjacency matrix

How to convert adjacency list to adjacency matrix via matab
For example: Here is the adjacency list(undirected), the third column is the weight.
1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7
++++++++++++++++++++++
that should be converted to:
1 2 3 4 5
1 0 4 5 0
2 3 4 7 8
3 4 7 0 0
4 0 7 0 0
5 0 8 0 0
You can use sparse matrix. Let rows be the first column, cols the second, and s the weight.
A = sparse([rows; cols],[cols; rows],[s; s]);
If you want to see the matrix. use full().
UPDATE:
I made the answer a bit simpler (everything in one line, instead of adding the transposed, and included explanations, as requested:
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
rows = list(:,1)
cols = list(:,2)
s = list(:,3)
Now, rows, cols and s contains the needed information. Sparse matrices need three vectors. Each row of the two first vectors, rows and cols is the index of the value given in the same row of s (which is the weight).
The sparse command assigns the value s(k) to the matrix element adj_mat(rows(k),cols(k)).
Since an adjacency matrix is symmetric, A(row,col) = A(col,row). Instead of doing [rows; cols], it is possible to first create the upper triangular matrix, and then add the transposed matrix to complete the symmetric matrix.
A = sparse([rows; cols],[cols; rows],[s; s]);
full(A)
A =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0
It's really hard to tell what your'e asking. Is this right?
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
matrix = zeros(max(max(list(:, 1:2)))); %// Or just zeros(5) if you know you want a 5x5 result
matrix(sub2ind(size(matrix), list(:,1), list(:,2))) = list(:,3); %// Populate the upper half
matrix = matrix + matrix' %'// Find the lower half via symmetry
matrix =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0

How can you remove matrix rows in Matlab based on some criteria?

In Matlab, how can I remove spesific rows from a matrix I require? If for example I would like to remove all rows from a matrix which contain a spesific value (like 0 or NaN)?
Let's say you have A
A = [1 2 3;4 5 0; 7 8 9; 10 NaN 12]
A =
1 2 3
4 5 0
7 8 9
10 NaN 12
Then, you can choose the rows as follows:
any(isnan(A'))
ans =
0 0 0 1
To delete those NaN-containing rows, you can do:
A(any(isnan(A')),:) = []
A =
1 2 3
4 5 0
7 8 9
You can choose 0-containing rows by any(A' == 0). If you want all elements to be 0s or NaNs, then you can use all instead of any.