I have a 2-D matrix A(value, label). I want to find the label that has the largest and second largest sum of values. For example:
A = (1, 1;
2, 1;
3, 2;
4, 2;
5, 3)
In this case the result should be largest = 2, second largest = 3. How can I do this in MATLAB?
[b,m,n]=unique(a(:,2));
[val, idx]= sort(accumarray(n,a(:,1)),'descend');
b(idx(1:2))
Output is:
ans =
2
3
Something like this should do the trick.
A = [1, 1;
2, 1;
3, 2;
4, 2;
5, 3];
labels = unique(A(:,2)); % Pull out unique labels
for i = 1:numel(labels)
idx = (A(:,2) == labels(i)); % Find elements which match current label
s(i,1) = sum(A(idx,1)); % Sum them
end
r = sortrows([s labels], -1); % Sort by decreasing sum
r(1,2); % Label corresponding to largest sum
r(2,2); % Label corresponding to second largest sum
EDIT accumarray is a built-in function that will do this for you. Although I find the documentation on it somewhat cryptic.
Since your question isn't super clear and i don't get what sum you are referring to I'm just gonna guess that you are aiming for something like this
q=sortrows(A,-1);
q=q(1:2,:);
which will give the two labels (right column) with the largest values (left column) in q.
If this wasn't what you were looking for please comment.
EDIT: Missread which column that contained labels, corrected
Related
Let X = [1, 2, 3, 4, 5] and Y = [1, 2, 1, 0, 1] be vectors where X maps into Y.
Now I want to identify the maximum and minimum of Y, which is easy: [value_min, id_min] = min(Y) = [0, 4] and [value_max, id_max] = max(Y) = [2, 2].
Then I want to remove the element from X corresponding to the minimum in Y and expand evenly around the element in X corresponding to the maximum in Y, while keeping the number of points equal. For this example we remove X(4)=[]. Then we expand like X(2)=(X(2) - X(1))/2 and X(3)=(X(3) - X(2))/2 such that X looks like X = [1, 1.5, 2.5, 3, 5]. How can I achieve this? I think there is a general pattwern.
Solution
Now the following snipped should work for any vector of length N. Note that the first and final element are fixed.
[value_max, id_max] = max(Y(2:N-1));
X(id_max) = (X(id_max) - X(id_max-1))/2;
X(id_max+1) = (X(id_max+1) - X(id_max))/2;
[value_min, id_min] = min(Y(2:N-1));
X(id_min)=[];
Here is a solution to your problem but there are a few things you should take care of
% Any Vector should work
X=[1 2 3 4 5];
Y=[1 2 1 0 1];
%We dont need the actual min max
[~,MIN]=min(Y(2:end-1));
[~,MAX]=max(Y(2:end-1));
%you dont look at the first element so the index has to be increased by 1
MIN=MIN+1;
MAX=MAX+1;
X(MIN)=[];%taking out the smallest element
Xnew= [X(1:MAX) X(MAX:end)]; %Extend the vector by taking the MAX value twice
%the mean for 2 elements is A+B/2
Xnew(MAX)=mean(Xnew(MAX-1:MAX)); %the left one and the element next to it
Xnew(MAX+1)=mean(Xnew(MAX+1:MAX+2)); %the right one and the element next ot it
%rewrite X and clear Xnew
X=Xnew;
clear Xnew;
First of all this isnt very efficient, but if its just used to
modify some vectors and not get called a million times a day it will
do the trick.
In your text you say remove the minima then stretch
around the maxima, in your solution metacode it is the other way
around. this will influence the outcome when min and max are next to
each other, so please check which way you prefer.
Y isnt changed in this at all so it cant be performed multiple times on the same vector.
Is N (the length) of any importance later on? if not you can always just refer to "end"
Given a vector x belongs to R^n, an index subset I of S=(1, ..., n), I want to find the index of the largest elements of x in `I, or the index in the full vector.
In other words, how do I find the index of the largest element of a sub vector in the original vector's index space?
What's the best way to do this in MATLAB?
Currently, I use:
xmax = max(x(I));
i = I(x(I) == xmax);
i = i(1);
I'm looking for a more efficient way to achieve this.
Example:
x = [4, 2, 4];
S = [1, 2, 3];
I = [2, 3];
The desired output would be 3.
You can simply use the two output version of max. The second output will give you the location of where the maximum element was found. However, if there are multiple entries where the maximum was found, it will only find the first occurrence. You can then use the second output of max to index into I to get what you want. Therefore:
[~,loc] = max(x(I));
i = I(loc);
I have a vector whose elements identify the indices (per column) that I need to set in a different matrix. Specifically, I have:
A = 7
1
2
and I need to create a matrix B with some number of rows of zeros, except for the elements identified by A. In other words, I want B:
B = zeros(10, 3); % number of rows is known; num columns = size(A)
B(A(1), 1) = 1
B(A(2), 2) = 1
B(A(3), 3) = 1
I would like to do this without having to write a loop.
Any pointers would be appreciated.
Thanks.
Use linear indexing:
B = zeros(10, 3);
B(A(:).'+ (0:numel(A)-1)*size(B,1)) = 1;
The second line can be written equivalently with sub2ind (may be a little slower):
B(sub2ind(size(B), A(:).', 1:numel(A))) = 1;
This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 8 years ago.
I have an arbitrary n-by-n matrix. I want to look at sets of columns and rows of the matrix and do some analysis on them, for example by setting all elements of a specific set of rows and columns equal to zero. To do this I need to analyse all combinations of rows and columns.
For example, if n=3 the process selects the row and columns 1, 2, 3, 12, 13, 23, 123 in succession and creates a new variable for each row and column.
I am currently the technique below for a matrix of size 4:
H = [some 4-by-4 matrix]
for i1 = 1:n
for i2 = 1:n
for i3 = 1:n
for i4 = 1:n
% Set all rows and columns of all variables equal to 0
H(:,i1) = 0;
H(i1,:) = 0;
H(:,i2) = 0;
H(i2,:) = 0;
H(:,i3) = 0;
H(i3,:) = 0;
H(:,i4) = 0;
H(i4,:) = 0;
% Some more analysis on i1, i2, i3, i4...
end
end
end
end
This is an extremely crude method but it seems to work. Obviously, this technique looks at the set (1,1,1,1) which is equivalent to just (1) first, then (1,1,1,2) which is equivalent to (1,2), then (1,1,1,3) which is equivalent to (1,3)... and so on...
The problem here is that this is not a general process for any matrix of size n, this is only a crude process for a matrix of size 4.
Is there any way to generalise the process so that it works for any arbitrary n-by-n matrix?
Thanks!
You can reduce the arbitrary number of loops to one:
for k = 1:2^n-1
ind = dec2bin(k,n)=='1';
H(ind,:) = 0;
H(:,ind) = 0;
end
The trick is to use just one loop to create a logical index (ind) that tells which columns will be selected. So for n=4 the variable ind takes the values [0 0 0 1], [0 0 1 0], [0 0 1 1], ... [1 1 1 1].
Here is a neat way to do that with only two for loops and no magic function. It uses the binary representation of the integer numbers to decide whether to zero out a column and a row.
I just fix some values for the test
n = 3;
Mat = rand(n,n);
Then, we know that there are 2^n combinations, so let's number them from 0 to 2^n-1:
for tag=0:2^n-1
We make a copy to keep the original matrix untouched
myMat = Mat;
Now loop on the row and columns
for (i=1:n)
Here is the trick: if the i-th bit of tag (in binary) is 1, then we zero out the column and row, otherwise we keep it untouched.
if ( mod( floor(tag/2^(i-1)), 2) == 1 )
myMat(:,i) = 0;
myMat(i,:) = 0;
end
end
Finally display to check that we have what we need.
myMat
end
How does one create a vector that is composed of a random sampling of two other vectors?
For example
Vector 1 [1, 3, 4, 7], Vector 2 [2, 5, 6, 8]
Random Vector [random draw from vector 1 or 2 (value 1 or 2), random draw from vector 1 or 2 (value 3 or 5)... etc]
Finally, how can one ask matlab to repeat this process n times to draw a distribution of results?
Thank you,
There are many ways you could do this. One possibility is:
tmp=round(rand(size(vector1)))
res = tmp.*vector1 + (1-tmp).*vector2
To get one mixed sample, you may use the idea of the following code snippet (not the optimal one, but maybe clear enough):
a = [1, 3, 4, 7];
b = [2, 5, 6, 8];
selector = randn(size(a));
sample = a.*(selector>0) + b.*(selector<=0);
For n samples put the above code in a for loop:
for k=1:n
% Sample code (without initial "samplee" assignments)
% Here do stuff with the sample
end;
More generally, if X is a matrix and for each row you want to take a sample from a column chosen at random, you can do this with a loop:
y = zeros(size(X,1),1);
for ii = 1:size(X,1)
y(ii) = X(ii,ceil(rand*size(X,2)));
end
You can avoid the loop using clever indexing via sub2ind:
idx_n = ceil(rand(size(X,1),1)*size(X,2));
idx = sub2ind(size(X),(1:size(X,1))',idx_n);
y = X(idx);
If I understand your question, you are choosing two random numbers. First you decide whether to select vector 1 or vector 2; next you pick an element from the chosen vector.
The following code takes advantage of the fact that vector1 and vector2 are the same length:
N = 1000;
sampleMatrix = [vector1 vector2];
M = numel(sampleMatrix);
randIndex = ceil(rand(1,N)*M); % N random numbers from 1 to M
randomNumbers = sampleMatrix(randIndex); % sample N times from the matrix
You can then display the result with, for instance
figure; hist(randomNumbers); % draw a histogram of numbers drawn
When vector1 and vector2 have different elements, you run into a problem. If you concatenate them, you will end up picking elements from the longer vector more often. One way around this is to create random samplings from both arrays, then choose between them:
M1 = numel(vector1);
M2 = numel(vector2);
r1 = ceil(rand(1,N)*M1);
r2 = ceil(rand(1,N)*M2);
randMat = [vector1(r1(:)) vector2(r2(:))]; % two columns, now pick one or the other
randPick = ceil(rand(1,N)*2);
randomNumbers = [randMat(randPick==1, 1); randMat(randPick==2, 2)];
On re-reading, maybe you just want to pick "element 1 from either 1 or 2", then "element 2 from either 1 or 2", etc for all the elements of the vector. In that case, do
N=numel(vector1);
randPick = ceil(rand(1,N)*2);
randMat=[vector1(:) vector2(:)];
randomNumbers = [randMat(randPick==1, 1); randMat(randPick==2, 2)];
This problem can be solved using the function datasample.
Combine both vectors into one and apply the function. I like this approach more than the handcrafted versions in the other answers. It gives you much more flexibility in choosing what you actually want, while being a one-liner.