Pick x smallest elements in Matlab - matlab

I have a matrix of integer values, the x axis represent different days and y axis represents hour of the day. And in each cell is a number that indicates how many hours of the day of the day correspond some criteria of the day which is just going on. That's why I need to calculate it for every hour and not only at the end of the time.
The whole issue is I have then to pick 5 best days which have the lowest number (least corresponding). So basically in the matrix it means select 5 lowest numbers in the row and remember the indexes of the columns where the minimum is. (I need to know in which day it occured). Because at every time as the time goes on it can be 5 different days so sorting the whole table would do mess.
I can make it work really ugly by taking first 5 number and then when if I find smaller one on the way I will forget biggest one from the 5 and remember the index of the column for the new one. Yet this solution seems to be pretty sloppy. There has to be a better way in Matlab how to solve this.
Any ideas, functions that can make my life easier?
1 1 0 1 1 1 0 0 1 1
1 2 1 2 2 1 0 1 2 2
For example in these two rows indexed from 1-10, in the first row it should return columns
3,7,8 and two others not really caring which one.
In the second row it should return columns 7,8,6,1,3.

A = randi(60,100,2);
[min_val,index] = sort(A(:,2),'ascend');
output = [A(index(1:5),1) A(index(1:5),2)];
this should help you (I guess);

Probably one of the simplest (but not most efficient) way is to use the sort function (which also returns sorted indices):
>> [~,index] = sort([1 1 0 1 1 1 0 0 1 1]);
>> index(1:5)
ans =
3 7 8 1 2
>> [~,index] = sort([1 2 1 2 2 1 0 1 2 2]);
>> index(1:5)
ans =
7 1 3 6 8

Related

how to work with diagonals of a matrix in matlab without using loops?

Lets say I have a matrix and I want to change it's elements.
How can I tell matlab to go the element in the (i,j) place? for
example:
matrix(i;j) ---> if i=j (then do something for example matrix(i;j)^2
else ( do something else)
matrix=rand(n)
if (i=j)
matrix(i,j)=(matrix(i.j))^
else matrix(i,j)=matrix(i,j)*3
end
now how can I reach the matrix's diagonals? I am new to matlab and I didn't find an answer yet :\
I am looking for a hint or something but I can't use loops!
hey i got the answer but lets say i also want the opposite diagonal to be in square how can i do this ?? plz any help
> if a=1 2 3
> 4 5 6
> 7 8 9 i want a at the end to be a= 1 6 9
> 12 25 18
> 49 24 81
It is obvious that you do not know the basics of MATLAB. Here I will try to explain what you need a little bit, but I encourage you to read the basic documentations of programming MATLAB.
If your matrix is called A then each element can be accessed through the indices (number of row and column) of that element, for instance A(2,3) gives you the element on the second row and third column.
Also diag(A) gives all the diagonal elements of A as a vector.
What you have mentioned can be done in different ways, some of which are more efficient than the others but might be more difficult for a beginner. One of the simplest methods is using two for-loops. The first loop moves on the rows of the matrix while the second moves on the column. The goal is to check all the elements one by one.
Here, we use two variables ii and jj to count for matrix rows and columns.
ii moves on the rows, so it has to count from 1 to the number of rows your matrix has. The same is done for columns using variable jj. Moreover, to find the number of rows and columns of the matrix we use function size.
Inside the two for-loops we check if the element is a on the main diagonal with ii==jj and if its not then you do something else to that elements.
for ii=1:size(A,1)
for jj=1:size(A,2)
if ii==jj
A(ii,jj) = A(ii,jj)^2;
else
A(ii,jj) = A(ii,jj)*3;
end
end
end
A way more efficient solution is as follows:
diag(diag(A)).^2 + (tril(A,-1)+triu(A,1))*3
The firs part calculates a diagonal matrix with the elements on the main diagonal of A. The second part gets the upper and lower triangular parts of matrix.
Example:
A = [1 2 3 4;
1 2 3 4;
4 3 2 1;
4 3 2 1];
>> diag(diag(A))
ans =
1 0 0 0
0 2 0 0
0 0 2 0
0 0 0 1
>> (tril(A,-1)+triu(A,1))
ans =
0 2 3 4
1 0 3 4
4 3 0 1
4 3 2 0
Where
diag(diag(A)) + (tril(A,-1)+triu(A,1)) equals to A

MATLAB: sample from population randomly many times?

I am aware of MATLAB's datasample which allows to select k times from a certain population. Suppose population=[1,2,3,4] and I want to uniformly sample, with replacement, k=5 times from it. Then:
datasample(population,k)
ans =
1 3 2 4 1
Now, I want to repeat the above experiment N=10000 times without using a for loop. I tried doing:
datasample(repmat(population,N,1),5,2)
But the output I get is (just a short excerpt below):
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
1 3 2 1 3
Every row (result of an experiment) is the same! But obviously they should be different... It's as though some random seed is not updating between rows. How can I fix this? Or some other method I could use that avoids a for loop? Thanks!
You seem to be confusing the way datasample works. If you read the documentation on the function, if you specify a matrix, it will generate a data sampling from a selection of rows in the matrix. Therefore, if you simply repeat the population vector 10000 times, and when you specify the second parameter of the function - which in this case is how many rows of the matrix to extract, even though the actual row locations themselves are different, the actual rows over all of the matrix is going to be the same which is why you are getting that "error".
As such, I wouldn't use datasample here if it is your intention to avoid looping. You can use datasample, but you'd have to loop over each call and you explicitly said that this is not what you want.
What I would recommend you do is first create your population vector to have whatever you desire in it, then generate a random index matrix where each value is between 1 up to as many elements as there are in population. This matrix is in such a way where the number of columns is the number of samples and the number of rows is the number of trials. Once you create this matrix, simply use this to index into your vector to achieve the desired sampling matrix. To generate this random index matrix, randi is a fine choice.
Something like this comes to mind:
N = 10000; %// Number of trials
M = 5; %// Number of samples per trial
population = 1:4; %// Population vector
%// Generate random indices
ind = randi(numel(population), N, M);
%// Get the stuff
out = population(ind);
Here's the first 10 rows of the output:
>> out(1:10,:)
ans =
4 3 1 4 2
4 4 1 3 4
3 2 2 2 3
1 4 2 2 2
1 2 3 4 2
2 2 3 2 1
4 1 3 2 4
1 4 1 3 1
1 1 2 4 4
1 2 4 2 1
I think the above does what you want. Also keep in mind that the above code generalizes to any population vector you want. You simply have to change the vector and it will work as advertised.
datasample interprets each column of your data as one element of your population, sampling among all columns.
To fix this you could call datasample N times in a loop, instead I would use randi
population(randi(numel(population),N,5))
assuming your population is always 1:p, you could simplify to:
randi(p,N,5)
Ok so both of the current answers both say don't use datasample and use randi instead. However, I have a solution for you with datasample and arrayfun.
>> population = [1 2 3 4];
>> k = 5; % Number of samples
>> n = 1000; % Number of times to execute datasample(population, k)
>> s = arrayfun(#(k) datasample(population, k), n*ones(k, 1), 'UniformOutput', false);
>> s = cell2mat(s);
s =
1 4 1 4 4
4 1 2 2 4
2 4 1 2 1
1 4 3 3 1
4 3 2 3 2
We need to make sure to use 'UniformOutput', false with arrayfun as there is more than one output. The cell2mat call is needed as the result of arrayfun is a cell array.

How to count patterns columnwise in Matlab?

I have a matrix S in Matlab that looks like the following:
2 2 1 2
2 3 1 1
3 3 1 1
3 4 1 1
3 1 2 1
4 1 3 1
1 1 3 1
I would like to count patterns of values column-wise. I am interested into the frequency of the numbers that follow right after number 3 in any of the columns. For instance, number 3 occurs three times in the first column. The first time we observe it, it is followed by 3, the second time it is followed by 3 again and the third time it is followed by 4. Thus, the frequency for the patters observed in the first column would look like:
3-3: 66.66%
3-4: 33.33%
3-1: 0%
3-2: 0%
To generate the output, you could use the convenient tabulate
S = [
2 2 1 2
2 3 1 1
3 3 1 1
3 4 1 1
3 1 2 1
4 1 3 1
1 1 3 1];
idx = find(S(1:end-1,:)==3);
S2 = S(2:end,:);
tabulate(S2(idx))
Value Count Percent
1 0 0.00%
2 0 0.00%
3 4 66.67%
4 2 33.33%
Here's one approach, finding the 3's then looking at the following digits
[i,j]=find(S==3);
k=i+1<=size(S,1);
T=S(sub2ind(size(S),i(k)+1,j(k))) %// the elements of S that are just below a 3
R=arrayfun(#(x) sum(T==x)./sum(k),1:max(S(:))).' %// get the number of probability of each digit
I'm going to restate your problem statement in a way that I can understand and my solution will reflect this new problem statement.
For a particular column, locate the locations that contain the number 3.
Look at the row immediately below these locations and look at the values at these locations
Take these values and tally up the total number of occurrences found.
Repeat these for all of the columns and update the tally, then determine the percentage of occurrences for the values.
We can do this by the following:
A = [2 2 1 2
2 3 1 1
3 3 1 1
3 4 1 1
3 1 2 1
4 1 3 1
1 1 3 1]; %// Define your matrix
[row,col] = find(A(1:end-1,:) == 3);
vals = A(sub2ind(size(A), row+1, col));
h = 100*accumarray(vals, 1) / numel(vals)
h =
0
0
66.6667
33.3333
Let's go through the above code slowly. The first few lines define your example matrix A. Next, we take a look at all of the rows except for the last row of your matrix and see where the number 3 is located with find. We skip the last row because we want to be sure we are within the bounds of your matrix. If there is a number 3 located at the last row, we would have undefined behaviour if we tried to check the values below the last because there's nothing there!
Once we do this, we take a look at those values in the matrix that are 1 row beneath those that have the number 3. We use sub2ind to help us facilitate this. Next, we use these values and tally them up using accumarray then normalize them by the total sum of the tallying into percentages.
The result would be a 4 element array that displays the percentages encountered per number.
To double check, if we look at the matrix, we see that the value of 3 follows other values of 3 for a total of 4 times - first column, row 3, row 4, second column, row 2 and third column, row 6. The value of 4 follows the value of 3 two times: first column, row 6, second column, row 3.
In total, we have 6 numbers we counted, and so dividing by 6 gives us 4/6 or 66.67% for number 3 and 2/6 or 33.33% for number 4.
If I got the problem statement correctly, you could efficiently implement this with MATLAB's logical indexing and an approach that is essentially of two lines -
%// Input 2D matrix
S = [
2 2 1 2
2 3 1 1
3 3 1 1
3 4 1 1
3 1 2 1
4 1 3 1
1 1 3 1]
Labels = [1:4]'; %//'# Label array
counts = histc(S([false(1,size(S,2)) ; S(1:end-1,:) == 3]),Labels)
Percentages = 100*counts./sum(counts)
Verify/Present results
The styles for presenting the output results listed next use MATLAB's table for a well human-readable format of data.
Style #1
>> table(Labels,Percentages)
ans =
Labels Percentages
______ ___________
1 0
2 0
3 66.667
4 33.333
Style #2
You can do some fancy string operations to present the results in a more "representative" manner -
>> Labels_3 = strcat('3-',cellstr(num2str(Labels','%1d')'));
>> table(Labels_3,Percentages)
ans =
Labels_3 Percentages
________ ___________
'3-1' 0
'3-2' 0
'3-3' 66.667
'3-4' 33.333
Style #3
If you want to present them in descending sorted manner based on the percentages as listed in the expected output section of the question, you can do so with an additional step using sort -
>> [Percentages,idx] = sort(Percentages,'descend');
>> Labels_3 = strcat('3-',cellstr(num2str(Labels(idx)','%1d')'));
>> table(Labels_3,Percentages)
ans =
Labels_3 Percentages
________ ___________
'3-3' 66.667
'3-4' 33.333
'3-1' 0
'3-2' 0
Bonus Stuff: Finding frequency (counts) for all cases
Now, let's suppose you would like repeat this process for say 1, 2 and 4 as well, i.e. find occurrences after 1, 2 and 4 respectively. In that case, you can iterate the above steps for all cases and for the same you can use arrayfun -
%// Get counts
C = cell2mat(arrayfun(#(n) histc(S([false(1,size(S,2)) ; S(1:end-1,:) == n]),...
1:4),1:4,'Uni',0))
%// Get percentages
Percentages = 100*bsxfun(#rdivide, C, sum(C,1))
Giving us -
Percentages =
90.9091 20.0000 0 100.0000
9.0909 20.0000 0 0
0 60.0000 66.6667 0
0 0 33.3333 0
Thus, in Percentages, the first column are the counts of [1,2,3,4] that occur right after there is a 1 somewhere in the input matrix. As as an example, one can see column -3 of Percentages is what you had in the sample output when looking for elements right after 3 in the input matrix.
If you want to compute frequencies independently for each column:
S = [2 2 1 2
2 3 1 1
3 3 1 1
3 4 1 1
3 1 2 1
4 1 3 1
1 1 3 1]; %// data: matrix
N = 3; %// data: number
r = max(S(:));
[R, C] = size(S);
[ii, jj] = find(S(1:end-1,:)==N); %// step 1
count = full(sparse(S(ii+1+(jj-1)*R), jj, 1, r, C)); %// step 2
result = bsxfun(#rdivide, count, sum(S(1:end-1,:)==N)); %// step 3
This works as follows:
find is first applied to determine row and col indices of occurrences of N in S except its last row.
The values in the entries right below the indices of step 1 are accumulated for each column, in variable count. The very convenient sparse function is used for this purpose. Note that this uses linear indexing into S.
To obtain the frequencies for each column, count is divided (with bsxfun) by the number of occurrences of N in each column.
The result in this example is
result =
0 0 0 NaN
0 0 0 NaN
0.6667 0.5000 1.0000 NaN
0.3333 0.5000 0 NaN
Note that the last column correctly contains NaNs because the frequency of the sought patterns is undefined for that column.

Subsetting rows from Matlab for which specific column has value greater than zero

I want to subset rows from matrix for which the value in third column is greater than zero. For example, I have a matrix :
test =
1 2 3
4 5 0
4 4 1
4 4 0
Now I want to subset it so that I have
subset =
1 2 3
4 4 1
Any quick suggestion on how I can do this in matlab?
Simply make a logical array that is true for every row you want to keep, and pass it as the index to the rows:
subset = test(test(:,3)>0, :)

Resorting rows in matrix in non-decreasing order based on the entries of an arbitrary column

I am working with nx2 matrices in Matlab, and what I'm trying to do is fairly simple in principle. I randomly generate a square matrix, I run it through a series of functions and I get an mx2 matrix. I use the unique function on the rows to get rid of repeated rows and I end up with an nx2 matrix. What I'm having trouble doing is further reducing this matrix so that for all entries in the first column that have the exact same entry, only keep the row with the highest number on the second column.
I was using a loop to check the ith and (i+1)th entries of the first column and store the rows with the highest value in the second column, but I am trying to avoid for-loops as much as possible.
If anyone has an idea or suggestion please let me know!
Example:
0 0 0 0
0 1 0 1 0 3
A= 0 3 ---> unique(A, 'rows') = 0 3 --WANT--> 1 1
1 0 1 0 2 4
1 0 1 1
0 0 2 1
2 1 2 4
1 1
2 4
What you are looking for is:
[u,~,n] = unique(A(:,1));
B = [u, accumarray(n, A(:,2), [], #max)];
I don't exactly understand your problem description, but it sounds like sortrows() may be of some help to you.