I have a matrix:
A = [ 4567 345; 45 6787; 3345 NaN; 87 6787]
and a vector
B = [ 4567; 45; 8976 ]
I want to compare A and B and delete in A all the rows that do not have at least one number which is included in matrix B.
The resulting matrix would be:
[ 4567 345;
45 6787 ]
Here is the code:
idx=ismember(A(:,1:2),B); %%create a logical index in order to see if A includes elements of B
n = length(A)
for i=1:n
if (idx(i,1)==0)& (idx(i,2)==0)
A(i,:)=[];
end
end
However I got this error:
Index of element to remove exceeds matrix dimensions.
I tried with another solution but I get the same error.
n = length(A)
for i=1:n
if (find(idx(i,1)==0))& (find(idx(i,2)==0))
A(i,:)=[];
end
end
You do not need a loop in this logical indexing task:
ismember(A,B)
ans =
1 0
1 0
0 0
0 0
All you need is to keep those rows with at least one match with any(...,2):
idx = any(ismember(A,B),2)
idx =
1
1
0
0
The result:
A(idx,:)
ans =
4567 345
45 6787
The error is caused by the fact that your loop runs from 1:n but you are removing rows from the matrix making it effectively shorter than n.
A = [ 4567 345; 45 6787; 3345 NaN; 87 6787]
B = [ 8976; 45; 4567 ]
z = sum(ismember(A,B)');
NewMatrix=[];
for i = 1:length(z)
if z(i)>= 1
newMatrix = A(i,:);
NewMatrix=[NewMatrix;newMatrix];
end
end
NewMatrix
Related
Been trying to solve this simple problem for a while but just couldn't find the solution for the life of me...
I'm programming an experiment in PsychToolbox but I'll spare you the details, basically I have two vectors A and B of equal size with the same number of ones and zeroes:
A = [0 0 1 1]
B = [0 0 1 1]
Both vectors A and B must be randomized independently but in such a way that one combination of items between the two vectors is never repeated. That is, I must end up with this
A = [1 1 0 0]
B = [1 0 0 1]
or this:
A = [0 0 1 1]
B = [0 1 0 1]
but I should never end up with this:
A = [1 1 0 0]
B = [1 1 0 0]
or this
A = [0 1 0 1]
B = [0 1 0 1]
One way to determine this is to check the sum of items between the two vectors A+B, which should always contain only one 2 or only one 0:
A = [1 1 0 0]
B = [1 0 0 1]
A+B = 2 1 0 1
Been trying to make this a condition within a 'while' loop (e.g. so long as the number of zeroes in the vector obtained by A+B is superior to 1, keep randomizing A and B), but either it still produces repeated combination or it just never stops looping. I know this is a trivial problem but I just can't get my head around it somehow. Anyone care to help?
This is a simplified version of the script I got:
A = [1 1 0 0];
B = A;
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
while nnz(~(A+B)) > 1
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
end
Still, I end up with repeated combinations.
% If you are only looking for an answer to this scenario the easiest way is
% as follows:
A = [0 0 1 1];
B = [0 0 1 1];
nn = length(A);
keepset = [0 0 1 1;0 1 0 1];
keepset = keepset(:,randperm(nn))
% If you want a more general solution for arbitrary A & B (for example)
A = [0 0 0 1 1 1 2 2 2];
B = [0 0 0 1 1 1 2 2 2];
nn = length(A);
Ai = A(randperm(nn));
Bi = B(randperm(nn));
% initialize keepset with the first combination of A & B
keepset = [Ai(1);Bi(1)];
loopcnt = 0;
while (size(keepset,2) < nn)
% randomize the elements in A and B independently
Ai = A(randperm(nn));
Bi = B(randperm(nn));
% test each combination of Ai and Bi to see if it is already in the
% keepset
for ii = 1:nn
tstcombo = [Ai(ii);Bi(ii)];
matchtest = bsxfun(#eq,tstcombo,keepset);
matchind = find((matchtest(1,:) & matchtest(2,:)));
if isempty(matchind)
keepset = [keepset tstcombo];
end
end
loopcnt = loopcnt + 1;
if loopcnt > 1000
disp('Execution halted after 1000 attempts')
break
elseif (size(keepset,2) >= nn)
disp(sprintf('Completed in %0.f iterations',loopcnt))
end
end
keepset
It's much more efficient to permute the combinations randomly than shuffling the arrays independently and handling the inevitable matching A/B elements.
There are lots of ways to generate all possible pairs, see
How to generate all pairs from two vectors in MATLAB using vectorised code?
For this example I'll use
allCombs = combvec([0,1],[0,1]);
% = [ 0 1 0 1
% 0 0 1 1 ]
Now you just want to select some amount of unique (non-repeating) columns from this array in a random order. In all of your examples you select all 4 columns. The randperm function is perfect for this, from the docs:
p = randperm(n,k) returns a row vector containing k unique integers selected randomly from 1 to n inclusive.
n = size(allCombs,2); % number of combinations (or columns) to choose from
k = 4; % number of columns to choose for output
AB = allCombs( :, randperm(n,k) ); % random selection of pairs
If you need this split into two variables then you have
A = AB(1,:);
B = AB(2,:);
Here's a possible solution:
A = [0 0 1 1];
B = [0 0 1 1];
% Randomize A and B independently
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
% Keep randomizing A and B until the condition is met
while sum(A+B) ~= 1 && sum(A+B) ~= length(A)
ARand = randperm(length(A));
A = A(ARand);
BRand = randperm(length(B));
B = B(BRand);
end
This solution checks if the sum of the elements in A+B is either 1 or the length of A, which indicates that only one element in A+B is either a 0 or a 2, respectively. If either of these conditions is not met, the vectors A and B are randomized again.
I have a 3x3 matrix, k1, that I would like to convert into a 5x5 matrix, k1g. k1g is created by inserting zeros into certain rows and columns of k1. In this case I would like to insert zeros into rows 3 and 4 and columns 3 and 4, and keep existing values from k1 matrix. The code below accomplishes what I am trying to do but seems that it is a long method and I need to do this many times in numerous problems.
clc
clear all
format long;
k1 = [20,50,-20;
60,20,-20;
-20,-20,40]
k1g = zeros(5,5);
k1g(1:2,1:2) = k1(1:2,1:2);
k1g(5:5,1:2) = k1(3:3,1:2);
k1g(1:2,5:5) = k1(1:2,3:3);
k1g(5,5) = k1(3,3)
Here is output of above code:
k1 =
20 50 -20
60 20 -20
-20 -20 40
k1g =
20 50 0 0 -20
60 20 0 0 -20
0 0 0 0 0
0 0 0 0 0
-20 -20 0 0 40
Is there a better way to accomplish this?
You just need to generalise your approach. e.g. with:
function k1g = rowcolsof0s(k1,rowsof0s,colsof0s)
k1g = ones(size(k1)+[numel(rowsof0s) numel(colsof0s)]); %Initialising matrix with ones
k1g(rowsof0s,:) = 0; %Changing the elements of desired rows to zeros
k1g(:,colsof0s) = 0; %Changing the elements of desired columns to zeros
k1g(logical(k1g)) = k1; %Transferring the contents of k1 into k1g
end
Now call that function with:
rowsof0s = [3 4]; %rows where you want to insert zeros
colsof0s = [3 4]; %columns where you want to insert zeros
k1g = rowcolsof0s(k1, rowsof0s, colsof0s);
I want to compare every row of a matrix with its every other row, element by element wise, using MATLAB. If two of the entries match, the result will be stored as 1, and if they don't match, it will be 0. This will give a symmetric matrix consisting of 0s and 1s.
For example, let A = [4 6 7 9 5; 2 6 9 9 1]
Then, the result expected is [1 1 1 1 1; 0 1 0 1 0; 0 1 0 1 0; 1 1 1 1 1]
The code I am using is (for a 1000*1000 random matrix):
A = randi(50,1000,1000);
B = zeros(1000000,1000);
D = zeros(1000000,1);
c=0;
for i=1:1000
for k=1:1000
for j=1:1000
if A(i,j)==A(k,j)
B(k+c,j)=1;
else
B(k+c,j)=0;
end
end
end
c=c+1000;
end
for l=1:1000000
D(l)=0;
for m=1:1000
D(l)=D(l)+(B(l,m)/(1000));
end
end
E=reshape(D,1000,1000);
This goes out of memory. Could anyone please suggest a solution or a more efficient code?
you can try row by row comparison directly as taking a complete row array and comparing with the other row array.
For example,
let
A = [4 6 7 9 5; 2 6 9 9 1];
nA = length(A(:,1));
finalMat = [];
for i = 1:nA
matRow = ones(nA,1)*A(i,:); % create a matrix size of A consists of same row elements
finalMat = [finalMat;matRow == A];
end
see if it is okay for you application.
You can use permute to align dimensions apprpriately and then bsxfun for the comparisons:
reshape(bsxfun(#eq, permute(A, [1 3 2]), permute(A, [3 1 2])), [], size(A,2))
i have the following vectors:
A=[1 0 1 0 0 1 0 1 0 0];
B=[1 2 3 4 5 6 7 8 9 10];
in this case A represents a time vector, where the 1s signal the beginning of one time unit.
now i want to add up all the values in B which correspond to a time unit with the same length of 3 steps.
So in this example this would mean the 3rd, 4th and 5th value and the 8th, 9th and 10th value of B should be summed cause these are in a time unit of length 3.
B_result=[12 27];
i know cumsum() is the command for this but i dont know how to say that only these specific values depending on the time indices of A should be summed.
can you help me?
thanks alot
You can use cumsum alongside accumarray and hist:
csa = cumsum(A); %// from begining og unit to unit indices
n = hist(csa, 1:max(csa)); %// count num of steps in each unit
B_result = accumarray( csa', B' ); %// accumulate B into different time units
B_result(n~=3) = []; %// discard all time units that do not have 3 steps
For a simpler pattern matching, you can use strfind:
loc = strfind([A,1],[1 0 0 1]); %// add the 1 at the end of A and the pattern to avoid longer intervals
idx = bsxfun(#plus,loc,(0:2)'); %'// get the indices that need to be summed
result = sum(B(idx),1); %// obtain the result
N = 3; %// We want to detect a one followed by exactly N-1 zeros. Call that
%// sequence an "interesting part"
ind = find([A 1]); %// find ones. Append a last one to detect a possible
%// interesting part at the end.
ind = ind(diff(ind)==N); %// index of beginning of interesting parts
cs = cumsum(B); %// accumulate values
B_result = cs(ind+N-1)-cs(ind-1); %// use index to build result
A more generic application of Jonas' Idea:
A = [1 0 1 0 0 1 0 1 0 0 0 0 1];
B = [1 2 3 4 5 6 7 8 9 10 11 12];
n = 3;
result = arrayfun(#(x) sum( B(x:x+n-1) ), strfind([A,1],num2str(10^n+1)-48))
or use cumsum instead of sum, I was not sure what you actually want:
result = arrayfun(#(x) cumsum( B(x:x+n-1) ), ...
strfind( [A,1],num2str(10^n+1)-48 ) ,'uni',0)
%optional:
result = cell2mat(result')
I want to run fast Matlab algorithms over Matrices by ignoring zero-elements.
In the past I just worked with a very slow double-for-loop e.g.
for i = 1 : size(x,1)
for j = 1 : size(x,2)
if x(i,j) ~= 0
... do something with x(i,j)
end
end
end
But how can I make the matrix operation on the whole matrix x?
E.g. how can I run
x(i,j) = log(x(i,j)) if x>0 else 0 <-- pseudo code
in Matlab on the whole matrix without for loops?
Finally I want to rewrite lines like
result = sum(sum((V.*log(V./(W*H))) - V + W*H));
with ignoring zeros.
I just need to understand the concept.
In case of need I could also use NaN instead of zero, but I didn't find e.g. the function
nanlog()
x~=0 returns you the indices of the locations not equal to zero. Then, you can use them to index corresponding locations of x such as follows:
>> x = [1 0 2 3; 0 4 0 5]
x =
1 0 2 3
0 4 0 5
>> mean(x(:)) %#mean of all elements
ans =
1.8750
>> mean(x(x~=0)) %#mean of nonzero elements
ans =
3
>> x(x~=0) = x(x~=0) + 1
x =
2 0 3 4
0 5 0 6
You can use NaN as a temporary and make use of the fact that log(NaN) = NaN, like so:
x(x==0) = NaN;
y = log(x);
y(isnan(y)) = 0;
alternatively, you can use logical indexing:
x(x~=0) = log(x(x~=0));
or, if you want to preserve x,
y = x;
y(y~=0) = log(y(y~=0));
For the example you provide, you can just do
result = nansum(nansum((V.*log(V./(W*H))) - V + W*H));
assuming that V == 0 is the problem.