Sorting a vector by the number of time each value occurs - matlab

We have the following case:
Q = [idxcell{:,1}];
Sort = sort(Q,'descend')
Sort =
Columns 1 through 13
23 23 22 22 20 19 18 18 18 18 17 17 17
Columns 14 through 26
15 15 14 14 13 13 13 12 12 12 11 10 9
Columns 27 through 39
9 9 8 8 8 8 8 7 7 7 7 7 7
Columns 40 through 52
7 6 6 6 5 4 4 3 3 3 3 2 2
Columns 53 through 64
2 2 2 2 2 2 2 1 1 1 1 1
How can we sort matrix Sort according to how many times its values are repeated?
Awaiting result should be:
repeatedSort = 2(9) 7(7) 1(5) 8(5) 3(4) 18(4) 6(3) 9(3) 12(3) 13(3) 17(3) 4(2) 14(2) 15(2) 22(2) 23(2) 5(1) 10(1) 11(1) 19(1) 20(1)
or
repeatedSort = 2 7 1 8 3 18 6 9 12 13 17 4 14 15 22 23 5 10 11 19 20
Thank you in advance.

You can use the TABULATE function from the Statistics Toolbox, then call SORTROWS to sort by the frequency.
Example:
x = randi(10, [20 1]); %# random values
t = tabulate(x); %# unique values and counts
t = t(find(t(:,2)),1:2); %# get rid of entries with zero count
t = sortrows(t, -2) %# sort according to frequency
the result, where first column are the unique values, second is their count:
t =
2 4 %# value 2 appeared four times
5 4 %# etc...
1 3
8 3
7 2
9 2
4 1
6 1

Here's one way of doing it:
d = randi(10,1,30); %Some fake data
n = histc(d,1:10);
[y,ii] = sort(n,'descend');
disp(ii) % ii is now sorted according to frequency

Related

Sorting every layer of 3D matrix by one column each

I have a 3D matrix. Say it is:A = randi(15,[4,3,2]). I want to sort the 2nd column of each layer in an ascending order, but the other columns simply stayed in their respective rows. How can I do that?
If the two layers are like this
val(:,:,1) =
6 12 13
10 14 8
15 8 2
4 3 14
val(:,:,2) =
10 1 8
2 15 12
14 11 1
1 6 11
Then I want a result like this
val(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
val(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12
If you have the Image Processing Toolbox, using blockproc is one solution:
val(:,:,1) = [ ...
6 12 13
10 14 8
15 8 2
4 3 14]
val(:,:,2) = [ ...
10 1 8
2 15 12
14 11 1
1 6 11]
%// row indices to used for sorting
rowidx = 2;
[n,m,p] = size( val );
%// get a 2D matrix
val2D = reshape(val, n, [], 1)
%// sorting
out2D = blockproc(val2D,[n,m],#(x) sortrows(x.data,rowidx))
%// transform back to 3D
out3D = reshape(out2D, n, m, [])
Without the toolbox, maybe a little slower:
temp = arrayfun(#(x) sortrows(val(:,:,x),rowidx),1:size(val,3),'uni',0)
out3D = cat(3,temp{:})
out3D(:,:,1) =
4 3 14
15 8 2
6 12 13
10 14 8
out3D(:,:,2) =
10 1 8
1 6 11
14 11 1
2 15 12

Matlab: Cut Vector at missing values and create new vectors

I want to write a Matlab script.
In my example I have a vector A=[1 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 21]
Now I want to cut the vector automatically at the points where a number is missing(here the numbers 2, 6, 12, 18 are missing).
As a result I want to have the vectors [1] and [3 4 5] and [7 8 9 10 11] and [13 14 15 16 17] and [19 20 21]. So as you can see the new vectors have different lenghts.
I thought about using a for loop, but I am not sure how to write these new vectors.
Thank you for your help :)
One liner with diff, cumsum & accumarray -
out = accumarray(cumsum([0 ; diff(A(:))~=1])+1,A(:),[],#(x) {x})
Sample run -
>> A
A =
1 3 4 5 7 8 9 10 ...
11 13 14 15 16 17 19 20 21
>> celldisp(out)
out{1} =
1
out{2} =
3
4
5
out{3} =
7
8
9
10
11
out{4} =
13
14
15
16
17
out{5} =
19
20
21
This is one approach:
s = [find(diff(A(:).')>1) numel(A)]; %'// detect where consecutive difference exceeds 1
s = [s(1) diff(s)]; %// sizes of groups
result = mat2cell(A(:).', 1, s); %'// split into cells according to those sizes
In your example, this gives
>> celldisp(result)
result{1} =
1
result{2} =
3 4 5
result{3} =
7 8 9 10 11
result{4} =
13 14 15 16 17
result{5} =
19 20 21
Another approach (computes group sizes differently):
s = diff([0 sum(bsxfun(#lt, A(:), setdiff(1:max(A(:).'), A(:).')), 1) numel(A)]);
result = mat2cell(A(:).', 1, s);

Matlab filter matrix

My data matrix is large: smt like 180:3000 size.
Each element value is between 0 to 255;
I have to find areas in this matrix where average value is higher than some threshold (lets call it 'P'). And reset each element in these areas to '0'. Another words filter my matrix.
I have width and heigth of filter area.
So I need to loop over data matrix to find appropriate areas (As many as exist).
EDIT:
Please, see an example:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13
This is given matrix. Lets try to find areas (2, 3) of size where average value is > 15.
So the result will be:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
Please, look at bottom of matrix
Please, give me some tips how it is possible to loop throw.
Thank you very much.
One way of doint this is as follows:
% example A with more areas of mean greater than 15
% there are four such areas as shown here: http://i.imgur.com/V6m0NfL.jpg
A = [16 16 16 5 16 16 16
16 16 16 8 16 16 16
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 15.1 15 15 5 5
4 5 15 15 15 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13];
% filter size
[n,m] = deal(2,3);
% filter center
center = floor(([n,m]+1)/2);
% find where we have areas greater than 15
B = nlfilter(A, [n,m], #(b) mean(b(:)) > 15);
% get coordinates of areas with mean > 15
[rows,cols] = find(B);
% zero out elements in all found areas
for i = 1:size(rows,1)
% calculate starting coordinates for the area to be set to 0
row = rows(i) - center(1) + 1;
col = cols(i) - center(2) + 1;
A(row:row+n-1 , col:col+m-1) = 0;
end
Results in:
A =
0 0 0 5 0 0 0
0 0 0 8 0 0 0
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 0 0 0 5 5
4 5 0 0 0 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
try this
a = input_matrix;
ii = 2 ; jj = 3;
threshold = 15;
x = ones(ii,jj)/(ii*jj);
%\\create matrix temp2 with average value of block a(i:i+ii-1,j:j+jj-1) at temp2(i,j)
temp1 = conv2(a,x,'full');
temp2 = temp1(ii:end-ii+1,jj:end-jj+1);
%\\find row and column indices of temp2 with value > threshold
[row_ col_] = find(temp2>threshold);
out = a;
%\\assign zero value to the corresponding blocks
for iii = 1:length(row_)
out(row_(iii):row_(iii)+ii-1,col_(iii):col_(iii)+jj-1) = 0;
end

Change orientation of buffer function

I need a function that splits a vector in smaller frames with an overlap, like buffer, but instead of column-wise, it should be done row-wise.
This is how buffer works:
x = 1:20
x = buffer(x, 10, 5);
x = 0 1 6 11
0 2 7 12
0 3 8 13
0 4 9 14
0 5 10 15
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
What I want would be this though:
x = 0 0 1 2
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
11 12 13 14
13 14 15 16
15 16 17 18
17 18 19 20
Is there any function or way to achieve that? Maybe combination of buffer + some rearranging?
First figure out the answer in columns, then transpose the resulting matrix:
buffer(x, 4, 2).'

Extracting portions of matrix into cell array

I have a pretty large matrix M and I am only interested in a few of the columns. I have a boolean vector V where a value of 1 represents a column that is of interest. Example:
-1 -1 -1 7 7 -1 -1 -1 7 7 7
M = -1 -1 7 7 7 -1 -1 7 7 7 7
-1 -1 7 7 7 -1 -1 -1 7 7 -1
V = 0 0 1 1 1 0 0 1 1 1 1
If multiple adjacent values of V are all 1, then I want the corresponding columns of M to be extracted into another matrix. Here's an example, using the matrices from before.
-1 7 7 -1 7 7 7
M1 = 7 7 7 M2 = 7 7 7 7
7 7 7 -1 7 7 -1
How might I do this efficiently? I would like all these portions of the matrix M to be stored in a cell array, or at least have an efficient way to generate them one after the other. Currently I'm doing this in a while loop and it is not as efficient as I'd like it to be.
(Note that my examples only include the values -1 and 7 just for clarity; this isn't the actual data I use.)
You can utilize the diff function for this, to break your V vector into blocks
% find where block differences exist
diffs = diff(V);
% move start index one value forward, as first value in
% diff represents diff between first and second in original vector
startPoints = find(diffs == 1) + 1;
endPoints = find(diffs == -1);
% if the first block begins with the first element diff won't have
% found start
if V(1) == 1
startPoints = [1 startPoints];
end
% if last block lasts until the end of the array, diff won't have found end
if length(startPoints) > length(endPoints)
endPoints(end+1) = length(V);
end
% subset original matrix into cell array with indices
results = cell(size(startPoints));
for c = 1:length(results)
results{c} = M(:,startPoints(c):endPoints(c));
end
The one thing I'm not sure of is if there's a better way to find the being_indices and end_indices.
Code:
X = [1 2 3 4 5 1 2 3 4 5
6 7 8 9 10 6 7 8 9 10
11 12 13 14 15 11 12 13 14 15
16 17 18 19 20 16 17 18 19 20
1 2 3 4 5 1 2 3 4 5
6 7 8 9 10 6 7 8 9 10
11 12 13 14 15 11 12 13 14 15
16 17 18 19 20 16 17 18 19 20];
V = logical([ 1 1 0 0 1 1 1 0 1 1]);
find_indices = find(V);
begin_indices = [find_indices(1) find_indices(find(diff(find_indices) ~= 1)+1)];
end_indices = [find_indices(find(diff(find_indices) ~= 1)) find_indices(end)];
X_truncated = mat2cell(X(:,V),size(X,1),[end_indices-begin_indices]+1);
X_truncated{:}
Output:
ans =
1 2
6 7
11 12
16 17
1 2
6 7
11 12
16 17
ans =
5 1 2
10 6 7
15 11 12
20 16 17
5 1 2
10 6 7
15 11 12
20 16 17
ans =
4 5
9 10
14 15
19 20
4 5
9 10
14 15
19 20