Suppose I specify a matrix A like
A = [1 2 3; 4 5 6; 7 8 9]
how can I query A (without using length(A)) to find out it has 3 columns?
Use the size() function.
>> size(A,2)
Ans =
3
The second argument specifies the dimension of which number of elements are required which will be '2' if you want the number of columns.
Official documentation.
While size(A,2) is correct, I find it's much more readable to first define
rows = #(x) size(x,1);
cols = #(x) size(x,2);
and then use, for example, like this:
howManyColumns_in_A = cols(A)
howManyRows_in_A = rows(A)
It might appear as a small saving, but size(.., 1) and size(.., 2) must be some of the most commonly used functions, and they are not optimally readable as-is.
When want to get row size with size() function, below code can be used:
size(A,1)
Another usage for it:
[height, width] = size(A)
So, you can get 2 dimension of your matrix.
Related
The specific task I'm trying to achieve is hard to describe, so here's an example: given A and x
A = [1 2;
3 0;
3 5;
4 0];
x = [1 2 3];
I want the algorithm to output
output: [1 2]
meaning that all of the nonzero elements in rows 1 and 2 in A are in x.
I have done this using cell arrays and loops; however, A and x are very large and my approach is not at all efficient. Also, I can't seem to figure out how to rework ismember to give me what I want. What is the fastest/least memory intensive method?
EDIT: Apologies, my original example was too simplistic. It is corrected now.
The first answer is good, but I would recommend to not using arrayfun. There are more eloquent ways to do what you ask. Use ismember combined with all, then index into the matrix A when you're done. Basically, your problem is to determine if a row has all of the values found in x and ignoring the zero values. In this case, we can find all of the values in the matrix A that are actually zero, then use this to augment our result.
Using A as the first input and x as the second input will return a matrix of the same size as A that tells you whether an element in A is found in x. If you want to check if all elements in the matrix A for a row can be found in x, check if all elements in a row is 1. On top of this, find all of the elements that are zero, then with the output of ismember set these to 1. This can be done with using a logical OR. After, you can use all and check each row independently by using the output of ismember as the first input into all and setting the second argument to 2. This would then return all of the rows in the matrix A where any column is found in x ignoring any values that are zero for a row in A which is what you're looking for:
A = [1 2; 3 0; 4 0];
x = [1 2 3];
mask = ismember(A, x);
ind = all(mask | A == 0, 2);
I'm also in favour of one-liners. We can consolidate this into one line of code:
ind = all(ismember(A, x) | A == 0, 2);
Even shorter is to simply invert A. All zero elements become true and false otherwise:
ind = all(ismember(A, x) | ~A, 2);
ind would thus be:
>> ind
ind =
3×1 logical array
1
1
0
Since you want the actual row indices, you can just use find on top of this:
>> find(ind)
ans =
1
2
To verify, let's use your second example in your comments:
>> A = [1 2;3 5;4 0];
>> x = [1 2 3];
>> ind = all(ismember(A, x) | ~A, 2)
ind =
3×1 logical array
1
0
0
>> find(ind)
ans =
1
I think the best way to rework ismember is to make sure there are no "no members" by just checking for the nonzero elements in A.
arrayfun can do the work in a fast way. It uses the most efficient parallel computing for your specific machine. The following line should return the correct output:
find(arrayfun(#(a) sum(~ismember(A(a,A(a,:)>0),x)),1:size(A,1))==0)
Is this what you were looking for?
However, if your problem is related to memory, then you may have to break the arrayfun operation into pieces (1:floor(size(A,1)/2), floor(size(A,1)/2):size(A,1) or smaller chunks), since MATLAB puts a bunch of workers to do the task, and may use all your available RAM memory...
I have a situation analogous to the following
z = magic(3) % Data matrix
y = [1 2 2]' % Column indices
So,
z =
8 1 6
3 5 7
4 9 2
y represents the column index I want for each row. It's saying I should take row 1 column 1, row 2 column 2, and row 3 column 2. The correct output is therefore 8 5 9.
I worked out I can get the correct output with the following
x = 1:3;
for i = 1:3
result(i) = z(x(i),y(i));
end
However, is it possible to do this without looping?
Two other possible ways I can suggest is to use sub2ind to find the linear indices that you can use to sample the matrix directly:
z = magic(3);
y = [1 2 2];
ind = sub2ind(size(z), 1:size(z,1), y);
result = z(ind);
We get:
>> result
result =
8 5 9
Another way is to use sparse to create a sparse matrix which you can turn into a logical matrix and then sample from the matrix with this logical matrix.
s = sparse(1:size(z,1), y, 1, size(z,1), size(z,2)) == 1; % Turn into logical
result = z(s);
We also get:
>> result
result =
8
5
9
Be advised that this only works provided that each row index linearly increases from 1 up to the end of the rows. This conveniently allows you to read the elements in the right order taking advantage of the column-major readout that MATLAB is based on. Also note that the output is also a column vector as opposed to a row vector.
The link posted by Adriaan is a great read for the next steps in accessing elements in a vectorized way: Linear indexing, logical indexing, and all that.
there are many ways to do this, one interesting way is to directly work out the indexes you want:
v = 0:size(y,2)-1; %generates a number from 0 to the size of your y vector -1
ind = y+v*size(z,2); %generates the indices you are looking for in each row
zinv = z';
zinv(ind)
>> ans =
8 5 9
Does any one know how I can convert a row vector [6 8 2] into a column vector without using a builtin command. I would like to do it without for loop.A ny idea please. Some one asked me is it a home work I say no, it's part of my work. I am trying to convert MATLAB code to vhdl using hdl coder but hdl coder seems not supporting transpose function.
Some options:
R = 1:10; %// A row vector
%// using built-in transpose
C = R'; %'// be warned this finds the complex conjugate
C = R.'; %'// Just swaps the rows and columns
C = transpose(R);
%// Flattening with the colon operator
C = R(:); %// usually the best option as it also convert columns to columns...
%// Using reshape
C = reshape(R,[],1);
%// Using permute
C = permute(R, [2,1]);
%// Via pre-allocation
C = zeros(numel(R),1);
C(1:end) = R(1:end);
%// Or explicitly using a for loop (note that you really should pre-allocate using zeros for this method as well
C = zeros(numel(R),1); %// technically optional but has a major performance impact
for k = 1:numel(R)
C(k,1) = R(k); %// If you preallocated then C(k)=R(k) will work too
end
%// A silly matrix multiplication method
C = diag(ones(numel(R),1)*R)
You can use the (:) trick
t = [1 2 3];
t(:)
ans =
1
2
3
UPDATE: you should use this method only in the following case: you have a vector (not matrix) and want to make sure it is a column-vector. This method is useful, when you don't know what type (column, row) of vector a variable has.
Check this out
t = [1 2 3]'; %// column vector
t(:)
ans =
1
2
3
However
A=magic(3);
A(:)
ans =
8
3
4
1
5
9
6
7
2
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).
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);