reconstruct time series from given matrix - matlab

suppose that we are creating following matrix from given signal
function [ x ]=create_matrix1(b,l)
n = length(b);
m = n-l+1;
x = zeros(m,l);
for i=1:m
x(i,:)=b(i:i+l-1);
end;
end
with some window length,for example
X=[2;1;3;4;5;7]
X =
2
1
3
4
5
7
>> B=create_matrix1(X,3)
B =
2 1 3
1 3 4
3 4 5
4 5 7
if we have given matrix and windows length ,how can i reconstruct original signal?let say i know that windows length is 3,thanks in advance,i think i should sum elements on anti diagonal and divide by number of elements in this anti diagonal ,but how can i do it by code?thanks in advance

Your original vector is located along the top and right edge of your matrix B and can be reconstructed like so:
>> X_reconstructed = [B(1,1:end-1).'; B(:,end)]
X_reconstructed =
2
1
3
4
5
7
In case the matrix B is some noisy matrix and you actually want to do the averages along the diagonals:
>> BB = fliplr(B);
>> X_mean = arrayfun(#(i) mean(diag(BB,i)), size(B,2)-1:-1:-size(B,1)+1).'
X_mean =
2
1
3
4
5
7

Related

Merging sorted pairs

I have two (or more but if solved for two, it's solved for any number) 2-by-N matrices which represent points with an x (the first row) and y (the second row) coordinates. The points are always sorted in the increasing x coordinate. What I want to do is I want to merge these two matrices into one 3-by-N matrix so that if two points (one from each matrix) have the same x coordinate, they would form one column in the new matrix, the first row being the x coordinate and the second and third row being the two y coordinates. However, if there is a point in one matrix that has x coordinate different than all other points in the second matrix, I still want to have full 3-element column that is placed such that the x coordinates are still sorted and the missing value from the other matrix is replaced by the nearest value with lower x coordinate (or NaN if there is none).
Better to explain by example.
First matrix:
1 3 5 7 % x coordinate
1 2 3 4 % y coordinate
Second matrix:
2 3 4 7 8 % x coordinate
5 6 7 8 9 % y coordinate
Desired result:
1 2 3 4 5 7 8 % x coordinate
1 1 2 2 3 4 4 % y coordinate from first matrix
NaN 5 6 7 7 8 9 % y coordinate from second matrix
My question is, how can I do it effectively in matlab/octave and numpy? (Effectively because I can always do it "manually" with loops but that doesn't seem right.)
You can do it with interp1 and the keyword 'previous' for strategy (you can also choose 'nearest' if you do not care if it is larger or smaller) and 'extrap' for allowing extrapolation.
Define the matrices
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
Then find the interpolation points
x = unique([a(1,:),b(1,:)]);
And interpolate
[x ; interp1(a(1,:),a(2,:),x,'previous','extrap') ; interp1(b(1,:),b(2,:),x,'previous','extrap') ]
Timeit results:
I tested the algorithms on
n = 1e6;
a = cumsum(randi(3,2,n),2);
b = cumsum(randi(2,2,n),2);
and got:
Wolfie: 1.7473 s
Flawr: 0.4927 s
Mine: 0.2757 s
This verions uses set operations:
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
% compute union of x coordinates
c = union(a(1,:),b(1,:));
% find indices of x of a and b coordinates in c
[~,~,ia] = intersect(a(1,:),c);
[~,~,ib] = intersect(b(1,:),c);
% create output matrix
d = NaN(3,numel(c));
d(1,:) = c;
d(2,ia) = a(2,:);
d(3,ib) = b(2,:);
% fill NaNs
m = isnan(d);
m(:,1) = false;
i = find(m(:,[2:end,1])); %if you have multiple consecutive nans you have to repeat these two steps
d(m) = d(i);
disp(d);
Try it online!
Your example:
a = [1 3 5 7; 1 2 3 4];
b = [2 3 4 7 8; 5 6 7 8 9];
% Get the combined (unique, sorted) `x` coordinates
output(1,:) = unique([a(1,:), b(1,:)]);
% Initialise y values to NaN
output(2:3, :) = NaN;
% Add x coords from `a` and `b`
output(2, ismember(output(1,:),a(1,:))) = a(2,:);
output(3, ismember(output(1,:),b(1,:))) = b(2,:);
% Replace NaNs in columns `2:end` with the previous value.
% A simple loop has the advantage of capturing multiple consecutive NaNs.
for ii = 2:size(output,2)
colNaN = isnan(output(:, ii));
output(colNaN, ii) = output(colNaN, ii-1);
end
If you have more than 2 matrices (as suggested in your question) then I'd advise
Store them in a cell array, and loop over them to do the calls to ismember, instead of having one code line per matrix hardcoded.
The NaN replacement loop is already vectorised for any number of rows.
This is the generic solution for any number of matrices, demonstrated with a and b:
mats = {a, b};
cmats = horzcat(mats);
output(1, :) = unique(cmats(1,:));
output(2:numel(mats)+1, :) = NaN;
for ii = 1:size(mats)
output(ii+1, ismember(output(1,:), mats{ii}(1,:))) = mats{ii}(2,:);
end
for ii = 2:size(output,2)
colNaN = isnan(output(:,ii));
output(colNaN, ii) = output(colNaN, ii-1);
end

Independent random selection with replacement of elements per column in a matrix

I have a matrix A which is of size r1 x c. I'm trying to create a matrix B which is of size r2 x c where for each individual column, I would like to randomly sample with replacement.
I wrote this code that does what I am looking for:
%// Define a random index :
RO = randi(r1,r2,c);
%// Define an output matrix
B = zeros(r2,c);
%// Perform selection
for i1 = 1:c
for i2 = 1:r2
B(i2,i1) = A(RO(i2,i1),i1);
end
end
Is there an easier and/or faster way to do this in MATLAB without loops?
If I am interpreting this code correctly, you have a matrix and for each column, you consider this to be an individual signal and you want to randomly sample r2 elements from each signal to create another r2 signal that possibly has duplicates. You wish to stack these columns horizontally to generate an output matrix. A property with this matrix is that for each column, this random sampling is applied only for the corresponding column in the input matrix.
You can certainly do this vectorized. The matrix RO would be used as row coordinates and the column coordinates, which we will call RC, would simply be matrix of enumerations where each row is the linear range 1:c and there are r2 of these stacked on top of each other. This can be achieved with repmat.
First obtain the linear indices of the row and column coordinates via sub2ind then use this to index into your input matrix A.
RO = randi(r1,r2,c);
RC = repmat(1:c,r2,1);
ind = sub2ind(size(A), RO, RC);
B = A(ind);
To show that this works, I've created the following data:
rng(123);
r1 = 5;
r2 = 10;
c = 3;
A = randi(10, r1, c);
Running your code above gives me:
>> B
B =
6 10 8
7 10 5
7 10 4
3 10 4
3 5 5
6 5 1
8 7 4
6 7 8
6 7 5
6 7 4
Using the same matrix RO that was generated, the more optimized code that I wrote also gives:
>> B
B =
6 10 8
7 10 5
7 10 4
3 10 4
3 5 5
6 5 1
8 7 4
6 7 8
6 7 5
6 7 4

find and index equal values in multidimensional matrix

I am producing a three dimensional matrix with two rows(e.g. a 2x1000x10 matrix). These contain x- and y-coordinates for dot motion paths, where the first line contains the x-coordinates and the second line the y-coordinates. The number of columns (here: 1000) depends on the length of the motion paths. The number of levels in the third dimension depends on the number of dots (here: 10).
I want to know if some dots are going to overlap, i.e. if any x- and y-coordinates across the third dimension at the same time point t, i.e. any combination of (:, t, :), are identical. So the comparison will be within the matrix.
i = [1:size(matrix, 3)];
j = [1:size(matrix, 3)];
t = [1:size(matrix, 2)];
crash = any(coordinates(:, t, i)==coordinates(:, t, j))
would be trivial because i and j can be the same and thus say that the point is equal to itself.
Do you know how I can detect equal value combinations across matrix dimensions? How do I index them if they exist?
I think this does what you want. To find out if there's a crash:
t = bsxfun(#eq, coordinates, permute(coordinates, [1 2 4 3]));
crash = any(sum(any(all(t,1),2),4)>1,3);
We first use bsxfun to compute a 4D array (t) that tests for equality in the same coordinate (1st dim) and the same position along path (2nd dim), where the 3rd and 4th dims run over all pairs of dots. A crash occurs if both coordinates (all(,...,1)) are equal for any column (any(...,2)) in more than one "other" dot (sum(...,4)>1) for any "reference" dot (any(...,3)). We need to specify "more than one" because any dot is at least equal to itself (for a given position and coordinate).
Example:
>> coordinates = randi(9,2,5,4)
coordinates(:,:,1) =
7 4 3 3 8
7 1 4 2 4
coordinates(:,:,2) =
8 7 8 4 8
4 4 7 2 9
coordinates(:,:,3) =
3 4 7 8 5
7 8 2 9 8
coordinates(:,:,4) =
6 2 7 8 5
2 4 8 3 1
>> t = bsxfun(#eq, coordinates, permute(coordinates, [1 2 4 3]));
>> crash = any(sum(any(all(t,1),2),4)>1,3)
crash =
0
>> coordinates(:,2,4) = coordinates(:,2,1) %// 4th dot equal to 1st dot in column 2
coordinates(:,:,1) =
7 4 3 3 8
7 1 4 2 4
coordinates(:,:,2) =
8 7 8 4 8
4 4 7 2 9
coordinates(:,:,3) =
3 4 7 8 5
7 8 2 9 8
coordinates(:,:,4) =
6 4 7 8 5
2 1 8 3 1
>> t = bsxfun(#eq, coordinates, permute(coordinates, [1 2 4 3]));
>> crash = any(sum(any(all(t,1),2),4)>1,3)
crash =
1
To find the coordinates of the crash:
t = bsxfun(#eq, coordinates, permute(coordinates, [1 2 4 3]));
[m,n,p] = size(coordinates);
ii = find(squeeze(all(bsxfun(#times, t, ...
bsxfun(#ne, reshape(1:p, 1,1,[]), reshape(1:p, 1,1,1,[]) )),1)));
[col, dot_ref, dot_oth] = ind2sub([n p p], ii);
In the latter example, this gives
col =
2
2
dot_ref =
4
1
dot_oth =
1
4
which tells you that the dot 4 equals dot 1 in column 2; and then of course that dot 1 equals dot 4 in column 2.
This computes the same t as above. It then multiplies by a logical mask along the third and fourth dimensions (bsxfun(#ne, reshape(1:p, 1,1,[]), reshape(1:p, 1,1,1,[]) )) to avoid detecting each dot as similar to itself. Finally, it requires that all coordinates (all(...,1)) be the same in order to declare two dots as crashing, and applies find to locate those dots. The result (ii) is a linear index into a 3D array of dimensions path length × number of dots × number of dots, which is translated by ind2sub into position along path and identities of crashing dots.
A=[1 2 ;3 4];B=[5 6;3 9];
A==B
ans =
0 0
1 0
This works in 2D, but also in 3D. You can find the location of the equal numbers by using find:
C=permute(A,[3 2 1]);
D=permute(B,[3 2 1]);
find(C==D)
ans =
3
where 3 is a linear index to the location of the equal number.
for ii = 1:size(A,3)-1
for jj = ii+1:size(A,3)
[r{ii,jj},c{ii,jj},v{ii,jj}] = find(squeeze(A(:,:,ii))==squeeze(A(:,:,jj)));
end
end
This will loop over your matrices in the third dimension, i.e. your physical dots. It will squeeze out the 2D matrix per dot and check that against every other dot's 2D matrix. If it finds any, it will store the row, column and value at the intersection in the cells r, c and v, where the indices correspond to the dot numbers, i.e. r{2,4} will give the row numbers of intersections between dot 2 and 4.

diagonal averaging of matrix in matlab

let us consider following matrix
A=[1 2 3 4;2 4 6 7;3 1 9 8]
A =
1 2 3 4
2 4 6 7
3 1 9 8
size of which can easily be calculated using
n,m]=size(A)
n =
3
m =
4
let us consider that we want to get following vector v
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2)/2;
v(3)=(A(3,1)+A(2,2)+A(1,3))/3;
v(4)=(A(3,2)+A(2,3)+A(1,4))/3;
v(5)=(A(3,3)+A(2,4))/2;
v(6)=A(3,4);
definitely we need vector with size
v=zeros(n+m-1,1);
i have calculated first two element which seems trivial
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
but all others i need to implement using cycles,please pay attention that i need it for general matrix using same principle,not exact for such matrix
my starting code is following
function [v]=dehankel(A);
%convert matrix A to vector using diagonal averaging
[n,m]=size(A);
v=zeros(n+m-1,1);
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
for i=2:3
for j=2:3
please help me how to continue
A =
1 2 3 4
2 4 6 7
3 1 9 8
[n,m]=size(A);
v=zeros(n+m-1,1);
i = 1;
for d = -(n-1):(m-1)
v(i) = mean(diag(flipud(A),d));
i = i+1;
end
It can be done without loops (not the most readable code, I admit):
B = zeros(size(A,1)+size(A,2)-1, size(A,2));
B(bsxfun(#plus, (1:size(A,1)).', (0:size(A,2)-1)*(size(A,1)+size(A,1)+1))) = A;
v = sum(B.')./[1:size(A,1) size(A,1):-1:1];

average 3rd column when 1st and 2nd column have same numbers

just lets make it simple, assume that I have a 10x3 matrix in matlab. The numbers in the first two columns in each row represent the x and y (position) and the number in 3rd columns show the corresponding value. For instance, [1 4 12] shows that the value of function in x=1 and y=4 is equal to 12. I also have same x, and y in different rows, and I want to average the values with same x,y. and replace all of them with averaged one.
For example :
A = [1 4 12
1 4 14
1 4 10
1 5 5
1 5 7];
I want to have
B = [1 4 12
1 5 6]
I really appreciate your help
Thanks
Ali
Like this?
A = [1 4 12;1 4 14;1 4 10; 1 5 5;1 5 7];
[x,y] = consolidator(A(:,1:2),A(:,3),#mean);
B = [x,y]
B =
1 4 12
1 5 6
Consolidator is on the File Exchange.
Using built-in functions:
sparsemean = accumarray(A(:,1:2), A(:,3).', [], #mean, 0, true);
[i,j,v] = find(sparsemean);
B = [i.' j.' v.'];
A = [1 4 12;1 4 14;1 4 10; 1 5 5;1 5 7]; %your example data
B = unique(A(:, 1:2), 'rows'); %find the unique xy pairs
C = nan(length(B), 1);
% calculate means
for ii = 1:length(B)
C(ii) = mean(A(A(:, 1) == B(ii, 1) & A(:, 2) == B(ii, 2), 3));
end
C =
12
6
The step inside the for loop uses logical indexing to find the mean of rows that match the current xy pair in the loop.
Use unique to get the unique rows and use the returned indexing array to find the ones that should be averaged and ask accumarray to do the averaging part:
[C,~,J]=unique(A(:,1:2), 'rows');
B=[C, accumarray(J,A(:,3),[],#mean)];
For your example
>> [C,~,J]=unique(A(:,1:2), 'rows')
C =
1 4
1 5
J =
1
1
1
2
2
C contains the unique rows and J shows which rows in the original matrix correspond to the rows in C then
>> accumarray(J,A(:,3),[],#mean)
ans =
12
6
returns the desired averages and
>> B=[C, accumarray(J,A(:,3),[],#mean)]
B =
1 4 12
1 5 6
is the answer.