MATLAB matrix range assignment - matlab

Is it possible to assign ranges to a matrix.
If you consider the below zeros matrix as a 'grid' for plotting:
R = zeros(5,8);
R =
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
So can you treat this matrix as a grid so each x-axis zero can considered as a range? for example R(5,1) is a range 0-0.1 seconds. R(5,2) is a range 0.1-0.2 seconds etc.
Can the range idea also be applied to the columns?
The purpose for this is so I can read cell array data I have already organised into ranges into the zeros matrix to produce a 2d histogram.

Assume you have the times tt and the datavalues val, where val(i) contains the datavalue for time tt(i). In your example you would have
tt = [0.02, 0.22, 0.15, 0.08, 0.27, 0.09];
val = [0.5, 1.4, 2.5, 0.6 , 0.8, 0.3 ];
Now you need vectors that represent the time and data ranges that you want (increasing), for example
trange = [0, 0.1, 0.2, 0.3, Inf];
valrange = [0, 1, 2, 3, Inf];
Now you create a matrix of the right size
R = zeros(length(valrange), length(trange));
You can fill the matrix up easily just by looping over all times you have
for i=1:length(tt)
%// We consider the pair tt(i), val(i)
%// First find out, in which time range tt(i) lies:
tind = find(trange > tt(i), 1, 'first');
%// Now find out, in which value range val(i) lies:
valind = find(valrange > val(i), 1, 'first');
%// Now we increase the corresponding matrix entry
R(valind,tind) = R(valind,tind) + 1;
end
Note that the first column corresponds to the time range between -Inf to trange(1) and the last column to the range between trange(end-1) and trange(end)==Inf. Simliary for the first and last row.

I'm not sure if I understand your question.
If you ask, whether it is possible to assign a vector, e.g. a = [1;2;3], to be a column in some matrix R = zeros(3, 5), then this can be achieved by
R(:, 1) = a;
R(:, 2) = [4;5;6];

Related

How to get pivot points of RREF matrix

I have this Reduced Row Echelon Form (RREF) matrix:
1 -2 0 1 1
0 0 1 0 -1
0 0 0 0 0
0 0 0 0 0
Is there a way to get the pivot points in Matlab? I know that it will be columns 1 and 3, but I am not sure how I can do this in Matlab.
For a Reduced Row Echelon Form matrix;
The first non-zero entry in any row is the number 1, these are called pivots (1)
If you assume that your matrix is already in RREF then we don't care about what each value is, only if it is 0 or not, so for some RREF matrix A:
A = logical(A);
Then we can find the first element in each row which is non-zero using max
[v,col] = max(A,[],2);
Finally we can remove values from col where v=0, i.e. rows which are entirely 0, leaving the pivots piv:
piv = col( v > 0 );
For your example, this returns col = [1; 3]
You could do this in one line, but it's not pretty
[~,piv] = max( logical(A(any(A,2),:)), [], 2 );
(1): https://www.math.fsu.edu/~bellenot/class/f08/lalab/other/rref2.pdf

How can I create a modified identity matrix?

I have an identity matrix in MATLAB which is used in some regression analysis for joint hypothesis tests. However, when I change the linear restrictions for my tests, I can no longer rely on the identity matrix.
To give a simple example, here is some code which produces an identity matrix depending on the value of y:
for i = [1, 2, 4]
y = i
x = 5;
H = eye(y*x)
end
However, what I need is not the identity matrix, but the first two rows and all others to be zero.
For the first example, the code produces an eye(5):
H =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
I need something that given y does not produce the identity but in fact produces:
H =
1 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
Can I adjust the identity matrix to include zeroes only after the first two rows?
I think the simplest solution is to make a matrix of all zeroes and then just place the two ones by linear indexing:
H = zeros(x*y);
H([1 x*y+2]) = 1;
Generalizing the above to putting the first N ones along the diagonal:
H = zeros(x*y);
H(x*y.*(0:(N-1))+(1:N)) = 1;
As suggested in this comment you can use diag:
diag([ones(2,1); zeros(x*y-2,1)])
This works because diag makes a vector become the main diagonal of a square matrix, so you can simply feed it the diagonal vector, which is your case would be 2 1s and the rest 0s.
Of course if you need a variable amount of 1s, which I was in doubt about hence the comment,
n=2;
diag([ones(n,1); zeros(x*y-n,1)])
Here are some alternatives:
Use blkdiag to diagonally concatenate an identity matrix and a zero matrix:
y = 5; x = 2;
H = blkdiag(eye(x), zeros(y-x));
A more exotic approach is to use element-wise comparisons with singleton expansion and exploit the fact that two NaN's are not equal to each other:
y = 5; x = 2;
H = [1:x NaN(1,y-x)];
H = double(bsxfun(#eq, H, H.'))

Matlab operation without loops

I have a matrix distance = [d11,d12,d13,d14;d15;...;dn1,dn2,dn3,dn4,dn5]; and a vector index(n,1). The value of index are between 1 and 5.
I want to get the sum of the distance according to the index if a vector R(1,5).
An example :
distance = [1,2,4,1,2 ; 4,5,6,1,6 ; 7,8,9,5,8] and index = [1;1;3]
So, I want R(1) = 1+4 = 5, R(2) = 0, R(3) = 9, and R(4) = R(5) = 0
The condition is to not use a loop over 1:5 with a if condition in order to minimise the time of execution if there are billions of points.
Maybe it is possible with arrayfun, but I don't succeed.
Best regards
To find out which elements you have to sum up, you can use the bsxfun to create a matrix containing a 1 if the value is relevant, and a 0 otherwise. This can done with
bsxfun(#eq, index, 1:5)
which will create a vector [1, 2, 3, 4, 5] and do an element-wise comparison between index and that vector. The result of this function is
ans =
1 0 0 0 0
1 0 0 0 0
0 0 1 0 0
Now you can multiply this matrix with the distance matrix (element-wise!) and finally sum over each column:
>> R = sum(bsxfun(#eq, index, 1:5) .* distance, 1);
which results in
R =
5 0 9 0 0

Merge two matrices in matlab

I have two matrices. One is of size 1,000,000 x 9 and the other is 500,000 x 9.
The columns have the same meaning and the first 7 columns have the function of a key. Correspondingly, the last two columns have data character. There are many overlapping key values in both of the matrices and I would like to have a big matrix to compare the values. This big matrix should be of dimension 1,000,000 x 11.
For example:
A = [0 0 0 0 0 0 0 10 20; 0 0 0 0 0 0 1 30 40];
B = [0 0 0 0 0 0 0 50 60];
A merged matrix would look like this:
C = [0 0 0 0 0 0 0 10 20 50 60; 0 0 0 0 0 0 1 30 40 0 0];
As you can see, the first row of C has columns 8, 9 from matrix A and columns 10,11 from matrix B. The second row uses the columns 8, 9 from matrix A and 0,0 for the last to columns because there is no corresponding entry in matrix B.
I have accomplished this task theoretically, but it is very, very slow. I use loops a lot. In any other programming language, I would sort both tables, would iterate both of the tables in one big loop keeping two pointers.
Is there a more efficient algorithm available in Matlab using vectorization or at least a sufficiently efficient one that is idiomatic/short?
(Additional note: My largest issue seems to be the search function: Given my matrix, I would like to throw in one column vector 7x1, let's name it key to find the corresponding row. Right now, I use bsxfun for that:
targetRow = data( min(bsxfun(#eq, data(:, 1:7), key), [], 2) == 1, :);
I use min because the result of bsxfun is a vector with 7 match flags and I obviously want all of them to be true. It seems to me that this could be bottleneck of a Matlab algorithm)
Maybe with ismember and some indexing:
% locates in B the last ocurrence of each key in A. idxA has logicals of
% those keys found, and idxB tells us where in B.
[idxA, idxB] = ismember(A(:,1:7), B(:,1:7),'rows');
C = [ A zeros(size(A, 1), 2) ];
C(idxA, 10:11) = B(idxB(idxA), 8:9); % idxB(idxA) are the idxB != 0
I think this does what you want, only tested with your simple example.
% Initial matrices
A = [0 0 0 0 0 0 0 10 20;
0 0 0 0 0 0 1 30 40];
B = [0 0 0 0 0 0 0 50 60];
% Stack matrices with common key columns, 8&9 or 10&11 for data columns
C = [[A, zeros(size(A,1),2)]; [B(:,1:7), zeros(size(B,1),2), B(:,8:9)]];
% Sort C so that matching key rows will be consecutive
C = sortrows(C,1:7);
% Loop through rows
curRow = 1;
lastRow = size(C,1) - 1;
while curRow < lastRow
if all(C(curRow,1:7) == C(curRow+1,1:7))
% If first 7 cols of 2 rows match, take max values (override 0s)
% It may be safer to initialise the 0 columns to NaNs, as max will
% choose a numeric value over NaN, and it allows your data to be
% negative values.
C(curRow,8:11) = max(C(curRow:curRow+1, 8:11));
% Remove merged row
C(curRow+1,:) = [];
% Decrease size counter for matrix
lastRow = lastRow - 1;
else
% Increase row counter
curRow = curRow + 1;
end
end
Answer:
C = [0 0 0 0 0 0 0 10 20 50 60
0 0 0 0 0 0 1 30 40 0 0]

Finding lengths of 0's separating islands of 1's and assigning them

I have a vector with alternating 0's and 1's and would like to convert each "1" to the length of the zeros that precede it. For example, I have x and would like to get to y:
x = [0 0 1 0 0 0 0 1 0 0 0 1 1 0 0 1]
y = [0 0 2 0 0 0 0 4 0 0 0 3 0 0 0 2]
I would really appreciate any suggestions on how to achieve this.
One approach with find & diff -
%// Initialize array, y with zeros and of length same as input, x
y = zeros(size(x))
%// Find places/indices where new values would be put
idx = find(x)
%// Calculate new values which would be the differentiated values of indices
%// and subtracted by 1 to account for the number of zeros in between two
%// non-zero values. We need to concatenate the indices array with one zero
%// at the start to account for the starting non-zero value in x
y(idx) = diff([0 idx])-1