diagonal averaging of matrix in matlab - 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];

Related

How to split a matrix based on how close the values are?

Suppose I have a matrix A:
A = [1 2 3 6 7 8];
I would like to split this matrix into sub-matrices based on how relatively close the numbers are. For example, the above matrix must be split into:
B = [1 2 3];
C = [6 7 8];
I understand that I need to define some sort of criteria for this grouping so I thought I'd take the absolute difference of the number and its next one, and define a limit upto which a number is allowed to be in a group. But the problem is that I cannot fix a static limit on the difference since the matrices and sub-matrices will be changing.
Another example:
A = [5 11 6 4 4 3 12 30 33 32 12];
So, this must be split into:
B = [5 6 4 4 3];
C = [11 12 12];
D = [30 33 32];
Here, the matrix is split into three parts based on how close the values are. So the criteria for this matrix is different from the previous one though what I want out of each matrix is the same, to separate it based on the closeness of its numbers. Is there any way I can specify a general set of conditions to make the criteria dynamic rather than static?
I'm afraid, my answer comes too late for you, but maybe future readers with a similar problem can profit from it.
In general, your problem calls for cluster analysis. Nevertheless, maybe there's a simpler solution to your actual problem. Here's my approach:
First, sort the input A.
To find a criterion to distinguish between "intraclass" and "interclass" elements, I calculate the differences between adjacent elements of A, using diff.
Then, I calculate the median over all these differences.
Finally, I find the indices for all differences, which are greater or equal than three times the median, with a minimum difference of 1. (Depending on the actual data, this might be modified, e.g. using mean instead.) These are the indices, where you will have to "split" the (sorted) input.
At last, I set up two vectors with the starting and end indices for each "sub-matrix", to use this approach using arrayfun to get a cell array with all desired "sub-matrices".
Now, here comes the code:
% Sort input, and calculate differences between adjacent elements
AA = sort(A);
d = diff(AA);
% Calculate median over all differences
m = median(d);
% Find indices with "significantly higher difference",
% e.g. greater or equal than three times the median
% (minimum difference should be 1)
idx = find(d >= max(1, 3 * m));
% Set up proper start and end indices
start_idx = [1 idx+1];
end_idx = [idx numel(A)];
% Generate cell array with desired vectors
out = arrayfun(#(x, y) AA(x:y), start_idx, end_idx, 'UniformOutput', false)
Due to the unknown number of possible vectors, I can't think of way to "unpack" these to individual variables.
Some tests:
A =
1 2 3 6 7 8
out =
{
[1,1] =
1 2 3
[1,2] =
6 7 8
}
A =
5 11 6 4 4 3 12 30 33 32 12
out =
{
[1,1] =
3 4 4 5 6
[1,2] =
11 12 12
[1,3] =
30 32 33
}
A =
1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3
out =
{
[1,1] =
1 1 1 1 1 1 1
[1,2] =
2 2 2 2 2 2
[1,3] =
3 3 3 3 3 3 3
}
Hope that helps!

Two simple examples on vectorizing for loops in matlab

Unfortunately my programming skills are not that advanced and I really need to vectorize some loops to finish my thesis.
I tried to make things really clear and simple and I have the following two questions in matlab:
1.
If we have a 5x5 matrix A and we want to set the diagonal elements of this matrix to the diagonal of a matrix B, apart from diag(A)=diag(B) we could use :
for i=1:5
B(i,i)=A(i,i)
end
Now if I want to vectorize this I can not use:
i=1:5
B(i,i)=A(i,i)
In that way we assign each combination from 1:5. So, in the end we asign each element of A equal to B and not the diagonal.
Is there some way that we could assign each identical pair of (i,i)?
I tried :
i=1:5
j=1:5
B(i,find(j==i))=A(i,find(j==i))
But still does not work. I repeat I know the diag property but Im only interested on the particular problem.
2.
A similar problem is the fillowing.
b=[ones(2,2) ones(2,2)*2 ones(2,2)*3 ones(2,2)*4] ;
a = zeros(8,12);
for i=1:4
a((i-1)*2+1:(i)*2,(i-1)*3+1:(i)*3) = [8*ones(2,1) b(:,[2*(i-1)+1 2*i])];
end
Thank you for your time and for your help.
Let's bring some mask magic, shall we!
Problem #1
mask = eye(size(A))==1
A(mask) = B(mask)
For creating the mask, you can also use bsxfun -
N = size(A,1)
bsxfun(#eq,[1:N]',1:N)
Or finally, you can use linear indexing -
N = size(A,1)
A(1:N+1:N^2) = B(1:N+1:N^2)
Sample run -
>> A
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
>> B
B =
5 5 2 8 2
1 1 6 5 2
7 8 5 4 4
1 8 9 8 8
1 7 6 1 8
>> mask = eye(size(A))==1;
>> A(mask) = B(mask)
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
Problem #2
%// Append 8's at the start of every (2,2) block in b
b1 = reshape([8*ones(2,4) ; reshape(b,4,[])],2,[])
%// Mask where b1 values are to be put in an otherwise zeros filled array
mask = kron(eye(4,4),ones(2,3))==1
%// Initialize output arraya and set values from b1 into masked places
out = zeros(size(mask))
out(mask) = b1
For your first problem. Use logical indexing:
index = diag(ones(1,size(B,1))
B(index) = A(index)

How to split vector by zeros in MATLAB

I have got a problem with splitting a vector by zeros.
I have a vector for example
v=[1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]
I need to get vectors like
v1=[1 3 2 6 4]
v2=[2 4 6]
v3=[3 1]
Is there any way to do this by using MATLAB functions?
Of course I don't know of how many subvectors are included in main vector v and how many zeros delimits vectors.
I'm not a programmer and also I'm not a pro in MATLAB.
I know a procedural way to do this but want do it by MATLAB somehow.
I found a function A = strsplit(str,delimiter) but I don't have string I have a vector.
So I searched for conversion function. I found S = char(V) but when I executed it it crashed.
It's better to have the output as a cell array, not as separate variables. That way the output will be easier to handle.
Try this:
v = [1 3 2 6 4 0 0 2 4 6 0 0 0 3 1]; %// data
w = [false v~=0 false]; %// "close" v with zeros, and transform to logical
starts = find(w(2:end) & ~w(1:end-1)); %// find starts of runs of non-zeros
ends = find(~w(2:end) & w(1:end-1))-1; %// find ends of runs of non-zeros
result = arrayfun(#(s,e) v(s:e), starts, ends, 'uniformout', false); %// build result
Result (for your example):
>> result{:}
ans =
1 3 2 6 4
ans =
2 4 6
ans =
3 1
The strsplit() solution for a vector of whole numbers smaller than 9 (so a very specific solution, for a general solution see Luis Mendo's). Split and convert back to number:
res = strsplit(char(v), char(0));
res = cellfun(#(x) x - 0,res,'un',0);
celldisp(res)
res{1} =
1 3 2 6 4
res{2} =
2 4 6
res{3} =
3 1

reconstruct time series from given matrix

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

What is the simplest way to create a weight matrix bases on how frequent each element appear in the matrix?

This is the input matrix
7 9 6
8 7 9
7 6 7
Based on the frequency their appearance in the matrix (Note. these values are for explanation purpose. I didn't pre-calculate them in advance. That why I ask this question)
number frequency
6 2
7 4
8 1
9 2
and the output I expect is
4 2 2
1 4 2
4 2 4
Is there a simple way to do this?
Here's a three-line solution. First prepare the input:
X = [7 9 6;8 7 9;7 6 7];
Now do:
[a m n] = unique(X);
b = hist(X(:),a);
c = reshape(b(n),size(X));
Which gives this value for c:
4 2 2
1 4 2
4 2 4
If you also wanted the frequency matrix, you can get it with this code:
[a b']
Here is a code with for-loop (a is input matrix, freq - frequency matrix with 2 columns):
weight = zeros(size(a));
for k = 1:size(freq,1)
weight(a==freq(k,1)) = freq(k,2);
end
Maybe it can be solved without loops, but my code looks like:
M = [7 9 6 ;
8 7 9 ;
7 6 7 ;];
number = unique(M(:));
frequency = hist(M(:), number)';
map = containers.Map(number, frequency);
[height width] = size(M);
result = zeros(height, width); %allocate place
for i=1:height
for j=1:width
result(i,j) = map(M(i,j));
end
end