Implementing this equation in MATLAB with a for loop? - matlab

I am looking to implement the following equation in MATLAB since I have a very large matrix,
How would I be able to do this? It is not really about the 261 and for the sake of simplicity, we can assume d = 0.94, and there is no need to worry about the squared term nor mean term as I will be able to figure that out if I can get the loop concept down. So for instance, I will just try to calculate an average of all the past values in the rows with specific weights attached to them.
To clarify, we can essentially think of i as indexing the rows of a matrix and so this consists of an entire column which I provided as an example below. Ignoring the infinity, we can just sum it to period t, but the idea is that there is a certain weight placed on all the previous values of the rows where the most recent row has the greatest weight.
I was thinking of using something like this:
R = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10];
d = 0.94;
r = zeros(10,1);
for t = 2:10
r(t,1) = R(t,1);
for i = 1:10
W(i,1) = (1-d)*(d.^i)*r(t,1);
end
end
Or even indexing t = 1:10.
None of these works. In essence, I want to be able to calculate a mean for which there is greater weight placed to the most recent value. So for example, at row t=4, the value I would get would be:
(1-0.94)(0.94^3)*(1) + (1-0.94)(0.94^2)(2) +(1-0.94)(0.94)(3).

Right, if I understand you correctly, I think the following should work:
R = [1 2 3 4 5 6 7 8 9 10];
d = 0.94;
W = zeros(size(R));
% at t = 1, sigma will be 0
for t = 2:length(R)
meanR = mean(R(1:t-1));
for i = 1:t-1
W(t) = W(t) + 261*(1-d)*(d.^(t-i))*(R(i) - meanR)^2;
end
end

Related

Calculate the set of autocorrelation functions and then sum them

Good evening! I have a 3D vector. It has the first dimension 1. For clarity, I set it exactly the same as used in my program. "с" is like a number of experiments, in this case there are three, so I calculate the correlation function three times and then add them up.
In fact, the number of experiments is 100. I have to calculate 100 correlation functions and add them.
Tell me how you can do it automatically. And if possible, then no cycles. Thank you.
And yes, in the beginning I set the 3D vector using a loop. Is it possible to set it without a loop as well? This is certainly not my main question, but I would also like to know the answer to it.
d = [1 2 3];
c = [4 2 6];
for i = 1: length(c)
D(1,:,i) = d.*c(i);
end
D
X1 = xcorr(D(:,:,1));
X2 = xcorr(D(:,:,2));
X3 = xcorr(D(:,:,3));
X = X1+X2+X3;
With the help of a loop, my solution looks like this:
d = [1 2 3];
c = [4 2 6];
for i = 1: length(c)
D(1,:,i) = d.*c(i);
x(:,:,i) = xcorr(D(:,:,i));
end
X = sum(x,3)
It seems to be correct. Is it possible to do this without a cycle?
You can easily set your first array D without any loop, even though I don't know why you want to keep the first singleton dimension...
D(1, :, :) = d'.*c;
As for the sum of the autocorrelations, I'm not sure you can do it without a loop. The only thing that you can perhaps do is to not use an array to store the correlation for each index (if memory consumption is a problem for you) and just update the sum:
X = zeros(1, 2*length(d)-1); % initialize the sum array
for i = 1:length(c)
X = X + xcorr(D(:, :, i)); % update the sum
end

Shifting repeating rows to a new column in a matrix

I am working with a n x 1 matrix, A, that has repeating values inside it:
A = [0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4]
which correspond to an n x 1 matrix of B values:
B = [2;4;6;8;10; 3;5;7;9;11; 4;6;8;10;12; 5;7;9;11;13]
I am attempting to produce a generalised code to place each repetition into a separate column and store it into Aa and Bb, e.g.:
Aa = [0 0 0 0 Bb = [2 3 4 5
1 1 1 1 4 5 6 7
2 2 2 2 6 7 8 9
3 3 3 3 8 9 10 11
4 4 4 4] 10 11 12 13]
Essentially, each repetition from A and B needs to be copied into the next column and then deleted from the first column
So far I have managed to identify how many repetitions there are and copy the entire column over to the next column and then the next for the amount of repetitions there are but my method doesn't shift the matrix rows to columns as such.
clc;clf;close all
A = [0;1;2;3;4;0;1;2;3;4;0;1;2;3;4;0;1;2;3;4];
B = [2;4;6;8;10;3;5;7;9;11;4;6;8;10;12;5;7;9;11;13];
desiredCol = 1; %next column to go to
destinationCol = 0; %column to start on
n = length(A);
for i = 2:1:n-1
if A == 0;
A = [ A(:, 1:destinationCol)...
A(:, desiredCol+1:destinationCol)...
A(:, desiredCol)...
A(:, destinationCol+1:end) ];
end
end
A = [...] retrieved from Move a set of N-rows to another column in MATLAB
Any hints would be much appreciated. If you need further explanation, let me know!
Thanks!
Given our discussion in the comments, all you need is to use reshape which converts a matrix of known dimensions into an output matrix with specified dimensions provided that the number of elements match. You wish to transform a vector which has a set amount of repeating patterns into a matrix where each column has one of these repeating instances. reshape creates a matrix in column-major order where values are sampled column-wise and the matrix is populated this way. This is perfect for your situation.
Assuming that you already know how many "repeats" you're expecting, we call this An, you simply need to reshape your vector so that it has T = n / An rows where n is the length of the vector. Something like this will work.
n = numel(A); T = n / An;
Aa = reshape(A, T, []);
Bb = reshape(B, T, []);
The third parameter has empty braces and this tells MATLAB to infer how many columns there will be given that there are T rows. Technically, this would simply be An columns but it's nice to show you how flexible MATLAB can be.
If you say you already know the repeated subvector, and the number of times it repeats then it is relatively straight forward:
First make your new A matrix with the repmat function.
Then remap your B vector to the same size as you new A matrix
% Given that you already have the repeated subvector Asub, and the number
% of times it repeats; An:
Asub = [0;1;2;3;4];
An = 4;
lengthAsub = length(Asub);
Anew = repmat(Asub, [1,An]);
% If you can assume that the number of elements in B is equal to the number
% of elements in A:
numberColumns = size(Anew, 2);
newB = zeros(size(Anew));
for i = 1:numberColumns
indexStart = (i-1) * lengthAsub + 1;
indexEnd = indexStart + An;
newB(:,i) = B(indexStart:indexEnd);
end
If you don't know what is in your original A vector, but you do know it is repetitive, if you assume that the pattern has no repeats you can use the find function to find when the first element is repeated:
lengthAsub = find(A(2:end) == A(1), 1);
Asub = A(1:lengthAsub);
An = length(A) / lengthAsub
Hopefully this fits in with your data: the only reason it would not is if your subvector within A is a pattern which does not have unique numbers, such as:
A = [0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0;]
It is worth noting that from the above intuitively you would have lengthAsub = find(A(2:end) == A(1), 1) - 1;, But this is not necessary because you are already effectively taking the one off by only looking in the matrix A(2:end).

Multiple sampling with different sizes on Matlab

I am trying to implement this code so it works as quickly as possible.
Say I have a population of 100 different values, you can think of it as pop = 1:100 or pop = randn(1,100) to keep things simple. I have a vector n which gives me the size of samples I want to get. Say, for example, that n=[1 3 10 6 2]. What I want to do is to take 5 (which in reality is length(n)) different samples of pop, each consisting of n(i) elements without replacement. This means that for my first sample I want 1 element out of pop, for the second sample I want 3, for the third I want 10, and so on.
To be honest, I am not really interested in which elements are sampled. What I want to get is the sum of those elements that are present in the ith-sample. This would be trivial if I implemented it with a loop, but I am trying to avoid using them to keep my code as quick as possible. I have to do this for many different populations and with length(n)being very large.
If I had to do it with a loop, this would be how:
pop = randn(1,100);
n = [1 3 10 6 2];
sum_sample = zeros(length(n),1);
for i = 1:length(n)
sum_sample(i,1) = sum(randsample(pop,n(i)));
end
Is there a way to do this?
The only way to figure out what is fastest for you is to do a comparison of the different methods.
In fact the loop appears to be very fast in this case!
pop = randn(1,100);
n = [1 3 10 6 2];
tic
sr = #(n) sum(randsample(pop,n));
sum_sample = arrayfun(sr,n);
toc %% Returns about 0.004
clear su
tic
for t=numel(n):-1:1
su(t)=sum(randsample(pop,n(t)));
end
toc %% Returns about 0.003
You can create a function handle which choses the random samples and sums these up. Then you can use arrayfun to execute this function for all values of n:
pop = randn(1,100);
n = [1 3 10 6 2];
sr = #(n) sum(randsample(pop,n));
sum_sample = arrayfun(sr,n);
You can do something like this:
pop = randn(1,100);
n = [1 3 10 6 2];
sampled_data_index = randi(length(pop),1,sum(n));
sampled_data = pop(sampled_data_index);
The randi function randomly selects integer values in a specified range that is suitable for indexing. After you have the indices you can use those at once to sample the data from the pop database.
If you want to have unique indices you can replace the randi function with randperm:
sampled_data_index = randperm(length(pop),sum(n));
Finally:
You can have all the sampled values as a cell variable using the following code:
pop = randn(1,100);
n = [1 3 10 6 2];
fun = #(m) pop(randperm(length(pop),m));
C = arrayfun(fun,n,'UniformOutput',0)
Also having the sum of the sampled data:
funs = #(m) sum(pop(randperm(length(pop),m)));
sumC = arrayfun(funs,n)

Extract every element except every n-th element of vector

Given a vector
A = [1,2,3,...,100]
I want to extract all elements, except every n-th. So, for n=5, my output should be
B = [1,2,3,4,6,7,8,9,11,...]
I know that you can access every n-th element by
A(5:5:end)
but I need something like the inverse command.
If this doesn't exist I would iterate over the elements and skip every n-th entry, but that would be the dirty way.
You can eliminate elements like this:
A = 1:100;
removalList = 1:5:100;
A(removalList) = [];
Use a mask. Let's say you have
A = 1 : 100;
Then
m = mod(0 : length(A) - 1, 5);
will be a vector of the same length as A containing the repeated sequence 0 1 2 3 4.
You want everything from A except the elements where m == 4, i.e.
B = A(m ~= 4);
will result in
B == [1 2 3 4 6 7 8 9 11 12 13 14 16 ...]
Or you can use logical indexing:
n = 5; % remove the fifth
idx = logical(zeroes(size(A))); % creates a blank mask
idx(n) = 1; % makes the nth element 1
A(idx) = []; % ta-da!
About the "inversion" command you cited, it is possible to achieve that behavior using logical indexing. You can negate the vector to transform every 1 in 0, and vice-versa.
So, this code will remove any BUT the fifth element:
negatedIdx = ~idx;
A(negatedIdx) = [];
why not use it like this?
say A is your vector
A = 1:100
n = 5
B = A([1:n-1,n+1:end])
then
B=[1 2 3 4 6 7 8 9 10 ...]
One possible solution for your problem is the function setdiff().
In your specific case, the solution would be:
lenA = length(A);
index = setdiff(1:lenA,n:n:lenA);
B = A(index)
If you do it all at once, you can avoid both extra variables:
B = A( setdiff(1:end,n:n:end) )
However, Logical Indexing is a faster option, as tested:
lenA = length(A);
index = true(1, lenA);
index(n:n:lenA) = false;
B = A(index)
All these codes assume that you have specified the variable n, and can adapt to a different value.
For the shortest amount of code, you were nearly there all ready. If you want to adjust your existing array use:
A(n:n:end)=[];
Or if you want a new array called B:
B=A;
B(n:n:end)=[];

Sum of row elements between colMin and colMax, with different colMin and colMax for each row - Octave / Matlab

I have matrix
p=[1 2 3 4;
5 6 7 8;
10 20 30 50];
I'd like to compute the sum of the elements of each row that are between column iMin and iMax, with iMin and iMax being different for each row
e.g for
iMin = [3 2 1];
iMax = [4 4 3];
the result is
[7 21 60]
Is there an easy Octave / Matlab way to do this without loops ?
You can achieve this using logical indexing, following a similar approach to my answer to your other question.
Assuming that iMin and iMax have the same number of entries as the number of rows in p you can horizonally tile the column indices for p i.e. [1:size(p,2)] and compare this to vertical tilings of iMin and iMax to generate a logical index into p for the entries that satisfy your criterion so:
c_min=repmat(iMin',1,size(p,2))
c_max=repmat(iMax',1,size(p,2))
c_ind=repmat([1:size(p,2)],size(p,1),1)
result=sum(p.*(c_ind>=c_min & c_ind<=c_max),2)
Giving:
result =
7
21
60
No loops :-)
I know I'm a little late, but here's my contribution:
A one-liner with bsxfun:
sum((p.*bsxfun(#le,iMin(:),1:size(p,2)).*bsxfun(#ge,iMax(:),1:size(p,2))).')
A solution with linear indexing:
aux = [zeros(1,size(p,1)); cumsum(p.')];
rowjumps = 0:size(p,2)+1:numel(p);
result = aux(iMax+1+rowjumps) - aux(iMin+rowjumps);
I'm fairly sure that
[nRows,nCols]=size(p);
result = zeros(nRows,1);
for iRow = 1:nRow
result(iRow) = sum(p(iRow,iMin(iRow):iMax(iRow));
end
is the fastest solution, at least on more recent versions of Matlab.
To perform the summation in one go, you need to create an array of ones and zeros to mask p, i.e.
[nRows,nCols] = size(p);
idxCells = arrayfun(#(x,y)...
[false(1, x-1), true(1,y-x+1), false(1,nCols-y)], iMin, iMax,...
'UniformOutput',false);
result = sum( p .* cell2mat(idxCells), 2)