MATLAB: Reset Vector at Index - matlab

Consider the following vectors:
>> signals
signals =
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
>>exits
exits =
2
10
What I need to do is set the 1s to 0s in the signal matrix from each value in exits until the value in signals changes. For example, where exits=2, I would set the 1s to 0s in the signal vector at indicies 2, 3, and 4.
What I have done so far is to identify where the values change in the signal vector so that I can identify the start and stop index. For example:
>> find(diff(signals)~=0)
ans =
4
8
12
By doing this, I know I have to set the 1s to 0s from exits=2 to signals=4 and exits=10 to signals=12. I am stuck however in figuring out how to do this with no loops.
I realize this may be a bit vague, so here is a simpler example:
>> signals
signals =
1
1
1
1
1
0
0
0
1
1
1
>> exit
exit =
3
>> rst=exit:find(diff(signals)~=0)
rst =
3 4 5
signals =
1
1
0
0
0
0
0
0
1
1
1
I am basically trying to generalize this simple example to cases where there are multiple exit values and multiple different sequences of signals.

Looping is most certainly going to be the simpler and more readable solution. The way to make this without loops is to reconstruct the signals-array, keeping starts and throwing away redundant exits.
signals = [
1
1
1
1
1
0
0
0
1
1
1];
exit = 3;
startEnd = diff([0;signals]);
%# add the new exit
startEnd(exit) = -1;
%# remove redundant "exits"
startEndIdx = find(startEnd);
deltaEvent = diff([0;startEnd(startEndIdx)]);
deltaIsZero = deltaEvent == 0; %# these are the bad exits
startEnd(startEndIdx(deltaIsZero)) = 0;
%# now we can reconstruct the signals vector
signals = cumsum(startEnd)
signals =
1
1
0
0
0
0
0
0
1
1
1

Related

Performing an averaging operation over every n elements in a vector

I have a logical vector in which I would like to iterate over every n-elements. If in any given window at least 50% are 1's, then I change every element to 1, else I keep as is and move to the next window. For example.
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
output = func(input,4);
output = [0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1];
This function is trivial to implement but is it possible to apply a vectorized implementation using logical indexing?. I am trying to build up the intuition of applying this technique.
here's a one liner (that works for your input):
func = #(input,n) input | kron(sum(reshape(input ,n,[]))>=n/2,ones(1,n));
of course, there are cases to solve that this doesnt answer, what if the size of the input is not commensurate in n? etc...
i'm not sure if that's what you meant by vectorization, and I didnt benchmark it vs a for loop...
Here is one way of doing it. Once understood you can compact it in less lines but I'll details the intermediate steps for the sake of clarity.
%% The inputs
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
1) Split your input into blocks of size n (note that your final function will have to check that the number of elements in input is a integer multiple of n)
c = reshape(input,n,[]) ;
Gives you a matrix with your blocks organized in columns:
c =
0 0 0 0 0
0 1 0 1 0
0 1 0 0 0
1 0 1 1 1
2) Perform your test condition on each of the block. For this we'll take advantage that Matlab is working column wise for the sum function:
>> cr = sum(c) >= (n/2)
cr =
0 1 0 1 0
Now you have a logical vector cr containing as many elements as initial blocks. Each value is the result of the test condition over the block. The 0 blocks will be left unchanged, the 1 blocks will be forced to value 1.
3) Force 1 columns/block to value 1:
>> c(:,cr) = 1
c =
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
1 1 1 1 1
4) Now all is left is to unfold your matrix. You can do it several ways:
res = c(:) ; %% will give you a column vector
OR
>> res = reshape(c,1,[]) %% will give you a line vector
res =
0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1

Why my transfer function keep turn back in to 'logsig'?

   I try to build a basic feedforward system using patternnet command that can recognise the data from MNIST dataset. Here is my code
one = [1];
one = repelem(one,100);
%%%%%%%%%%%%%%%Create Neural network%%%%%%%%%%%%%%%%%%%%%
nn = patternnet([100 100]);
nn.numInputs = 1;
nn.inputs{1}.size = 784;
nn.layers{1}.transferFcn = 'logsig';
nn.layers{2}.transferFcn = 'logsig';
nn.layers{3}.transferFcn = 'softmax';
nn.trainFcn = 'trainscg';
net.divideParam.trainRatio = 70/100;
net.divideParam.valRatio = 15/100;
net.divideParam.testRatio = 15/100;
%%%%%%%%%%%%%%%%Dealing with data%%%%%%%%%%%%%%%%%%%%%%%%%%
mnist_in = csvread('mnist_train_100.csv');
mnist_test_in = csvread('mnist_test_10.csv');
[i,j] = size(mnist_in);
data_in = mnist_in(:,2:785);
data_in = data_in';
target_in = mnist_in(:,1);
target_in = target_in';
nn = train(nn,data_in,target_in);
   The problem is when I build this system the transfer function in output layer is set to softmax function. Somehow when I train my system the transfer function turn into 'logsig' function and it stay that way until I clear my workspace. I even try to set the transfer function of output layer in the code and program still find a way to change it to logsig. So is there anything I can do.
PS. I even try building this system using network() to make everything from scrath the program still change my tranfer function back from softmax to logsig.
As I see, there is a mistake in the divideParam parameter. You created the neural network as nn but the parameters that you changed is belong to a variable called net. Other than that, the creating neural network part is normal.
I think the problem lies in the data preparation part.
Your training target, the target_in, has the dimension of 1 x < Number of sample>. Because of that, the train function replace 'softmax' with 'logsig' to fit with the output.
The output data for softmax should be in the form of < Number of result> x < Number of sample>
For example, the output is either 1,2 or 3. Then the output array shouldn't be
[1 2 1 3 3 1 ...]
but it should be
[1 0 1 0 0 1 ...;
0 1 0 0 0 0 ...;
0 0 0 1 1 0 ...]
Hope this helps.
EDIT: To turn the single array (1 x < Number of sample>) to the multiple array (< Number of result> x < Number of sample>), the data in the single array will be map with index. For example, 11 sample in a single array:
[-1 -5.5 4 0 3.3 4 -1 0 0 0 -1]
Checking all the unique number and sort it. Now every number has its index.
[-5.5 -1 0 3.3 4] #index table
Going through the single array, for each number, place it in the right index. Basically, -1 will have index 2 so I will tick 1 in the second row at any column that -1 appear. Finally,
[ 0 1 0 0 0 0 0 0 0 0 0;
1 0 0 0 0 0 1 0 0 0 1; #there are three -1 in the single array
0 0 0 1 0 0 0 1 1 1 0;
0 0 0 0 1 0 0 0 0 0 0;
0 0 1 0 0 1 0 0 0 0 0]
Here is the code for it:
idx = sort(unique(target_in));
number_of_result = size(idx,2);
number_of_sample = size(target_in,2);
target_softmax = zeros(number_of_result,number_of_sample);
for i = 1:number_of_sample
place = find(idx == target_in(i)); % find the index of the value
target_softmax(place,i) = 1; % tick 1 at the row
end

Generating in Matlab a "modified" diagonal matrix

I want to construct a matrix A in Matlab of dimension w x (m*w) where
each row is full of zeros except m consecutive ones that shift towards the right hand side as we move down to the rows.
Few examples can clarify
w=3,m=4
A=[1 1 1 1 0 0 0 0 0 0 0 0;
0 0 0 0 1 1 1 1 0 0 0 0;
0 0 0 0 0 0 0 0 1 1 1 1]
or
w=3, m=3
A=[1 1 1 0 0 0 0 0 0;
0 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 1 1 1]
or
w=2, m=3
A=[1 1 1 0 0 0;
0 0 0 1 1 1]
I can't see how to proceed and any hint would be extremely helpful.
Step 1. Simplify the problem
If you write the "modified diagonal matrix" you are asking about as a row vector it will always look like the following
% 1 ... 1 0 ... ... 0 ... ... ... ... ... ... ... ... 1 ... 1
% m ones m*w zeros w-1 times the same as before m ones
Step 2. Think how to solve the simplified problem
The fundamental unit you need is a vector of m ones followed by m*w zeros;
Once you have built such vector, you need it to be repeated w times, MATLAB already knows how to do that;
The only thing you miss are the trailing ones: append them;
Now that the vector you were looking for is completed, you need to turn it into a matrix. MATLAB already knows how to do this too.
Final code
Once you understood the above steps, the final behaviour can be achieved even with a one-liner
>> m = 4; w = 3;
>> vec2mat([repmat([ones(1, m) zeros(1, m*w)], 1, w-1) ones(1, m)], w*m)
ans =
1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1
About speed
It's true, for loops aren't so slow anymore. I timed my one-liner solution, the trivial for loop and Luis Mendo's solution with eye() and repelem().
Click on images to zoom
Tested on the same machine, with MATLAB R2018a.
As you can see, as long as m and w are quite small, even if you could point out some differences in speed, them won't be noticeable to humans.
Anyway if you are going to work with bigger matrices, it becomes quite obvious which solution is the best.
Here are some approaches:
Using eye and repelem:
A = repelem(eye(w), 1, m);
Using eye and indexing:
A = eye(w);
A = A(1:w, ceil(1/m:1/m:w));
Using eye and kron:
A = kron(eye(w), ones(1,m));
Using singleton expansion:
A = bsxfun(#eq, (1:m).', ceil(1/m:1/m:w)); % Or A = (1:m).'==ceil(1/m:1/m:w);

Creating a square wave to overlay data set in matlab

In Matlab I am trying to achieve the following:
I have a data set that biologically represents activation in the brain when stimulus is given. So the data is such that we have 9 data points of stimulation, and then 15 of rest and it keeps going on like that for around 300 data points (4 mins in real-time).
I am able to plot the data easily but I am trying to overlay a square wave which represents the time in which there is "stimuluation" so that just by looking at the graph it is easy to see which is the rest period and which stimulation.
Very simply I have created a vector X and made it so that (the first 3 points are meant to be 0)
X = [0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0]
And plotted it on the same graph as the data. It works fine but the problem is that I need X to be created automatically according to my time scale.
Total_time = [-3:1.5:302]
This is my total time scale, from -3 to 302 seconds with the sampling rate as 1.5s. the first 3 points
-3, -1.5, 0 are period of rest. Then from 0 seconds the stimulus starts for about 9 seconds (that will make 6 data points in that 9 second period).
So my question is - is it possible to use some sort of for loop to create this vector X to say that for 6 data points from 0 X = 1 and for the next 10 X = 0? I was thinking of the following:
X = zeros(1,304) %to create a 1x304 vector of zeros
X(0:3)=0
X(3:9)=1
X(9:19)=0
But then again.. this is writing it by hand.
Can anyone help?
Thanks!
As you already told us: What you have is a repeating pattern.
In your case the pattern is the vector
pattern = [zeros(1,3) ones(1,9) zeros(1,15-3)];
So you could generate your signal by replicating this vector using repmat:
startTime = -3;
endTime = 302;
timeStep = 1.5;
%%// Computation
time = startTime:timeStep:endTime;
numPatterns = ceil(length(time)/length(pattern));
X = repmat(pattern, 1, numPatterns);
%// As the pattern will end after endTime, we remove everything beyond endTime
X(length(time)+1:end) = [];
%%// Plot
plot(time, X);
This is easy with modulo operations:
m = 3; %// initial low period
n = 6; %// high period
p = 10; %// low period
s = 304; %// x size
x = [zeros(1,m) mod(0:s-m-1, n+p)<n];
Result (first values):
0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 ...
Note that n and p can be non-integer if needed. For example, if the high period lasts for 5 seconds and your sampling period is 1.5 seconds, just define n=5/1.5, which gives
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 ...
As can be seen, the high period lasts either 4 or 3 samples to accomodate the non-integer n.

Effiicient ways to count a streak of consecutive integers in MATLAB

Say I have a vector containing only logical values, such as
V = [1 0 1 0 1 1 1 1 0 0]
I would like to write a function in MATLAB which returns a 'streak' vector S for V, where S(i) represents the number of consecutive 1s in V up to but not including V(i). For the example above, the streak vector would be
S = [0 1 0 1 0 1 2 3 4 0]
Given that I have to do this for a very large matrix, I would very much appreciate any solution that is vectorized / efficient.
This should do the trick:
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
The complexity is only O(n), which I guess should be good enough.
For your sample input:
V = [1 0 1 0 1 1 1 1 0 0];
S = zeros(size(V));
for i=2:length(V)
if(V(i-1)==1)
S(i) = 1 + S(i-1);
end
end
display(V);
display(S);
The result would be:
V =
1 0 1 0 1 1 1 1 0 0
S =
0 1 0 1 0 1 2 3 4 0
You could also do it completely vectorized with a couple intermediate steps:
V = [1 0 1 0 1 1 1 1 0 0];
Sall = cumsum(V);
stopidx = find(diff(V)==-1)+1;
V2=V;
V2(stopidx) = -Sall(stopidx)+[0 Sall(stopidx(1:end-1))];
S2 = cumsum(V2);
S = [0 S2(1:end-1)];
Afaik the only thing that can take a while is the find call; you can't use logical indexing everywhere and bypass the find call, because you need the absolute indices.
It's outside the box - but have you considered using text functions? Since strings are just vectors for Matlab it should be easy to use them.
Regexp contains some nice functions for finding repeated values.