How can I create a modified identity matrix? - matlab

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.'))

Related

Vector to matrix with row sum 1

I have a logical 1-by-n vector with sum m. Now, I need to convert it into a matrix m-by-n in a way that the row sum is equal 1.
vector (1-by-8) with sum 4
[0 1 0 0 1 0 1 1]
matrix (4-by-8) with row sum 1
[0 1 0 0 0 0 0 0;
0 0 0 0 1 0 0 0;
0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 1]
Is there a mathematically efficient way without calculating the sum, creating a empty matrix, loop through the vector and adding the 1s row by row?
I think that in that case, given your input, you don't even need to calculate the sum.
You can define an identity matrix of size n, then use your input vector to sample the required rows out of it:
I = eye(n);
y = I(x, :) ; % Output Matrix. x is the input vector
Here's another method, using sparse:
matrix = full(sparse(1:m, find(vector), 1, m, n));

How does Y = eye(K)(y, :); replace a "for" loop? Coursera

Working on an assignment from Coursera Machine Learning. I'm curious how this works... From an example, this much simpler code:
% K is the number of classes.
K = num_labels;
Y = eye(K)(y, :);
seems to be a substitute for the following:
I = eye(num_labels);
Y = zeros(m, num_labels);
for i=1:m
Y(i, :)= I(y(i), :);
end
and I have no idea how. I'm having some difficulty Googling this info as well.
Thanks!
Your variable y in this case must be an m-element vector containing integers in the range of 1 to num_labels. The goal of the code is to create a matrix Y that is m-by-num_labels where each row k will contain all zeros except for a 1 in column y(k).
A way to generate Y is to first create an identity matrix using the function eye. This is a square matrix of all zeroes except for ones along the main diagonal. Row k of the identity matrix will therefore have one non-zero element in column k. We can therefore build matrix Y out of rows indexed from the identity matrix, using y as the row index. We could do this with a for loop (as in your second code sample), but that's not as simple and efficient as using a single indexing operation (as in your first code sample).
Let's look at an example (in MATLAB):
>> num_labels = 5;
>> y = [2 3 3 1 5 4 4 4]; % The columns where the ones will be for each row
>> I = eye(num_labels)
I =
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
>> Y = I(y, :)
Y =
% 1 in column ...
0 1 0 0 0 % 2
0 0 1 0 0 % 3
0 0 1 0 0 % 3
1 0 0 0 0 % 1
0 0 0 0 1 % 5
0 0 0 1 0 % 4
0 0 0 1 0 % 4
0 0 0 1 0 % 4
NOTE: Octave allows you to index function return arguments without first placing them in a variable, but MATLAB does not (at least, not very easily). Therefore, the syntax:
Y = eye(num_labels)(y, :);
only works in Octave. In MATLAB, you have to do it as in my example above, or use one of the other options here.
The first set of code is Octave, which has some additional indexing functionality that MATLAB does not have. The second set of code is how the operation would be performed in MATLAB.
In both cases Y is a matrix generated by re-arranging the rows of an identity matrix. In both cases it may also be posible to calculate Y = T*y for a suitable linear transformation matrix T.
(The above assumes that y is a vector of integers that are being used as an indexing variables for the rows. If that's not the case then the code most likely throws an error.)

How to generate a vector that orthogonal to other vectors?

I have a matrix A which is
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
And a given vector v=[ 0 0 1 1 0] which has two elements one. I have to change the position of element one such that the new vector v is orthogonal to all the rows in the matrix A.
How can I do it in Matlab?
To verify the correct answer, just check gfrank([A;v_new]) is 5 (i.e v_new=[0 1 0 0 1]).
Note that: Two vectors uand v whose dot product is u.v=0 (i.e., the vectors are perpendicular) are said to be orthogonal.
As AVK also mentioned in the comments, v_new = [0 1 0 0 1] is not orthogonal to all rows of A.
Explanation:-
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
For A(1,:).*v = 0 to A(4,:).*v = 0,
0 x x 0 x % elements of v so that it's orthagonal to the 1st row of A
x 0 0 x x % -------------------------------------------- 2nd row of A
x x 0 0 x % -------------------------------------------- 3rd row of A
0 0 0 x x % -------------------------------------------- 4th row of A
where 0 represents the terms which have to be 0 and x represents the terms which can be either 0 or 1.
If you look as a whole, first 4 columns of v have to be zero so that the output is orthagonal to all rows of A. The 5th column can either be zero or 1.
So,
v_new can either be: v_new = [0 0 0 0 1] or v_new = [0 0 0 0 0]
From above explanation, you can also see that [0 1 0 0 1] is not orthagonal to 2nd and 4th row of A
Solution:-
To find v_new, you can use null function as: v_new = null(A).'
which gives: v_new = [0 0 0 0 1] for which gfrank([A;v_new]) also gives 5.
Maybe this will help you see the orthogonality between two vectors in N dimension.
N=100;
B1 = ones(1,N);
B2 = -1*ones(1,N/2);
B2 = [ones(1,N/2) B2];
B2 = transpose(B2);
B3 = dot(B1,B2);
The above code generates two vectors in N dimension. To check for orthogonality just transpose one of the vectors and multiply with the other one. You should get zero if they are Orthogonal.
The example I used makes sure that I get zero indeed.

Matlab: Can I create a matrix with unknown number of dimensions?

Normally a matrix has 2 dimensions, but there doesn't seem to be a limit on the number of dimensions a matrix may have in MATLAB.
To create a 4-dimensional matrix, for example, I can do this:
>> x = zeros(2,2,2,2)
x(:,:,1,1) =
0 0
0 0
x(:,:,2,1) =
0 0
0 0
x(:,:,1,2) =
0 0
0 0
x(:,:,2,2) =
0 0
0 0
Is there a way to create a matrix of which the number of dimensions is only known at runtime?
You could call zeros like this:
x = zeros([2 2 2 2])
Hence, you can customize the input array as you want.
For example: to create a 2x2x2x2x2 matrix (where D = 5, the number of dimensions):
D = 5;
x = zeros(zeros(1, D) + 2)
Rafael's answer hits the nail on the head. But there's also a general way to do this sort of thing even when the function doesn't have an overload for something like a vector input as in the case of zeros. You can use a cell array like so:
>> dims = {2,2,2,2};
>> zeros(dims{:})
ans(:,:,1,1) =
0 0
0 0
ans(:,:,2,1) =
0 0
0 0
ans(:,:,1,2) =
0 0
0 0
ans(:,:,2,2) =
0 0
0 0
I've found this approach to be very useful for other functions.
Edit:
This approach is more robust. Here's another example:
imginfo = { rand(40), [0 1], 'Colormap', colormap(jet) };
figure, imshow(a{:});

How to create symmetric zero and one matrix

I need to create a 100*100 symmetric matrix that has random distribution of zeros and ones, but the diagonal should be all zeros, how can I do that?
This is one way to do it:
N = 100; % size of square matrix
p = 0.5; % probability of 0s
A = triu(rand(N)>p, 1); % matrix of 0s and 1s (upper triangular part)
A = A + A'; % now it is symmetric
You can use a uniform distribution to generate your random numbers:
n = 100;
a = round(rand(n,n));
Now set the diagonal entries to zero (as discussed here by Jonas):
a(logical(eye(size(a)))) = 0;
Symmetric component:
aSym = floor((a + a')/2);
Example for n = 5:
aSym =
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 0 0 0 0
0 1 1 0 0
Edit: At randomatlabuser's suggestion, added line to calc the symmetric component of the matrix and eliminated loop to zero out entries on the diagonal