Deleting elements from array in Matlab - arrays

Given,
a = [2 4 6 8 10 0 7 18 9 0 8 2 0 5];
b = [1 3 0 5 70 8 6 87 1 9 7 8 0 2];
I am trying to delete elements (in both 'a' & 'b') that corresponds
to '0' or less than '0' in either 'a' or 'b' i.e., I want
% a = [2 4 8 10 7 18 9 8 2 5];
% b = [1 3 5 70 6 87 1 7 8 2];
I am trying like this -
n = length(b);
a1 = [];
b1 = [];
for k = 1:n
if a(n) <= 0 || b(n) <= 0
a1 = [a; a(a > 0)] % eliminates 0 from a
b1 = [b; b(b > 0)] % eliminates 0 from b
end
end
Any help will be very helpful.

Use find:
a = [2 4 6 8 10 0 7 18 9 0 8 2 0 5];
b = [1 3 0 5 70 8 6 87 1 9 7 8 0 2];
A = a( find( a > 0 & b > 0 ) );
B = b( find( a > 0 & b > 0 ) );
or even faster:
C = a( a > 0 & b > 0 );
D = b( a > 0 & b > 0 );
returns:
C =
2 4 8 10 7 18 9 8 2 5
D =
1 3 5 70 6 87 1 7 8 2
If you can be sure, that there are no values below zero you could also use:
E = a( logical(a) & logical(b) );
F = b( logical(a) & logical(b) );
which is a little faster, but containing also negative values.

The efficient and compact way to do this is to first create the relevant index, that prevents double calculation:
idx = a>0 & b>0
a = a(idx);
b = b(idx);

Related

MATLAB : How to construct block bi-diagonal matrix from input arguments [duplicate]

I have a matrix B and I want to obtain a matrix C of dimension (L+k)*m by L*n. L and k are input values. B0 , B1 , ... , Bk has size m by n.
For example :
If I have a matrix B = [1 1 ; 1 1 ; 1 1] with B0 = [1 1], B1 = [1 1] and B2 = [1 1], and each B0 , B1 , B2 of dimension 1 by 2 with k = 2 and L = 4.
Then the matrix C obtained is given by C = [1 1 0 0 0 0 0 0 ; 1 1 1 1 0 0 0 0 ; 1 1 1 1 1 1 0 0 ; 0 0 1 1 1 1 1 1 ; 0 0 0 0 1 1 1 1 ; 0 0 0 0 0 0 1 1] and of dimension
6 by 8.
I would like to generalize my program for any size matrix B.
My program solves the problem for B = [1 1 ; 1 1 ; 1 1] with m = 1 , n = 2 , k = 2 and L = 4.
My code :
clc;
clear;
k = 2;
L = 4;
B = [1 1 ; 1 1 ; 1 1];
B0 = [1 1];
B1 = [1 1];
B2 = [1 1];
m = size(B0,1);
n = size(B0,2);
c = [B ; zeros(size(B))];
C = zeros((L+k)*m,L*n);
for i = 1:L
C(:,2*i-1:2*i) = circshift(c,i-1,1);
end
Result : C =
1 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 1 1 0 0
0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1
I have difficulties to generalize for any given matrix B and for any value of k and L.
Any suggestions?
B = [1 2 3; 4 5 6; 7 8 9; 100 110 120; 130 140 150; 160 170 180]; % input
L = 4; % input
k = 2; % input
m = size(B,1)/(k+1); % obtain m
n = size(B,2); % obtain n
C = zeros((L-1)*m+1, (L-1)*n+1); % initiallize result
C(1:((L-1)*m+1)*n+m:end) = 1; % each 1 marks the upper-left corner for a copy of B
C = conv2(C, B); % insert copies of B, extending size
The second-to-last line uses linear indexing. The last line applies two-dimensional convolution. The result in this example is
B =
1 2 3
4 5 6
7 8 9
100 110 120
130 140 150
160 170 180
C =
1 2 3 0 0 0 0 0 0 0 0 0
4 5 6 0 0 0 0 0 0 0 0 0
7 8 9 1 2 3 0 0 0 0 0 0
100 110 120 4 5 6 0 0 0 0 0 0
130 140 150 7 8 9 1 2 3 0 0 0
160 170 180 100 110 120 4 5 6 0 0 0
0 0 0 130 140 150 7 8 9 1 2 3
0 0 0 160 170 180 100 110 120 4 5 6
0 0 0 0 0 0 130 140 150 7 8 9
0 0 0 0 0 0 160 170 180 100 110 120
0 0 0 0 0 0 0 0 0 130 140 150
0 0 0 0 0 0 0 0 0 160 170 180
In addition to #LuisMendo's answer:
If size(B,1)/(k+1) do not produce an integer, then his solution can fail.
I would suggest to create the C matrix with sparse():
n = size(B,2)
C = full(sparse(1:k:k*L,1:n:n*L,1))
So the whole code become:
B = ones(7,3); % An input matrix that will produce an error with the linear indexing solution.
L = 6; % number of repetition
k = 2; % row-shift
n = size(B,2); % obtain n
C = full(sparse(1:k:k*L,1:n:n*L,1)); % Create C using full(sparse())
C = conv2(C, B) % insert copies of B, extending size
(all credits goes to LuisMendo for the idea)
This solution as #obchardon's answer uses sparse but unlike the #LuisMendo's answer doesn't use conv2. Indices of blocks are computed and used in sparse to form the desired matrix.
[row col] = find(true(size(B)));
ROW = row + (0:L-1)*k;
COL = col + (0:L-1)*size(B,2);
C = sparse (ROW, COL, repmat (B, 1, L));

Expanding a matrix diagonally with Matlab

I have a matrix B and I want to obtain a matrix C of dimension (L+k)*m by L*n. L and k are input values. B0 , B1 , ... , Bk has size m by n.
For example :
If I have a matrix B = [1 1 ; 1 1 ; 1 1] with B0 = [1 1], B1 = [1 1] and B2 = [1 1], and each B0 , B1 , B2 of dimension 1 by 2 with k = 2 and L = 4.
Then the matrix C obtained is given by C = [1 1 0 0 0 0 0 0 ; 1 1 1 1 0 0 0 0 ; 1 1 1 1 1 1 0 0 ; 0 0 1 1 1 1 1 1 ; 0 0 0 0 1 1 1 1 ; 0 0 0 0 0 0 1 1] and of dimension
6 by 8.
I would like to generalize my program for any size matrix B.
My program solves the problem for B = [1 1 ; 1 1 ; 1 1] with m = 1 , n = 2 , k = 2 and L = 4.
My code :
clc;
clear;
k = 2;
L = 4;
B = [1 1 ; 1 1 ; 1 1];
B0 = [1 1];
B1 = [1 1];
B2 = [1 1];
m = size(B0,1);
n = size(B0,2);
c = [B ; zeros(size(B))];
C = zeros((L+k)*m,L*n);
for i = 1:L
C(:,2*i-1:2*i) = circshift(c,i-1,1);
end
Result : C =
1 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 1 1 1 0 0
0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1
I have difficulties to generalize for any given matrix B and for any value of k and L.
Any suggestions?
B = [1 2 3; 4 5 6; 7 8 9; 100 110 120; 130 140 150; 160 170 180]; % input
L = 4; % input
k = 2; % input
m = size(B,1)/(k+1); % obtain m
n = size(B,2); % obtain n
C = zeros((L-1)*m+1, (L-1)*n+1); % initiallize result
C(1:((L-1)*m+1)*n+m:end) = 1; % each 1 marks the upper-left corner for a copy of B
C = conv2(C, B); % insert copies of B, extending size
The second-to-last line uses linear indexing. The last line applies two-dimensional convolution. The result in this example is
B =
1 2 3
4 5 6
7 8 9
100 110 120
130 140 150
160 170 180
C =
1 2 3 0 0 0 0 0 0 0 0 0
4 5 6 0 0 0 0 0 0 0 0 0
7 8 9 1 2 3 0 0 0 0 0 0
100 110 120 4 5 6 0 0 0 0 0 0
130 140 150 7 8 9 1 2 3 0 0 0
160 170 180 100 110 120 4 5 6 0 0 0
0 0 0 130 140 150 7 8 9 1 2 3
0 0 0 160 170 180 100 110 120 4 5 6
0 0 0 0 0 0 130 140 150 7 8 9
0 0 0 0 0 0 160 170 180 100 110 120
0 0 0 0 0 0 0 0 0 130 140 150
0 0 0 0 0 0 0 0 0 160 170 180
In addition to #LuisMendo's answer:
If size(B,1)/(k+1) do not produce an integer, then his solution can fail.
I would suggest to create the C matrix with sparse():
n = size(B,2)
C = full(sparse(1:k:k*L,1:n:n*L,1))
So the whole code become:
B = ones(7,3); % An input matrix that will produce an error with the linear indexing solution.
L = 6; % number of repetition
k = 2; % row-shift
n = size(B,2); % obtain n
C = full(sparse(1:k:k*L,1:n:n*L,1)); % Create C using full(sparse())
C = conv2(C, B) % insert copies of B, extending size
(all credits goes to LuisMendo for the idea)
This solution as #obchardon's answer uses sparse but unlike the #LuisMendo's answer doesn't use conv2. Indices of blocks are computed and used in sparse to form the desired matrix.
[row col] = find(true(size(B)));
ROW = row + (0:L-1)*k;
COL = col + (0:L-1)*size(B,2);
C = sparse (ROW, COL, repmat (B, 1, L));

How to remove extra duplicated elements in each row of a matrix in matlab?

Let's say I have a matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
How do I remove 2s and keep one 2 in the first row and keep only one 5 in the second row?
The result can't be a matrix anymore, because each row will have a different length. You can obtain the result as a cell array of row vectors as follows:
B = mat2cell(A, ones(size(A,1),1)); %// convert matrix to cell array of its rows
B = cellfun(#(x) unique(x,'stable'), B, 'uniformoutput', 0); %// stably remove duplicates
For your example matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
this gives
B{1} =
2 3 5 6 7
B{2} =
1 2 5 4 6 7
B{3} =
7 5 3 9 8 1 2
If you want to find out which values are duplicates within the row, you can do something like this:
[vals, col_idx] = sort(A,2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
is_duplicate(idx(:,2:end)) = vals(:,1:end-1) == vals(:,2:end);
is_duplicate = reshape(is_duplicate, size(A));
is_duplicate =
0 0 1 0 0 0 1
0 0 0 0 1 0 0
0 0 0 0 0 0 0
From there, it depends what outcome you are looking for. You could set the duplicates to NaN or some other value, or you could set them to NaN, but then shift them to the end of the row, using something like the following:
col_idx = cumsum(~is_duplicate, 2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
A_new = nan(size(A));
A_new(idx(~is_duplicate)) = A(~is_duplicate);
A_new =
2 3 5 6 7 NaN NaN
1 2 5 4 6 7 NaN
7 5 3 9 8 1 2

Extract equally spaced subarrays from an array

I have an array:
v = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20];
I want to extract multiple arrays of length 3 equally spaced by 6 elements, starting at the fifth element of v, and then combine them together:
v1 = [5 6 7];
v2 = [11 12 13];
v3 = [17 18 19];
v_combined = [5 6 7 11 12 13 17 18 19];
Are there any simple ways to do this without using a for loop?
You can do it using logical indexing. You need to create an index mask like this
idx = [0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0]
which you can create like this:
idx = false(size(v))
k = 5
idx(k:end) = ~mod(floor((0:numel(v)-k)/3),2)
And finally
v_combined = v(idx)
In general for m elements spaces by n elements starting from k you can use
k=5;
m=3;
n=6;
I=1:numel(v);
v_combined = v((I>=k) & mod(I-k,n)<m)

Returns the value of the array when the condition was true on the n -th most recent occurrence

I have defined a function
result = valuewhen(condition, array)
which returns the value of the array when the condition was True on the most recent occurrence:
import pandas as pd
pd1 = pd.Series([0,0,1,1,0,0,1,0,1,0,0,0,1])
pd2 = pd.Series([1,2,3,4,5,6,7,8,9,10,11,12,13])
def valuewhen(a1, a2):
res = pd.Series(index=a1.index)
res.loc[a1 == 1] = a2
res = res.ffill().fillna(0)
return res
result = valuewhen(pd1, pd2)
Example:
result = valuewhen(array1, array2)
array1 array2 result
0 1 0
0 2 0
1 3 3
1 4 4
0 5 4
0 6 4
1 7 7
0 8 7
1 9 9
0 10 9
0 11 9
0 12 9
1 13 13
Now I want to return the value of the array when the condition was True on the nth most recent occurrence:
result = ValueWhen(condition, array[, n]) #[if missing n=1]
Example:
Result = ValueWhen(array1, array2, 1)
Result2 = ValueWhen(array1, array2, 2)
array1 array2 Result Result2
0 1 0 0
0 2 0 0
1 3 3 0
1 4 4 3
0 5 4 3
0 6 4 3
1 7 7 4
0 8 7 4
1 9 9 7
0 10 9 7
0 11 9 7
0 12 9 7
1 13 13 9
What is the most Pythonic way to add parameter n to this function?

Resources