# Searching and replacing values in a matrix

522 views (last 30 days)
Daniel Ring on 24 Sep 2018
Edited: James Tursa on 24 Sep 2018
I have a very large matrix of ones and zeros X. I would like to replace all the ones in the first column with a value, and all the zeros in the same column with a different value. I would like to do the same for all of the columns in my matrix. What I've tried so far is
x(x(:,1)>0) = .75;
x(x(:,2)>.0) = .66;
x(x(:,3)>0) = .95;
x(x(:,1)<1) =.25;
x(x(:,2)<1) =.34;
x(x(:,3)<1) =.05;
However the code is replacing the ones (not the zeros) in the first column only, and not doing it correctly at that.
How can I fix this?

Bish Erbas on 24 Sep 2018
Have you tried the == operator? For example,
x(x(:,1) == 0) = 0.75;
aepound on 24 Sep 2018
You still need to include the particular column in the outer x index:
x(x(:,1) == 0,1) = 0.75;

James Tursa on 24 Sep 2018
Edited: James Tursa on 24 Sep 2018
You are inadvertently using linear indexing because you don't supply the 2nd index. Change your code to:
x(x(:,1)>0,1) = .75;
x(x(:,2)>0,2) = .66;
x(x(:,3)>0,3) = .95;
x(x(:,1)<1,1) =.25; % <-- No ... see correction from Nicole below
x(x(:,2)<1,2) =.34;
x(x(:,3)<1,3) =.05;
Or, another way:
v = [0.75 0.66 0.95];
x(:,1:3) = bsxfun(@times,x(:,1:3),v) + bsxfun(@times,1-x(:,1:3),1-v);
Or if you have a later version of MATLAB
x(:,1:3) = x(:,1:3).*v + (1-x(:,1:3)).*(1-v);
And if your matrix only has three columns,
x = bsxfun(@times,x,v) + bsxfun(@times,1-x,1-v);
or
x = x.*v + (1-x).*(1-v);

Show 1 older comment
James Tursa on 24 Sep 2018
We are given that x only contains 1's and 0's, so using ==0 gives the same result as using <1 in this case. Try it out.
Nicole Peltier on 24 Sep 2018
The output is:
x =
0.2500 0.3400 0.0500
0.2500 0.3400 0.0500
0.2500 0.3400 0.0500
0.2500 0.3400 0.0500
...
because once the first three lines run, every item in x is less than 1.
James Tursa on 24 Sep 2018
Ah, yes! Good catch! (Shame on me for using a temporary variable in my testing and jumping to the vectorized code too quickly ...)
And, to make the whole algorithm more robust, it should be noted that even with the ==0 correction it will not work properly if one of the values on the rhs is 0. So, best either to use temporary variables to save the logical locations or just use vectorized code to begin with.

aepound on 24 Sep 2018
In your example, you are indexing into a 2D x matrix x( ) with the values of the column x(:,3) that are > 0. You probably mean to do something more like this:
x(x(:,1),1) = .75;
x(x(:,2),2) = .66;
That being said, if the matrix is binary (i.e. 0s and 1s), then I would try to take advantage of logical indexing. The idea is that your matrix is already logical, and the things that you want to replace can be added in using that.
The difficulty lies in teasing out what shape your values need to be in that you want to put into the matrix. Because you are working column by column, it isn't the worst thing to come up with. I've included a small demo below that you should be able to try out and modify to work for you. Of note, if you haven't worked with logical matrices/vectors before: You can use the "not" operator to switch 1s into 0s and 0s into 1s.
% First, let's make some random data of ones and zeros:
N = 10; % The number of columns == 10
M = rand(N) > .5
% Now, Get a vector of values that you want where the 1s are:
vals1 = rand(1,N)
% Let's make it the same shape as 'x':
vals1 = repmat(vals1,N,1)
% And get a vector of values for the columns where the 0s are:
vals0 = -rand(1,N)
% Replicate them into the shape of 'x', also:
vals0 = repmat(vals0,N,1)
% Now, let's do the replacements:
res = zeros(size(M));
% For the ones spots:
res(logical(M)) = vals1(logical(M));
% And now for the zeros:
res(~logical(M)) = vals0(~logical(M));
The calls to 'logical()' just makes sure that the 'M' matrix is logical, even if it wasn't to begin with. I think that this would be much more flexible than going column by column. The downside is the allocation of the extra (possibly big) matrices 'vals1' and 'vals0'.