Replace values in matrix with other values - matlab

I have a matrix with integers and I need to replace all appearances of 2 with -5. What is the most efficient way to do it? I made it the way below, but I am sure there is more elegant way.
a=[1,2,3;1,3,5;2,2,2]
ind_plain = find(a == 2)
[row_indx col_indx] = ind2sub(size(a), ind_plain)
for el_id=1:length(row_indx)
a(row_indx(el_id),col_indx(el_id)) = -5;
end
Instead of loop I I seek for something like: a(row_indx,col_indx) = -5, which does not work.

find is not needed in this case.
Use logical indexing instead:
a(a == 2) = -5
In case of searching whether a matrix is equal to inf you should use
a(isinf(a)) = -5
The general case is:
Mat(boolMask) = val
where Mat is your matrix, boolMask is another matrix of logical values, and val is the assignment value

Try this:
a(a==2) = -5;
The somewhat longer version would be
ind_plain = find(a == 2);
a(ind_plain) = -5;
In other words, you can index a matrix directly using linear indexes, no need to convert them using ind2sub -- very useful! But as demonstrated above, you can get even shorter if you index the matrix using a boolean matrix.
By the way, you should put semicolons after your statements if (as is usually the case) you're not interested in getting the result of the statement dumped out to the console.

The Martin B's method is good if you are changing values in vector. However, to use it in matrix you need to get linear indices.
The easiest solution I found is to use changem function. Very easy to use:
mapout = changem(Z,newcode,oldcode)
In your case: newA = changem(a, 5, -2)
More info: http://www.mathworks.com/help/map/ref/changem.html

Here's a trivial, unoptimised, probably slow implementation of changem from the Mapping Toolbox.
function mapout = changem(Z, newcode, oldcode)
% Idential to the Mapping Toolbox's changem
% Note the weird order: newcode, oldcode. I left it unchanged from Matlab.
if numel(newcode) ~= numel(oldcode)
error('newcode and oldcode must be equal length');
end
mapout = Z;
for ii = 1:numel(oldcode)
mapout(Z == oldcode(ii)) = newcode(ii);
end
end

Related

Are unnecessary computations avoidable?

I got an index-array ind of length len which is either 0 or 1. I need results coming from a complex and time-intensive function func to be stored in a result-vector res (also length len). Input-vector is called inp.
I could do this via the two following ways:
% 1st way:
res = zeros(len,1);
res(ind) = func(inp);
% 2nd way:
res = ind .* func(inp);
My question for the 2nd one: for those entries where ind is 0, does MATLAB evaluate func()? I hope not, because zero times anything else is zero, so it is a waste to evaluate func.
For those entries where ind is 0, your first option won't work because res(ind) will throw an error:
Subscript indices must either be real positive integers or logicals.
Anyway, I think this is what you are looking for:
allowed_indices = ind > 0; % Logical indexing of valid indices
res = zeros(len,1);
res(allowed_indices) = func(inp(allowed_indices));
It probably does, but this is very easy for you to test by making a test func that prints to the console and then make all of ind 0 and see if it prints anything (I'm sure it will, but I don't have MATLAB to check myself).
I hoped no because zero times sth. else is zero
Not necessarily, what about 0*inf? Or 0*NaN?
If the point of your question is which is more efficient, test both using timeit

elegant k-smallest argmin in Matlab

Is there a cleaner (as in, ideally built in; I've never used Matlab so apologies if I missed something obvious) way to do k-smallest argmin in Matlab (i.e. if an array is [4,5,6,7] it should return the indexes 1,2 in that order) besides stuff like:
arr = [4,5,6,7];
[~, argmin1] = min(arr);
arr(argmin1) = Inf;
[~, argmin2] = min(arr);
...
Say we want indices of k smallest element in array arr, then:
arr=[4,5,6,7,2];
[~,indices]=sort(arr,'ascend');
argmin=indices(1:k);
If one want k highest values, use descend argument instead.

Matlab: make a matrix by looping through an index without using a For loop?

I have a function A(k) which returns a matrix dependent on k when I type for example A(1). I want to automatically create the matrix:
[A(3)*A(2)*A(1) A(3)*A(2) A(3)]
In Mathematica I can do for example:
Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}]
Assume A(k) is a function which returns a 3x3 matrix. For example typing A(1) may return:
[1,2,3;4,5,6;7,8,9]
Explanation of Mathematica code: Table[A(k),{k,3,i,-1}] is a "loop" from k=3 to k=i with each iteration decrementing k by -1. Therefore the output would be a list {A(3),A(2),...,A(i)}... obviously k starting from 3 then for i=2 the output list will be {A(3),A(2)}. The function Apply[Dot,Table[A(k),{k,3,i,-1}]] multiplied the elements of the list together. For i=2 this produces A(3)*A(2). Finally, Table[Apply[Dot,Table[A(k),{k,3,i,-1}]],{i,1,3}] applies the same logic as the first statement, looping i from 1 to 3. Because the inner table depends on i, this creates a list of elements {A(3)*A(2)*A(1),A(3)*A(2),A(3)}. A list is Mathematica's version of a matrix.
How can I achieve the same effect in MATLAB, i.e. not use a for loop to achieve the result? Thanks!
For the record, here's a looping version, mostly for subsequent timing checks. This is not the answer you want, but the answer you need;)
N = 10; %size of A
old = eye(N);
M2 = [];
for i=3:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
Or if you want to be really efficient (which is probably not the case):
N = 10; %size of A
M2 = A(3);
old = M2;
for i=2:-1:1
new = old*A(i);
M2 = [new M2];
old = new;
end
This answer basically is the solution to the problem, but as we are discussing efficient use of matlab I want to leave my thoughts here how to use Matlab efficient. Instead of the large 2D-Matrix it is much simpler to create a 3D-Matrix where the results of each multiplication are stacked. If a 3D-Matrix is acceptable use the code as it is, otherwise comment in the last line to get a 2D-matrix.
M3=[];
n=3;
M3(:,:,n) = A(n);
for ix=n-1:-1:1
M3(:,:,ix) = M3(:,:,ix+1)*A(i);
end
%M3=reshape(M3,size(M3,1),[]);
You can use arrayfun() with indexes as parameters, eg:
%// Compute the product A(3)*A(2)*...*A(idx)
F = #(idx) prod(reshape(cell2mat(arrayfun(A,3:-1:idx, 'UniformOutput', false)),10,10,4-idx),3);
%// Use the last function with idx=1:3
M = cell2mat(arrayfun(F,1:3, 'UniformOutput', false));

matlab inline function with argument conditions

folks,
I am wondering if it is possible to write the following function of r as an inline function in matlab. I tried to include the condition as a separate factor such as *(r>a) and I got NaN due to the division of 1/r^3 when r is 0.
I fould a simple way out. It's basically what Shai and Jigg suggested, i.e. using an extra multiplicative factor of (r>a).
To get rid of NaN, we just need to add eps to the denominator of 1/r3, i.e.
1/(r+eps)^3 *(r>a)
First, you haven't stated what should actually happen if r = 0. Mathematically the term gets infinity. I assumed you rather want to set it to zero. And what should happen for r = a? Just another ill-defined case, are you sure your formula is correct?
If you have the Statistics Toolbox you can use nansum. If not, I'd say there is no way around to write your own function similar to nansum, which can't be done inline.
r = -5:1:5;
a = 1;
R = 42; %// rest of your function
%// not working, or removing of nan afterwards required
X = #( r ) (r>=a).*(a./r).^3*R;
%// inline solution with statistics toolbox
Y = #( r ) arrayfun(#(x) nansum( (x>=a)*(a/x)^3*R ), r);
output = [X(r)' Y(r)']
nansum is not vectorized, if you still want to use it for vectors wrap it into arrayfun.
The code of nansum does exactly what was suggested in the comments (output(isnan(output))=0), I'm probably not allowed to copy&paste it here. It filters out all NaN and then sums the input. Use open nansum to have insight.
As pointed out by Jigg, similar functions like nanmean would do the trick as well.
You can try
chi = 1; %// arbitrary value
a = 1; %// arbitrary value
theta = pi/3; %// arbitrary value
nu = #( r ) (r>a).*( (chi/3).*((a.^3)./(r.^3)).*(3*cos(theta).^2 -1);

Vectorizing 'for' loops

This piece of code works as I want it to, but in the spirit of good MATLAB code, is there a way to vectorize this (previous is a k x 1 vector):
start = zeros(k,1);
for i = 2:length(previous)
if (previous(i-1) == -1)
start(previous(i))= start(previous(i))+1;
end
end
What, in general, is the intuitive way to go about vectorizing code in MATLAB?
Use the find command in MATLAB, which returns the index (i) for which a vector is TRUE. So:
% precache indices i where previous(i-1) == 1
idx = find(previous==-1)+1;
start(previous(idx)) = start(previous(idx))+1;
The reason I precache idx is in case that previous is a big vector and doing the find takes a while. Otherwise you could just do
start( find(previous==-1)+1 ) = start( find(previous==-1) ) + 1;
You can do this without find, for maximum performance:
I = [false; previous(1:end-1) == -1];
idx = previous(I);
start(idx) = start(idx) + 1;
This also avoids the risk that previous(end) == -1, which would cause an index out-of-range error in the alternative.
Note that this doesn't work the same as your original if idx contains duplicated indices.
I would do something like:
prev_is_minus1 = [false; previous(1:end-1)==-1]
start = accumarray(previous(prev_is_minus1), 1, k)
I believe this has the same effect as the code loop you posted.