select a range of values from a matrix and swap them - matlab

I have a matrix and i want to select a range of elements.
for example i want to select all the elements that are lower than 182 and swap/change them.
does someone know an easy way or command to do this in matlab ?
thanx

Since you say "swap", I understand you mean a vector, not a matrix. You can do it as follows:
x = [ 1 34 66 22 200 55 301 ]; % data
[ values, ind ] = find(x<182);
x(ind) = x(ind(end:-1:1));
To simply replace them by another value such as NaN, do as follows. Note that this works also for matrices:
x = [ 1 34 66 22 200 55 301 ]; % data
x(x<182) = NaN;

Such things can usually be accomplished via logical indexing:
A = randn(1,100);
B = randn(size(A));
test = (A>1|A<0); % For example, values that are greater than 1 or less than 0
A(test) = B(test);
or another example:
A = randn(1,100);
test = (A>1|A<0);
A(test) = randn(1,nnz(test));
or another:
A = randn(1,100);
A(A>1|A<0) = NaN;

You may use loop like this:
for i = 1:length(matrix(:,1))
for j = 1:length(matrix(1,:))
if matrix(i,j) < 182
matrix(i,j) = NaN;
end
end
end

Related

What is the meaning of the following matlab notation?

I want to write this matlab code in python but I do not know what LEV(1:n+1:n^2) = 0; or LEV(i,:) means. Can anyone explain me what are this notation? Thank you!
function A = ILU_p(A,p)
n = length(A);
LEV = inf(n);
LEV(find(A)) = 0;
LEV(1:n+1:n^2) = 0;
for i = 2:n
for k = 1:i-1
if LEV(i,k) > p
continue
end
A(i,k) = A(i,k) / A(k,k);
A(i,k+1:n) = A(i,k+1:n) - A(i,k) * A(k,k+1:n);
LEV(i,k+1:n) = min([LEV(i,k+1:n); LEV(i,k) + LEV(k,k+1:n) + 1]);
end
A(i,find(LEV(i,:)>p)) = 0;
end
The below sets up a vector of values to be used in an index. If n=10 then the below would yield a row vector of [1 12 23 34 45 56 67 78 89 100]
1:n+1:n^2
Since LEV is set up as an nxn matrix and the above row vector picks up the diagonal elements, i.e., LEV(1) = LEV(1,1), LEV(12) = LEV(2,2), etc.
LEV(i,:) is MATLAB's shorthand for referencing all columns in row i.

How to efficiently find maximum of selected indices of an array in MATLAB?

Let us say we have the vectors: w, s_on, and s_off. s_on and s_off have the ascending indices of the onset and offset of an event. We need to find the maximum value in during each event. How can we do it without using loop.
for example we may have the following values:
s_on = [5 19 78 101];
s_off = [10 28 97 152];
w = rand(1,200);
The following code does not work:
pv = max(w(s_on(1:end):s_off(1:end)))
Let the data be defined as
s_on = [5 19 78 101];
s_off = [10 28 97 152];
w = rand(1,200);
The maximum for each range of indices can be computed as follows:
[v, t] = max(bsxfun(#ge, 1:numel(w), s_on(:)) & bsxfun(#le, 1:numel(w), s_off(:)), [], 1);
result = accumarray(t(v).', w(v).', [], #max);
A loop would be more readable:
result_loop = NaN(numel(s_on), 1);
for k = 1:numel(s_on)
result_loop(k) = max(w(s_on(k):s_off(k)));
end
Check that both approaches give the same result:
isequal(result, result_loop)

How to add certain rows to a 2D matrix?

I have a simple 2D matrix like this in MATLAB:
A = [34 10;
23 10;
64 10];
What I need to do is to find max(A(:,1)), then while A(j,1) < max(A(:,1)) add rows like [A(j,1)+1 10] to the matrix, so I want to eventually get this:
A = [34 10;
35 10;
36 10;
37 10;
.
.
.
62 10;
63 10;
64 10;
.
23 10;
24 10;
25 10;
.
.
.
62 10
63 10
64 10
.
64 10];
I have written the following but it does not work:
for j = 1:size(A,1)
while A(j,1) < max(A(:,1))
A(end+1,:) = [A(j,1)+1 10];
end
end
Any ideas how I could do that?
You can try the following, for Matlab without loops:
my_max = max(A(:,1));
my_arrays = arrayfun(#(x) [x:my_max]', A(:,1), 'uni', 0);
my_expanded_column = cat(1,my_arrays{:});
my_output = [my_expanded_column, 10*ones(size(my_expanded_column))]
It first finds the maximum,
Then expands each entry to a range to the maximum,
Then combines all the ranges to one,
Then tacks on the second column of 10's.
Your while-loop gets stuck checking the same element over and over again (because you don't increment anything).
You could instead use a for-loop to count up from each element in A's first column. And make sure you add the rows to a new matrix, otherwise your loop will recursively expand A ad infinitum.
For example:
B = [];
index = 1; % keeps track of the last element of B
for j = 1:size(A,1)
for k = A(j,1):max(A(:,1))
B(index,:) = [k A(j,2)];
index = index + 1;
end
end

Get all columns of matrix except some indices

I have a matrix x and an index vector p. Now I want to select all the columns in x except the columns in p.
Example:
x = [12,11,33,33;22,44,33,44;33,22,55,32]
p = [2,4]
then it should return
out = [12,33;22,33;33,55]
Use setdiff and end
>> x(:,setdiff(1:end,p))
ans =
12 33
22 33
33 55
One way:
out = x;
out(:,p) = []
another way:
out = x(:,setxor(p,1:size(x,2)))
%// ore inspired by Mohsen Nosratinia
out = x(:,setxor(p,1:end))
and another one:
mask(size(x,2)) = 0
mask(p) = 1
out = x(:,~mask)
There are many ways to do this, but a simple one is:
y = x; %// Create copy of x
y(:,p) = [] %// Remove columns p
Or, maybe you prefer to use sparse?
x(:,~sparse(p,1,1));
Or how about accumarray?
x(:,~accumarray(p.',1))

A Fast and Efficient way to create a matrix from a series of product

Ax, Ay, Az: [N-by-N]
B=AA (a dyadic product)
It means :
B(i,j)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)]
B(i,j) : a 3x3 matrix.
One way to construct B is:
N=2;
Ax=rand(N); Ay=rand(N); Az=rand(N); %# [N-by-N]
t=1;
F=zeros(3,3,N^2);
for i=1:N
for j=1:N
F(:,:,t)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)];
t=t+1; %# t is just a counter
end
end
%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)';
B = cell2mat(B);
Is there a faster way for when N is large.
Edit:
Thanks for your answer. (It's faster)
Let's put:
N=2;
Ax=[1 2;3 4]; Ay=[5 6;7 8]; Az=[9 10;11 12];
B =
1 5 9 4 12 20
5 25 45 12 36 60
9 45 81 20 60 100
9 21 33 16 32 48
21 49 77 32 64 96
33 77 121 48 96 144
Run:
??? Error using ==> mtimes
Inner matrix dimensions must agree.
If I write :P = Ai*Aj; then
B =
7 19 31 15 43 71
23 67 111 31 91 151
39 115 191 47 139 231
10 22 34 22 50 78
34 78 122 46 106 166
58 134 210 70 162 254
That is defferent from above
A(:,:,1) deffer from [Ax(1,1) Ay(1,1) Az(1,1)]
Edit:
N=100;
Me :Elapsed time is 1.614244 seconds.
gnovice :Elapsed time is 0.056575 seconds.
N=200;
Me :Elapsed time is 6.044628 seconds.
gnovice :Elapsed time is 0.182455 seconds.
N=400;
Me :Elapsed time is 23.775540 seconds.
gnovice :Elapsed time is 0.756682 seconds.
Fast!
rwong: B was not the same.
Edit:
After some modification for my application :
by gnovice codes
1st code : 19.303310 seconds
2nd code: 23.128920 seconds
3rd code: 13.363585 seconds
It seems that any function calling like ceil,ind2sub ... make thw loops slow and shoud avoid if possible.
symIndex was interesting! Thank you.
Here's a fairly simple and general implementation that uses a single for loop to perform linear indexing and avoids dealing with 3-dimensional variables or reshaping:
%# General solution:
%# ----------------
B = cell(N);
for index = 1:N^2
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
end
B = cell2mat(B);
EDIT #1:
In response to the additional question of how to reduce the number of calculations performed for a symmetric matrix B, you could use the following modified version of the above code:
%# Symmetric solution #1:
%# ---------------------
B = cell(N);
for index = find(tril(ones(N))).' %'# Loop over the lower triangular part of B
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
symIndex = N*rem(index-1,N)+ceil(index/N); %# Find the linear index for the
%# symmetric element
if symIndex ~= index %# If we're not on the main diagonal
B{symIndex} = B{index}; %# then copy the symmetric element
end
end
B = cell2mat(B);
However, in such a case you may get better performance (or at least simpler looking code) by foregoing the linear indexing and using two for loops with subscripted indexing like so:
%# Symmetric solution #2:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
for r = c:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
B{r,c} = A(:)*A;
if r ~= c %# If we're not on the main diagonal
B{c,r} = B{r,c}; %# then copy the symmetric element
end
end
end
B = cell2mat(B);
EDIT #2:
The second symmetric solution can be further sped up by moving the diagonal calculation outside of the inner loop (removing the need for a conditional statement) and overwriting A with the result A(:)*A so that we can update the symmetric cell entry B{c,r} using A instead of B{r,c} (i.e. updating one cell with the contents of another appears to carry some extra overhead):
%# Symmetric solution #3:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
A = [Ax(c,c) Ay(c,c) Az(c,c)];
B{c,c} = A(:)*A;
for r = c+1:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
A = A(:)*A;
B{r,c} = A;
B{c,r} = A;
end
end
B = cell2mat(B);
And here are some timing results for the 3 symmetric solutions using the following sample symmetric matrices Ax, Ay, and Az:
N = 400;
Ax = tril(rand(N)); %# Lower triangular matrix
Ax = Ax+triu(Ax.',1); %'# Add transpose to fill upper triangle
Ay = tril(rand(N)); %# Lower triangular matrix
Ay = Ay+triu(Ay.',1); %'# Add transpose to fill upper triangle
Az = tril(rand(N)); %# Lower triangular matrix
Az = Az+triu(Az.',1); %'# Add transpose to fill upper triangle
%# Timing results:
%# --------------
%# Solution #1 = 0.779415 seconds
%# Solution #2 = 0.704830 seconds
%# Solution #3 = 0.325920 seconds
The big speed-up for solution 3 results primarily from updating the cell contents of B with the local variable A instead of updating one cell with the contents of another. In other words, copying cell contents with operations like B{c,r} = B{r,c}; carries more overhead than I expected.
A = cat(3, Ax, Ay, Az); % [N-by-N-by-3]
F = zeros(3, 3, N^2);
for i = 1:3,
for j = 1:3,
Ai = A(:,:,i);
Aj = A(:,:,j);
P = Ai(:) .* Aj(:);
F(i,j,:) = reshape(P, [1, 1, N^2]);
end
end
%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)';
B = cell2mat(B);