在矩阵中索引重复:Matlab

时间:2014-09-24 06:45:46

标签: matlab indexing

考虑矩阵

 X = [ 1 2 0 1; 
       1 0 1 2;                                          
       1 2 3 4;                                     
       2 4 6 8;
          .           
          .                          
       1 2 0 1                  
          .                 
          .    ]

我想创建一个新列,以便我可以在每一行中编号ith

答:

   X = [ 1 2 0 1;   y =  [1
         1 0 1 2;         1                                 
         1 2 3 4;         1                            
         2 4 6 8;         1
           .             .
           .             .             
         1 2 0 1          2        
           .             .    
           .    ]        .]

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

这个怎么样?

y = sum(triu(squareform(pdist(X))==0)).';

这可以通过计算前一行等于每行的数量来实现。如果它们的距离(使用squareformpdist计算)为0,则两行相等。triu确保仅考虑先前的行。

为减少计算时间并避免依赖统计工具箱,您可以使用@ user1735003的建议:

y = sum(triu((bsxfun(@plus, sum(X.^2,2), sum(X.^2,2)') - 2*X*X.')==0));

答案 1 :(得分:2)

方法#1

%// unique rows
unqrows = unique(X,'rows'); 

%// matches for each row against the unique rows and their cumsum values
matches_perunqrow = squeeze(all(bsxfun(@eq,X,permute(unqrows,[3 2 1])),2));
cumsum_unqrows = cumsum(matches_perunqrow,1);

%// Go through a row-order and get the cumsum values for the final output
[row,col] = find(matches_perunqrow);
[sorted_row,ind] = sort(row);
y=cumsum_unqrows(sub2ind(size(cumsum_unqrows),[1:size(cumsum_unqrows,1)]',col(ind)));

示例运行 -

X =
     1     2     0     1
     1     0     1     2
     1     2     3     4
     2     4     6     8
     1     2     0     1
     1     2     3     4
     1     2     3     4
     1     2     3     4
     1     2     3     4
     1     2     0     1
out =
     1
     1
     1
     1
     2
     2
     3
     4
     5
     3

方法#2

%// unique rows
unqrows = unique(X,'rows');

%// matches for each row against the unique rows
matches_perunqrow = all(bsxfun(@eq,X,permute(unqrows,[3 2 1])),2)

%// Get the cumsum of matches and select only the matches for each row.
%// Since we need to go through a row-order, transpose the result
cumsum_perrow = squeeze(cumsum(matches_perunqrow,1).*matches_perunqrow)' %//'

%// Select the non zero values for the final output
y = cumsum_perrow(cumsum_perrow~=0)

方法#3

%// label each row based on their uniqueness
[~,~,v3] = unique(X,'rows')
matches_perunqrow = bsxfun(@eq,v3,1:size(X,1))

cumsum_unqrows = cumsum(matches_perunqrow,1);

%// Go through a row-order and get the cumsum values for the final output
[row,col] = find(matches_perunqrow);
[sorted_row,ind] = sort(row);
y=cumsum_unqrows(sub2ind(size(cumsum_unqrows),[1:size(cumsum_unqrows,1)]',col(ind)));

方法#4

%// label each row based on their uniqueness
[~,~,match_row_id] = unique(X,'rows');

%// matches for each row against the unique rows and their cumsum values
matches_perunqrow = bsxfun(@eq,match_row_id',[1:size(X,1)]');
cumsum_unqrows = cumsum(matches_perunqrow,2);

%// Select the cumsum values for the ouput based on the unique matches for each row
y = cumsum_unqrows(matches_perunqrow);

答案 2 :(得分:1)

包含for循环的解决方案可以很容易地完成,也许它已经足够快了。我相信有一个更快的解决方案,可能会使用cumsum,但也许你根本不需要它。基本思路:首先找到唯一行的索引,以便能够处理标量索引而不是完整行(向量)。 然后遍历索引并找到先前出现的次数:

X = [ 1 2 0 1; 
   1 0 1 2;                                          
   1 2 3 4;                                     
   2 4 6 8;                        
   1 2 0 1;                 
   1 3 3 7;                 
   1 2 0 1];

[~,~,idx] = unique(X, 'rows'); %// find unique rows

%// loop over indices and accumulate number of previous occurences
y = zeros(size(idx));
for i = 1:length(idx)
   y(i) = sum(idx(1:i) == idx(i)); %// this line probably scales horrible with length of idx.
end

该示例的结果是:

y =

 1
 1
 1
 1
 2
 1
 3