Make a general import of upper triangular matrix in MATLAB - matlab

I have been trying to make a general import of Ghaul's answer to my earlier question about importing an upper triangular matrix.
Initial Data:
1.0 3.32 -7.23
1.00 0.60
1.00
A = importdata('A.txt')
A =
1.0000 3.3200 -7.2300
1.0000 0.6000 NaN
1.0000 NaN NaN
So you will have to shift the two last rows, like this:
A(2,:) = circshift(A(2,:),[0 1])
A(3,:) = circshift(A(3,:),[0 2])
A =
1.0000 3.3200 -7.2300
NaN 1.0000 0.6000
NaN NaN 1.0000
and then replace the NaNs with their symmetric counterparts:
A(isnan(A)) = A(isnan(A)')
A =
1.0000 3.3200 -7.2300
3.3200 1.0000 0.6000
-7.2300 0.6000 1.0000
I have this, so we get the complete matrix for any size:
A = importdata('A.txt')
for i = (1:size(A)-1)
A(i+1,:) = circshift(A(i+1,:),[0 i]);
end
A(isnan(A)) = A(isnan(A)');
Is this approach the best? There must be something better. I remember someone told me to try not to use for loops in MATLAB.
UPDATE
So this is the result. Is there any way to make it faster without the loop?
A = importdata('A.txt')
for i = (1:size(A)-1)
A(i+1,:) = circshift(A(i+1,:),[0 i])
end
A(isnan(A)) = 0;
A = A + triu(A, 1)';

Here's another general solution that should work for any size upper triangular matrix. It uses the functions ROT90, SPDIAGS, and TRIU:
>> A = [1 3.32 -7.23; 1 0.6 nan; 1 nan nan]; %# Sample matrix
>> A = spdiags(rot90(A),1-size(A,2):0); %# Shift the rows
>> A = A+triu(A,1).' %'# Mirror around the main diagonal
A =
1.0000 3.3200 -7.2300
3.3200 1.0000 0.6000
-7.2300 0.6000 1.0000

Here's one way without loop. If you have a more recent version of Matlab, you may want to check which solution is really faster, since loops aren't as bad as they used to be.
A = A'; %'# transpose so that linear indices get the right order
out = tril(ones(size(A))); %# create an array of indices
out(out>0) = A(~isnan(A)); %# overwrite the indices with the right number
out = out + triu(out',1); %'# fix the upper half of the array

Related

mvnrnd does not generates data with given average and correlation

let us suppose that we have following vector of averages
mu = [2,3]
and given correlation matrix
sigma = [1,1.5;1.5,3].
so we would have in matlab
>> mu = [2,3]
sigma = [1,1.5;1.5,3]
mu =
2 3
sigma =
1.0000 1.5000
1.5000 3.0000
now generate Multivariate normal random numbers with the given information
rng default % For reproducibility
r = mvnrnd(mu,sigma,100);
but mean of given matrix
>> mean(r)
ans =
2.1231 3.1217
and correlation matrix
>> corrcoef(r)
ans =
1.0000 0.9016
0.9016 1.0000
what is the reason of such difference? because of small sample size? thanks in advance

Operations within matrix avoiding for loops

I have a rather simple question but I can't get the proper result in MATLAB.
I am writing a code in Matlab where I have a 200x3 matrix. This data corresponds to the recording of 10 different points, for each of which I took 20 frames.
This is just in order to account for the error in the measuring system. So now I want to calculate the 3D coordinates of each point from this matrix by calculating an average of the measured independent coordinates.
An example (for 1 point with 3 measurements) would be:
MeasuredFrames (Point 1) =
x y z
1.0000 2.0000 3.0000
1.1000 2.2000 2.9000
0.9000 2.0000 3.1000
Point = mean(MeasuredFrames(1:3, :))
Point =
1.0000 2.0667 3.0000
Now I want to get this result but for 10 points, all stored in a [200x3] array, in intervals of 20 frames.
Any ideas?
Thanks in advance!
If you have the Image processing toolbox blockproc could be an option:
A = blockproc(data,[20 3],#(x) mean(x.data,1))
If not the following using permute with reshape works as well:
B = permute(mean(reshape(data,20,10,3),1),[2,3,1])
Explanation:
%// transform data to 3D-Matrix
a = reshape(data,20,10,3);
%// avarage in first dimension
b = mean(a,1);
%// transform back to 10x3 matrix
c = permute(b,[2,3,1])
Some sample data:
x = [ 1.0000 2.0000 3.0000
1.1000 2.2000 2.9000
0.9000 2.0000 3.1000
1.0000 2.0000 3.0000
1.1000 2.2000 2.9000
0.9000 2.0000 3.1000
1.0000 2.0000 3.0000
1.1000 2.2000 2.9000
0.9000 2.0000 3.1000
1.1000 2.2000 2.9000]
data = kron(1:20,x.').';
A = B =
1.5150 3.1200 4.4850
3.5350 7.2800 10.4650
5.5550 11.4400 16.4450
7.5750 15.6000 22.4250
9.5950 19.7600 28.4050
11.6150 23.9200 34.3850
13.6350 28.0800 40.3650
15.6550 32.2400 46.3450
17.6750 36.4000 52.3250
19.6950 40.5600 58.3050
If you do not have access to the blockproc function, you can do it with a combination of reshape:
np = 20 ; %// number of points for averaging
tmp = reshape( A(:) , np,[] ) ; %// unfold A then group by "np"
tmp = mean(tmp); %// calculate mean for each group
B = reshape(tmp, [],3 ) ; %// reshape back to nx3 matrix
In your case, replace A by MeasuredFrames and B by Points, and group in one line:
Points = reshape(mean(reshape( MeasuredFrames (:) , np,[] )), [],3 ) ;
Matrix multiplication can be used:
N=20;
L=size(MeasuredFrames,1);
Points = sparse(ceil((1:L)/N), 1:L, 1)*MeasuredFrames/N;

matlab: apply an operand on an array by a condition

I have an array like this:
>> a = [2,34,5,6,7,0,1,10]
now I want to reverse each element of this array.
By using 1 ./ a the result is:
ans =
0.5000 0.0294 0.2000 0.1667 0.1429 Inf 1.0000 0.1000
The Inf is not good for me, the answer should be
ans =
0.5000 0.0294 0.2000 0.1667 0.1429 0 1.0000 0.1000
I want to apply this on elements that are not zero!
How can I do that?
You could also reset the Inf value to zero afterwards:
>> b=1./a
b =
0.5000 0.0294 0.2000 0.1667 0.1429 Inf 1.0000 0.1000
>> b(isinf(b)) = 0
b =
0.5000 0.0294 0.2000 0.1667 0.1429 0 1.0000 0.1000
You can do it conditionally:
nz = a ~= 0; %// select using logical indexing
a(nz) = 1./a(nz);
A slightly more general approach than m.s.'s is to check for finite elements in the output using isfinite:
b = 1./a;
b( ~isfinite(b) ) = 0;
isfinite covers both inf values as well as NaN values, so if the element-wise function you are applying might generate both types of non-numeric values, isfinite handles them simultaneously for you.

Checking which rows switched given an original and an altered matrix in Matlab

I've been trying to wrap my head around this for awhile and was hoping to get some insight.
Suppose you have matrix A, then you switched rows until you ended up with matrix B;
A = [1 3 1;
3 2 1;
2 3 1;];
B = [3 2 1;
1 3 1;
2 3 1;];
invA =
0.0000 -1.0000 1.0000
-1.0000 -1.0000 2.0000
3.0000 5.0000 -7.0000
invB =
-1.0000 0.0000 1.0000
-1.0000 -1.0000 2.0000
5.0000 3.0000 -7.0000
How would I document these row switches?. I'm ultimately trying to alter the inverse of B to match with the inverse of A. My conclusion was that given 2 rows switched (aka between rows 1 and 2), the end result of the inverse would be identical except for switching the columns of (1 and 2) of the inverse B.
This is quite a basic algebra question.
You can write your matrix B as a product of a permutation matrix P and A:
B = PA;
(in your example: P = [0 1 0;1 0 0;0 0 1];).
Now you can invert B:
inv( B ) = inv( PA )
The inverse of a product is
= inv(A) * inv(P)
Since matrix P is a permutation matrix: inv(P) = P.'. Thus
= inv(A) * P.'
That is, inv(B) = inv(A) * P.' which means that you apply the permutation P to the columns of inv(A).
Note that a permutation P can represent more than a single switch between rows, moreover, permutations can be multiplies to account for repeated switching of rows.
An important comment: I use inv in this answer to denote the inverse of a matrix. However, when running Matlab and numerically inverting matrices it is un-recommended to use inv function explicitly.

MATLAB remove NaN values from matrix and shift values left

I am trying to compute column-wise differences in the following matrix:
A =
0 NaN NaN 0.3750 NaN
NaN 0.1250 0.2500 0.3750 NaN
I would like to obtain:
0.3750 NaN NaN
0.1250 0.1250 0.1250
Where I am essentially taking a columnwise difference, skipping NaN values and shifting values to the left.
A one-dimensional case would be:
A = [0 NaN 0.250 0.375 NaN 0.625];
NaN_diff(A) = [0.250 0.125 0.250];
Any way to do this efficiently in MATLAB without using inefficient find() queries per row?
Here's a solution that vectorizes most of the operations:
notNan = ~isnan(A);
numNN = sum(notNan,2);
shifted = NaN(size(A));
for r = 1:size(A,1)
myRow = A(r,:);
shifted(r,1:numNN(r)) = myRow(notNan(r,:));
end
nanDiff = diff(shifted,1,2);
Here is an alternative vectorized solution:
%// Convert to cell array without NaNs
[rows, cols] = size(A);
C = cellfun(#(x)x(~isnan(x)), mat2cell(A, ones(1, rows), cols), 'Uniform', 0);
%// Compute diff for each row and pad
N = max(sum(~isnan(A), 2));
C = cellfun(#(x)[diff(x) nan(1, N - length(x))], C, 'Uniform', 0);
%// Convert back to a matrix
nandiff = vertcat(C{:});
If you want to pad the result matrix with zeroes instead of NaN values, change the nan function call in nan(1, N - length(x)) to zeros.
Here is an alternative method that does require you to loop over each row, but should still have decent performance and feels very intuitive to me.
B = NaN(size(A,1),size(A,2)-1)
for i = 1:size(A,1)
idx = ~isnan(A(:,i))
B(i,1:sum(idx)) = diff(A(i,idx))
end
I'm aware that this is a rather old question, but for people like me who stumble into this page, here is a simpler (imho) solution to the question:
A = [0 NaN 0.250 0.375 NaN 0.625];
A(isnan(A))=[]; % identify index of NaN values and remove them from the array
B = diff(A);
Here is another simple solution without using a loop [but assuming all values are in ascending order]:
A=[0 NaN NaN 0.3750 NaN;NaN 0.1250 0.2500 0.3750 NaN]
A(isnan(A(:,1)))=0;
B=sort(A,2);
C=diff(B,1,2)