Matlab removing duplicate matrix value - matlab

I have a matrix with a shape like below. I want to delete rows with duplicate values ​​in the first column and leaving row with the smallest number of duplicate values ​​in the second column. my matrix
`d =
1 1
2 1
4 1
8 2
2 2
5 4
2 4
6 4
7 3
`
I want to remove duplicate number 2 in the first column and leaving the row with the smallest number of duplicate values ​​in the second row
result required:
1 1
4 1
8 2
2 2
5 4
6 4
7 3
Thanks for the helps. best regard.

We can sort the array regards to first column and replace elements of second column by their descending count
to obtain this array:
1 3
2 3
2 3
2 2
4 3
5 3
6 3
7 1
8 2
Then if we apply unique to this array indices of desirable rows can be obtained and then then those rows can be extracted:
1 1
2 2
4 1
5 4
6 4
7 3
8 2
If oreder of original data should be preserved more step required that commented in the code.
a=[...
1 1
2 1
4 1
8 2
2 2
5 4
2 4
6 4
7 3];
%steps to replace counts of each element of column2 with it
[a2_sorted, i_a2_sorted] = sort(a(:,2));
[a2_sorted_unique, i_a2_sorted_unique] = unique(a2_sorted);
h = hist(a2_sorted, a2_sorted_unique);
%count = repelems(h, [1:numel(h); h]);%octave
count = repelem(h, h);
[~,a2_back_idx] = sort(i_a2_sorted);
count = count (a2_back_idx);
b = [a(:,1) , count.'];
%counts shoule be sorted in descending order
%because the unique function extracts last element from each category
[b_sorted i_b_sorted] =sortrows(b,[1 -2]);
[~, i_b1_sorted_unique] = unique(b_sorted(:,1));
c = [b_sorted(:,1) , a(i_b_sorted,2)];
out = c(i_b1_sorted_unique,:)
%more steps to recover the original order
[~,b_back_idx] = sort(i_b_sorted);
idx_logic = false(1,size(a,1));
idx_logic(i_b1_sorted_unique) = true;
idx_logic = idx_logic(b_back_idx);
out = c(b_back_idx(idx_logic),:)

Create a function that finds the minimal duplicate from the right column, given an index from the left column:
function Out = getMinDuplicate (Index, Data)
Candidates = Data(Data(:,1) == Index, :); Candidates = Candidates(:, 2);
Hist = histc (Data(:,2), [1 : max(Data(:,2))]);
[~,Out] = min (Hist(Candidates)); Out = Candidates(Out);
end
Call this function for all unique values in column 1:
>> [unique(d(:,1)), arrayfun(#(x) getMinDuplicate(x, d), unique(d(:,1)))]
ans =
1 1
2 2
4 1
5 4
6 4
7 3
8 2
(where d is your data array).

Related

sum of values in a column corresponding to first and last occurrence of a number in another column - matlab

a = [1 1 1 1 2 2 2 2 3 3 3 3; 1 2 3 4 5 6 7 8 9 10 11 12]';
What is the quickest way to sum the values in column 2 that correspond to the first and last occurrence of each number in column 1?
The desired output:
1 5
2 13
3 21
EDIT: The result should be the same if the numbers in column 1 are ordered differently.
a = [2 2 2 2 1 1 1 1 3 3 3 3; 1 2 3 4 5 6 7 8 9 10 11 12]';
2 5
1 13
3 21
You can use accumarray as follows. Not sure how fast it is, especially because it uses a custom anonymous function:
[u, ~, v] = unique(a(:,1), 'stable');
s = accumarray(v, a(:,2), [], #(x) x(1)+x(end));
result = [u s];
If the values in the first column of a are always in contiguous groups, the following approach can be used as well:
ind_diff = find(diff(a(:,1))~=0);
ind_first = [1; ind_diff+1];
ind_last = [ind_diff; size(a,1)];
s = a(ind_first,2) + a(ind_last,2);
result = [unique(a(:,1), 'stable') s];

Matlab Matrix Repeat Value

my matrix:
e =
1 2
2 3
3 3
4 3
5 2
i want to repeat value from first coloumn as much as number from the second coloumn in the same row. i want to make my matrix to be like:
e =
1 2
1 2
2 3
2 3
2 3
3 3
3 3
3 3
4 3
4 3
4 3
5 2
5 2
thank you for your help...
You can use repelem to repeat the row indices and then grab those rows from e:
new_e = e(repelem(1:size(e,1), e(:,2)), :);
If you're using a MATLAB version prior to 2015a that doesn't have repelem, here's another way to do it:
spacing = cumsum([1; e(:,2)]); % the rows of new_e where we change row values
row_indices(spacing) = 1; % make a vector with these elements = 1
row_indices = cumsum(row_indices); % convert to row indices, last index is invalid
new_e = e(row_indices(1:end-1), :); % select valid rows from e

indexing for loop matlab

I want to do the following:
I create a matrix with all possible permutations from 1:n, for example
n=4;
L=perms(1:n)';
I get as output as expected a 4-by-24 matrix:
L =
Columns 1 through 13
4 4 4 4 4 4 3 3 3 3 3 3
3 3 2 2 1 1 4 4 2 2 1 1
2 1 3 1 2 3 2 1 4 1 2 4
1 2 1 3 3 2 1 2 1 4 4 2
Columns 14 through 24
2 2 2 2 2 1 1 1 1 1 1
3 4 4 1 1 3 3 2 2 4 4
1 3 1 4 3 2 4 3 4 2 3
4 1 3 3 4 4 2 4 3 3 2
Now I want to use this matrix for the indexes of a for loop:
Using the first column, I want to feed the input of my loop the following indexes: i=4 j=3,2,1. Then for i=3 j=2,1. Then for i=2 j=1. i=1 is empty
This could be done just for the first column like this:
for u=4:-1:1
for v=u-1:-1:1
But will not work for other columns so I need to do the same but with the entries of matrix L, something like (it doesn't work in MATLB) for column i=1:
u=L(1:4,1)
v=L(u:L(4,1) , 1) %// where u corresponds to L(1,1) then L(2,1) then L(3,1)
(for all the columns it would look like:
for i=1:length(L)
for u=L(4*(i-1)+1:4*i)
for v=.. ?
)
This doesn't work because MATLAB takes the values of the entries and when I write L(1,1):L(4,1) it doesn't mean return the entries from line one to line four but rather all the numbers with increment 1 from the value of L(1,1) to the value of L(4,1) (here empty).
Any ideas ? thank you very much in advance
I believe something like this will solve you problem.
for col = 1:size(L,2)
rowIdx = 1;
for j = [L(:,col)]'
for k = [L(rowIdx:end,col)]'
% Do your stuff here
end
rowIdx = rowIdx + 1;
end
end
Notice how I use the values from columns from L directly as loop index variable. In a for loop statement you can basically write any row vector and the index takes those values. For example
for i = [1, 7, 11, 14, 23]
disp(i); % prints 1,7,11,14,23
end
This is true for arrays of objects, cell arrays, basically any single row matrix.
You can do it like this:
for col = 1:size(L, 2)
for I = 1:n-1
for J = I:n
i = L(I,col);
j = L(J,col);
%// As an example just print out the loop variable values
disp(sprintf('Col:%d\ti:%d\tj:%d\r\n',col,i,j))
end
end
end

Specific selection of rows from a matrix MATLAB

Consider the following the matrix:
1 2 1 1
1 3 1 1
2 5 2 3
2 6 2 4
2 6 2 4
2 9 0 0
3 4 5 6
3 4 1 1
3 2 0 0
3 1 1 1
.
.
.
I want to select the row(s) with the maximum value in column 2 for every unique value in column 1.
For eg.
Answer should be:
1 3 1 1
2 9 0 0
3 4 5 6
3 4 1 1
Any ideas?
Here's one way:
%// Get a unique list of column 1 without changing the order in which they appear
[C1, ~, subs] = unique(M(:,1), 'stable');
%// Get the max value from column 2 corresponding to each unique value of column 1
C2 = accumarray(subs, M(:,2), [], #max);
%// Find the desired row indices
I = ismember(M(:,1:2), [C1, C2], 'rows');
%//Extract the rows
M(I, :)
Some code to get you started:
% unique values in first column
col1 = unique(x(:,1));
% we first store results in a cell array (later converted to matrix)
xx = cell(numel(col1), 1);
for i=1:numel(col1)
% rows with the same value in column 1
rows = x(x(:,1) == col1(i),:);
% maximum value along column 2
mx = max(rows(:,2));
% store all rows with the max value (in case of ties)
xx{i} = rows(rows(:,2)==mx,:);
end
% combine all resulting rows
xx = vertcat(xx{:});
The result for the matrix you've shown:
>> xx
xx =
1 3 1 1
2 9 0 0
3 4 5 6
3 4 1 1

How to flip specific parts of a matrix

I am trying to flip certain parts of a matrix. I can explain better by example. Let's say that I have a matrix
M = [ 1 3 6;
1 2 4;
1 7 1;
2 9 0;
2 8 3;
2 4 2;
2 3 1;
3 6 5;
3 4 5;
3 1 9;
4 2 4;
4 8 6 ]
What I'd like to do here is take any rows with an even number in the first column, and flip the third column elements. The end result would look like this:
1 3 6
1 2 4
1 7 1
2 9 1 *
2 8 2 *
2 4 3 *
2 3 0 *
3 6 5
3 4 5
3 1 9
4 2 6 *
4 8 4 *
Note the rows marked with a star have had the elements of the third column flipped upside-down. The problem I'm having is going through each row like in a for-loop you cannot flip an entire set of rows.
Thanks in advance for any help.
Another time accumarray is the way to go:
A =[ 1 3 6 ;
1 2 4 ;
1 7 1 ;
2 9 0 ;
2 8 3 ;
2 4 2 ;
2 3 1 ;
3 6 5 ;
3 4 5 ;
3 1 9 ;
4 2 4 ;
4 8 6 ]
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} ); %// get groups according to
%// first column and flip it
C = vertcat(C{:}); %// cell array returned,
%// transform to matrix
mask = ~mod(A(:,1),2); %// mask for even numbers
A(mask,3) = C(mask); %// replace masked values of 3rd column with flipped ones
returns:
A =
1 3 6
1 2 4
1 7 1
2 9 1
2 8 2
2 4 3
2 3 0
3 6 5
3 4 5
3 1 9
4 2 6
4 8 4
Certainly slower, but just for fun in two lines:
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} );
A(~mod(A(:,1),2),3) = getfield( vertcat(C{:}), {~mod(A(:,1),2)});
%// well no, I won't explain it...
Edit: I assumed your first column just contains integers!
I would suggest you break the problem down into stages, something like so:
Identify blocks you wish to flip
Extract them
Flip them
Replace them
You can identify a set of even numbers using the unique and mod functions, then use a for loop over them and use logical indexing to pull/replace the blocks.
Here, try this
a = magic(5); % Some data in a 5x5 matrix
b = 1:numel(a); % Indices of <a>
Rearrange b however you want, then do a=a(b) to reassign a based on the reassigned indices of b. For example, the following code
disp(a(b));
would just return the elements of a in their original order. For your application this code should work:
a = <your matrix data>
b = 1:numel(a);
b = [b(1:27) fliplr(b(28:31)) b(32:34) fliplr(b(35:36))] % Change this part
a = reshape(a(b),size(a))
You should change b based on whatever you need it to do.