create new vectors from columns of an existing matrix - matlab

I'd like to create new vectors from columns of an existing matrix. My code looks like:
Matrix=[1 2 3;4 5 6;7 8 9];
A=Matrix(:,1);
B=Matrix(:,2);
C=Matrix(:,3);
I see that this code is not really elegant especially if I have a big number of columns, that's why I'm looking for something like:
[A B C]=Matrix;
But Matlab said the matrix can't be assigned to multiple values. Is there another way?

use mat2cell to split your original matrix up and deal to assign the splitted data to the result variables A,B and C:
m = mat2cell(Matrix,size(Matrix,1),ones(1,size(Matrix,2)))
[A,B,C] = deal(m{:})
Unfortunately the intermediary variable is needed (however there is the FEX function dealcell that solves this if you like one-liners)

Why would you want to do this? (Just curious) Matlab is designed to work off of a matrix. Hence the name Matrix Labratory... But alas it is still possible.
I'm sure there's a more elegant solution but I'll let you ponder that. This should get you going.
Matrix=[1 2 3;4 5 6;7 8 9];
for i=1:size(Matrix,2) %number of rows
eval(sprintf('A%d = Matrix(:,i)', i));
end
A1 =
1
4
7
A2 =
2
5
8
A3 =
3
6
9

Related

1) Extract submatrices, 2) vectorize and then 3) put back

I simplify my problem, let says I have three matrices.
I want to extract the red-boxed sub-matrices. I define
S = [1 4;
2 5]
that are the linear indices of the above matrices. So, A(S), B(S) and C(S) can extract the entries of the three matrices.
I pack them into vector by V = [ A(S)(:); B(S)(:); C(S)(:) ]. Let says after some manipulations, I obtain a new vector
V_new = [12 9 8 12 21 8 7 5 3 12 11 10]'
Here comes to my problem:
E.g for matrix A, I want to obtain
2->12, 5->9, 4->8 and 6->12
which are the first four entries of my V_new.
Since I have around 200 matrices, I have no idea to swap along the 200 matrices and the updated vector, V_new at the same time. Is writing a for-loop best way to do this purpose?
Thanks in advance.
Assuming that your A, B and C matrices have the same dimensions, rather work with a 3D matrix.
e.g. assuming your example matrices
M = cat(3,A,B,C)
No to extract those 4 upper left elements:
M_subset = M(1:2,1:2,:)
And then to reshape them into the vector you had:
V = M_subset(:)
then manipulate it to get V_new and finally put it back in the original:
M(1:2,1:2,:) = reshape(V_new,2,2,[])

Matlab matrices dimension

I am new to matlab and just wondering if you guys can help me out with this problem.
For instance, I have two matrices:
A = [X1 X2 X3 X4]
B = [Y1; Y2; Y3]
now what I really want to achieve is to multiply these two matrices in this way:
[X1Y1 X2Y1 X3Y1 X4Y1;
X1Y2 X2Y2 X3Y2 X4Y2;
X1Y3 X2Y3 X3Y3 X4Y3;
.... and so on]
I tried using A(1,:).*B(:,1) but matlab is saying that matrix dimensions must agree.
I just don't know how to manipulate this on matlab but in excel is possible.
This is a simple outer product. kron is not needed (although it will work.) bsxfun is wild overkill, although will yield what you have asked for. repmat is inappropriate, because while it will help you do what you wish, it replicates the arrays in memory, using more resources than are needed. (Avoid using inefficient programming styles when there are good ones immediately at your disposal.)
All you need use is the simple * operator.
A is a row vector. B a column vector.
C = B*A
will yield the result C(i,j)=B(i)*A(j), which is exactly what you are looking for. Note that this works because B is 3x1 and A is 1x4, so the "inner" dimensions of B and A do conform.
In MATLAB, IF you are unsure if something works, TRY IT!
A = [1 2 3 4];
B = [1;2;3];
C = B*A
ans =
1 2 3 4
2 4 6 8
3 6 9 12
See that kron did indeed work, although I'd bet that use of kron here is probably less efficient than is the simple outer product multiply.
C = kron(B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
As well, bsxfun will work here too, although since we are using a general tool to do something that a basic operator will do, I'd bet it is slightly less efficient.
C = bsxfun(#times,B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
The WORST choice is repmat. Again, since it artificially replicates the vectors in memory FIRST, it must go out and grab big chunks of memory in the case of large vectors.
C = repmat(B,1,4).*repmat(A,3,1)
C =
1 2 3 4
2 4 6 8
3 6 9 12
I suppose for completeness, you could also have used meshgrid or ndgrid. See that it is doing exactly what repmat did, but here it explicitly creates new matrices. Again, this is a poor programming style when there are good tools to do exactly what you wish.
[BB,AA] = ndgrid(B,A)
BB =
1 1 1 1
2 2 2 2
3 3 3 3
AA =
1 2 3 4
1 2 3 4
1 2 3 4
C = BB.*AA
C =
1 2 3 4
2 4 6 8
3 6 9 12
What you need to understand is exactly why each of these tools COULD have been used for the job, and why they are different.
In Matlab there is * and .* and they are very different.
* is normal matrix multiplication which is what you want i.e. B*A, note the B must come first as the inner dimension must match. You can multiply a column by a row but not a row by a column (unless they have the same number of elements).
.* is element by element multiplication in which case the matrices must be exactly the same size and shape so for example [1 2 3].*[4 5 6] = [1*4 2*5 3*6] = [4 10 18]
Do not do a ".*". You should rather do a "*".
The ".*" is for index by index multiplication and should have given you [X1Y1 X2Y2 X3Y3] were they vectors have been equal in size.
If you do the regular multiplication "*", this is actually matrix multiplication.
I think you just need to transpose one of the vectors. You are multiplying a column vector (A(1,:)) with a row vector (B(:,1)). This should work:
C = A(1,:).*B(:,1)';

Extract fixed amounts of data from array based on a list of indices

I have the array
a=1:20
and a series of indices which indicate where I want to start pulling data out:
i=[4,12]
For each index i, I want that index and the next four (well, x, really) elements in a column or row. I'll avoid getting to close to the end of the array, so that special case can be disregarded.
If I was hard-coding this, I could use:
a([4:8;12:16])
and this would achieve my result.
But i may have many different values.
Any thoughts on how I can transform a list of indices into a matrix of ranges, or other ways to solve this problem?
EDIT
I am using Matlab 2007; it would be preferable if the solution relied solely on Matlab's internals and toolboxes. bsxfun is not present until 2007a.
Let i be your indicesx and x the number of elements you want in addition to the elements in i, then you can use
i = [4 6 8];
x = 4;
bsxfun(#plus, 0:x, i(:))
to get a matrix of indices:
ans =
4 5 6 7 8
6 7 8 9 10
8 9 10 11 12
If you do not have access to bsxfun you can use repmat instead:
i = [4 6 8];
x = 4;
repmat(i(:), 1, x+1) + repmat(0:x, length(i), 1)
Here is a solution without bsxfun but with repmat inspired by the previous answer.
i = [4 6 8];
x = 4;
p = repmat(1:x,length(i),1);
q = repmat(i',1,x);
p+q

splitting a Matrix into column vectors and storing it in an array

My question has two parts:
Split a given matrix into its columns
These columns should be stored into an array
eg,
A = [1 3 5
3 5 7
4 5 7
6 8 9]
Now, I know the solution to the first part:
the columns are obtained via
tempCol = A(:,iter), where iter = 1:end
Regarding the second part of the problem, I would like to have (something like this, maybe a different indexing into arraySplit array), but one full column of A should be stored at a single index in splitArray:
arraySplit(1) = A(:,1)
arraySplit(2) = A(:,2)
and so on...
for the example matrix A,
arraySplit(1) should give me [ 1 3 4 6 ]'
arraySplit(2) should give me [ 3 5 5 8 ]'
I am getting the following error, when i try to assign the column vector to my array.
In an assignment A(I) = B, the number of elements in B and I must be the same.
I am doing the allocation and access of arraySplit wrongly, please help me out ...
Really it sounds like A is alread what you want--I can't imagine a scenario where you gain anything by splitting them up. But if you do, then your best bet is likely a cell array, ie.
C = cell(1,3);
for i=1:3
C{i} = A(:,i);
end
Edit: See #EitanT's comment below for a more elegant way to do this. Also accessing the vector uses the same syntax as setting it, e.g. v = C{2}; will put the second column of A into v.
In a Matlab array, each element must have the same type. In most cases, that is a float type. An your example A(:, 1) is a 4 by 1 array. If you assign it to, say, B(:, 2) then B(:, 1) must also be a 4 by 1 array.
One common error that may be biting you is that a 4 by 1 array and a 1 by 4 array are not the same thing. One is a column vector and one is a row vector. Try transposing A(:, 1) to get a 1 by 4 row array.
You could try something like the following:
A = [1 3 5;
3 5 7;
4 5 7;
6 8 9]
arraySplit = zeros(4,1,3);
for i =1:3
arraySplit(:,:,i) = A(:,i);
end
and then call arraySplit(:,:,1) to get the first vector, but that seems to be an unnecessary step, since you can readily do that by accessing the exact same values as A(:,1).

Is there a vectorized way to operate on a different number of values per column in MATLAB?

In MATLAB, is there a more concise way to handle discrete conditional indexing by column than using a for loop? Here's my code:
x=[1 2 3;4 5 6;7 8 9];
w=[5 3 2];
q=zeros(3,1);
for i = 1:3
q(i)=mean(x(x(:,i)>w(i),i));
end
q
My goal is to take the mean of the top x% of a set of values for each column. The above code works, but I'm just wondering if there is a more concise way to do it?
You mentioned that you were using the function PRCTILE, which would indicate that you have access to the Statistics Toolbox. This gives you yet another option for how you could solve your problem, using the function NANMEAN. In the following code, all the entries in x less than or equal to the threshold w for a column are set to NaN using BSXFUN, then the mean of each column is computed with NANMEAN:
x(bsxfun(#le,x,w)) = nan;
q = nanmean(x);
I don't know of any way to index the columns the way you want. This may be faster than a for loop, but it also creates a matrix y that is the size of x.
x=[1 2 3;4 5 6;7 8 9];
w=[5 3 2];
y = x > repmat(w,size(x,1),1);
q = sum(x.*y) ./ sum(y)
I don't claim this is more concise.
Here's a way to solve your original problem: You have an array, and you want to know the mean of the top x% of each column.
%# make up some data
data = magic(5);
%# find out how many rows the top 40% are
nRows = floor(size(data,1)*0.4);
%# sort the data in descending order
data = sort(data,1,'descend');
%# take the mean of the top 20% of values in each column
topMean = mean(data(1:nRows,:),1);