基数排序!
听起来您需要一种内存效率高的排序算法。通过首先对行进行排序,然后检查相邻行是否有重复,可以找到唯一行。您可以为此调整基数排序,按顺序对每一列进行排序(而不是按顺序对每个数字进行排序)。这将是排序一列而不是整个矩阵的峰值内存成本。然后逐步遍历排序结果中的行并消除重复项。这是一个O(n) 操作,只需要足够的内存来容纳两行。
它也可以是“稳定的”。如果在排序过程中除了跟踪重新排列的行值之外还跟踪重新排列的行索引,则可以计算输入-输出映射索引。 (这些是 Matlab 自己的 [B,I] = sort(A) 签名中的 I。)这反过来将允许您将删除后的行重新排列回输入中的原始顺序,因此您可以保留它们的顺序。 (如 Matlab 的unique() 的setOrder='stable' 选项。)它们还可以用于计算整体唯一性操作的输入输出映射索引,因此您可以重现unique() 的完整多输出签名,它可以很有用。
示例代码
这是一个基本的示例实现。我还没有彻底测试过,所以不要在没有自己测试的情况下在生产中使用它。
function A = rrunique(A)
%RRUNIQUE "Radix Row Unique" - find unique rows using radix sort
%
% # Returns the distinct rows in A. Uses the memory-efficient radix sort
% # algorithm, so peak memory usage stays low(ish) for large matrices.
% # This uses a modified radix sort where only the row remapping indexes are
% # rearranged at each step, instead of sorting the whole input, to avoid
% # having to rewrite the large input matrix.
ix = 1:size(A,1); % # Final in-out mapping indexes
% # Radix sort the rows
for iCol = size(A,2):-1:1
c = A(ix,iCol);
[~,ixStep] = sort(c);
% # Don't do this! too slow
% # A = A(ixStep,:);
% # Just reorder the mapping indexes
ix = ix(ixStep);
end
% # Now, reorder the big array all at once
A = A(ix,:);
% # Remove duplicates
tfKeep = true(size(A,1),1);
priorRow = A(1,:);
for iRow = 2:size(A,1)
thisRow = A(iRow,:);
if isequal(thisRow, priorRow)
tfKeep(iRow) = false;
else
priorRow = thisRow;
end
end
A = A(tfKeep,:);
end
当我在 OS X 上的 Matlab R2014b 上对您大小的矩阵进行测试时,它使用的内存达到了大约 3 GB 的峰值,而仅保存输入矩阵大约需要 1 GB。还不错。
>> m = rand([13146,13146]);
>> tic; rrunique(m); toc
Elapsed time is 17.435783 seconds.