MATLAB replacing some elements from a vector - matlab

If i have a vector, lets say L=[10;10;10;11;11;13;13] which is associated to another vector X=[1;6;65;34;21;73;14] and I want to create a third vector, Z, with almost all the elements in X, but just replacing a 0 in X when the element (i,j) from L changes. Lets say that the result that I want should look like this Z=[1;6;65;0;21;0;14]
Any ideas how to solve this?
I would be really thankful :)

That's easy:
X = [1;6;65;34;21;73;14];
L = [10;10;10;11;11;13;13];
Z = X;
ind = [false; diff(L)~=0]; %// logical index of values to be set to 0
Z(ind) = 0;
This works by computing a logical index ind = [false; diff(L)~=0] of the elements where a change has ocurred. The initial false is needed because the first element doesn't have a previous one to compare with. The logical index is used to select which values of Z should be set to 0.

This should work
Z = zeros(length(L))
for i = 2:length(L)
if(L(i-1) == L(i)
Z(i) = X(i);
else
Z(i) = 0;
end
end

Related

using Matlab to reshape a 4d matrix into a cell array of vectors

I have a 4D matrix (dims - x,y,z,t). I want to reshape it to a 1D cell array of length x*y*z where each element is a long vector of size t which captures all elements at each volume location (x,y,z). After that I need to reshape it back.
I thought of looping over the array to do it since I can't really find a built in function to do it.
Any insights will be super helpful! Thanks!
See if this is that you want:
x = randn(2,3,4,5); % example data
x = reshape(x, [], size(x,4)); % collapse first three dimensions
x = mat2cell(x, ones(1,size(x,1)), size(x,2)); % split first dimension into cells
Luis's answer is great for being semi-vectorized (mat2cell uses a loop). If what you desire is a cell array of size x*y*z where each element is t long, it's possible to use a loop over each volume location and extract the t elements that "temporally" occupy this spot in 4D. Make sure you squeeze out any singleton dimensions to get the resulting vector. This is something to consider if you wanted to go with the loop approach. Assuming your matrix is called A, try the following:
B = cell(size(A,1)*size(A,2)*size(A,3), 1);
count = 1;
for ii = 1 : size(A,1)
for jj = 1 : size(A,2)
for kk = 1 : size(A,3)
B{count} = squeeze(A(ii,jj,kk,:));
count = count + 1;
end
end
end
To get this back into a 4D matrix form, you'd just apply the same logic but in reverse:
Ar = zeros(size(A));
count = 1;
for ii = 1 : size(A,1)
for jj = 1 : size(A,2)
for kk = 1 : size(A,3)
Ar(ii,jj,kk,:) = B{count};
count = count + 1;
end
end
end
Like Luis' solution, but simpler and more complete:
% Transform to cell
x = randn(2,3,4,5); % example data
y = reshape(x, [], size(x,4));
z = num2cell(y,2);
% transform back
x = reshape(cat(1,z{:}), size(x));

Why does the one-dimensional variant of a 2-d random walk not work?

There is a two-dimensional random walk that one can find here which works perfectly in Octave. However, when I tried to write a one-dimensional random walk program, I got an error. Here is the program:
t=[];
x=[];
for i=1:100000
J=rand;
if J<0.5
x(i+1)=x(i)+1;
t(i+1)=t(i)+1;
else
x(i+1)=x(i)-1;
t(i+1)=t(i)+1;
end
end
plot(t,x)
Here is the error:
error: A(I): index out of bounds; value 1 out of bound 0
Thank you.
No need for a loop:
N = 100000;
t = 1:N;
x = cumsum(2*(rand(1,N)<.5)-1);
plot(t,x)
For the 2D case you could use the same approach:
N = 100000;
%// t = 1:N; it won't be used in the plot, so not needed
x = cumsum(2*(rand(1,N)<.5)-1);
y = cumsum(2*(rand(1,N)<.5)-1);
plot(x,y)
axis square
You get an error because you ask MATLAB to use x(1) in the first iteration when you actually defined x to be of length 0. So you need to either initialize x and t with the proper size:
x=zeros(1,100001);
t=zeros(1,100001);
or change your loop to add the new values at the end of the vectors:
x(i+1)=[x(i) x(i)+1];
Since t and x are empty, therefore, you cannot index them through x(i+1) and x(i).
I believe you should intialize x and t with all zeros.
In the first iteration, i = 1, you have x(2) = x(1) +or- 1 while x has dimension of zero. You should define the starting point for x and t, which is usually the origin, you can also change the code a little bit,
x = 0;
N = 100000;
t = 0 : N;
for i = 1 : N
x(i+1) = x(i) + 2 * round(rand) - 1;
end
plot(t,x)

Meshgrid and double for-loops does not result in the same matrix, why?

I am trying to evaluate all values the expression f = 2y-exp(z) can take for different values of z and y. Were y and z are two vectors of length M. I am wondering why the two approaches for generating the expression f yields different results.
Using meshgrid:
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
and with double for-loops
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
argument_new(i,j) = 2*y(i)-exp(z(j));
end
end
Any hints will be highly appreciated!
That's because of the way meshgrid creates 'inverted' directions. I don't find the right words, but here is an example illustrating with your code.You see that if you uncomment option 2 and use argument_new(j,i) instead of argument_new(i,j) both matrices are equal (as obtained with isequal).
clear
clc
M = 20;
y = 1:M;
z = 1:M;
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
%// 1)
argument_new(i,j) = 2*y(i)-exp(z(j));
%// 2)
%// argument_new(j,i) = 2*y(i)-exp(z(j));
end
end
isequal(argument,argument_new) %// Gives 0 for option 1 and 1 for option 2.
Blame that on meshgrid:
MESHGRID is like NDGRID except that the order of the first two input
and output arguments are switched (i.e., [X,Y,Z] = MESHGRID(x,y,z)
produces the same result as [Y,X,Z] = NDGRID(y,x,z)).
Solution: use ndgrid, which doesn't do that switching, and is thus more "natural":
[Y,Z] = ndgrid(y,z);
argument = 2*Y-exp(Z);
Or in your code, after meshgrid, add a transpose operation: argument = argument.';)
They are the same, you should just transpose either one (' in Matlab), or you can replace i by j and vice versa in the for loops

Looping with two variables from a vector

I have a 30-vector, x where each element of x follows a standardised normal distribution.
So in Matlab,
I have:
for i=1:30;
x(i)=randn;
end;
Now I want to create 30*30=900 elements from vector, x to make a 900-vector, C defined as follows:
I am unable to do the loop for two variables (k and l) properly. I have:
for k=1:30,l=1:30;
C(k,l)=(1/30)*symsum((x(i))*(x(i-abs(k-l))),1,30+abs(k-l));
end
It says '??? Undefined function or method 'symsum' for input arguments of type
'double'.'
I hope to gain from this a 900-vector, C which I will then rewrite as a matrix. The reason I have using two indices k and l instead of one is because I eventually want these indices to denote the (k,l)-entry of such a matrix so it is important that that my 900-vector will be in the form of C = [ row 1 row 2 row 3 ... row 30 ] so I can use the reshape tool i.e.
C'=reshape(C,30,30)
Could anyone help me with the code for the summation and getting such a 900 vector.
Let's try to make this a bit efficient.
n = 30;
x = randn(n,1);
%# preassign C for speed
C = zeros(n);
%# fill only one half of C, since it's symmetric
for k = 2:n
for l = 1:k-1
%# shift the x-vector by |k-l| and sum it up
delta = k-l; %# k is always larger than l
C(k,l) = sum( x(1:end-delta).*x(1+delta:end) );
end
end
%# fill in the other half of C
C = C + C';
%# add the diagonal (where delta is 0, and thus each
%# element of x is multiplied with itself
C(1:n+1:end) = sum(x.^2);
It seems to me that you want a matrix C of 30x30 elements.
Given the formula that you provided I would do
x = randn(1,30)
C = zeros(30,30)
for k=1:30
for l=1:30
v = abs(k-l);
for i =1:30-v
C(k,l) = C(k,l) + x(i)*x(i+v);
end
end
end
if you actually need the vector you can obtain it from the matrix.

Elementwise ifs in matlab - do they exist?

Say I have the following basic if-statement:
if (A ~= 0)
% do something like divide your favorite number by A
else
% do something like return NaN or infinity
end
The problem is that A is not a simple number but a vector. Matlab returns true if no element in A is 0. What I am looking for is a vectorized? way of perforimg the if-statement above for each element in A.
Actually, I simply want to do this as fast as possible.
Vectorized ifs don't exist, but there are some options. If you want to test for all or any elements true, use the all or any function.
Here's one example of conditionally modifying values of a matrix:
b = A ~= 0; % b is a boolean matrix pointing to nonzero indices
% (b could be derived from some other condition,
% like b = sin(A)>0
A(b) = f(A(b)) % do something with the indices that pass
A(~b) = g(A(~b)) % do something else with the indices that fail
B = zeros(size(A));
B(A~=0) = FAV./A(A~=0);
B(A==0) = NaN;
In general, to perform one operation on some elements of a matrix and another operation on the remaining elements, a one-line solution is:
Z = B .* X + ~B .* Y;
where B is a logical matrix. As an example,
Z = (A == 0) .* -1 + (A ~= 0) .* A;
copies A but assigns -1 everywhere that A is zero.
However, because the question deals with infinity or NaNs, it can be done even more succinctly:
Z = FAV ./ A; % produces inf where A == 0
Z = (A ~= 0) .* FAV ./ A; % produces NaN where A == 0
Are you looking for all non-zero elements? You can do this a couple of ways.
nonzero = find(A); % returns indicies to all non-zero elements of A
y = x./A(nonzero); % divides x by all non-zero elements of A
% y will be the same size as nonzero
Or for a one-liner, you can use a conditional in place of indicies
y = x./A(A~=0); % divides x by all non-zero elements of A
What you need to do is identify the elements you want to operate on. I would use FIND. I store the results in VI (Valid Indicies) and use that to populate the matrix.
clear
clc
den = [2 0 2; 0 2 0; -2 -2 -2]
num = ones(size(den));
frac = nan(size(den));
vi = (den ~=0)
frac(vi) = num(vi)./den(vi)
vi = (den == 0)
frac(vi) = nan %just for good measure...