我在Matlab中有一个数组。我用自然数编号数组中的每个条目。所以我在数组中形成了等价关系。
例如,
array = [1 2 3 5 6 7]
classes = [1 2 1 1 3 3].
我想得到单元格数组:i
- 单元格数组的位置与i
- 初始数组的条目相关联并显示,哪个元素在这个条目的一个类中。对于上面的例子,我会得到:
{[1 3 5], [2], [1 3 5], [1 3 5], [6 7], [6 7]}
可以使用for循环轻松完成,但还有其他解决方案吗?如果它的工作速度比O(n^2)
快,那么n
就是初始数组的大小。
Edit.
如果我知道将排序数组拆分为O(n)
的具有相等元素的单元格的方法,问题就会得到解决。
array = [1 1 1 2 3 3]
groups = {[1 2 3], [4], [5 6]}
答案 0 :(得分:3)
不确定复杂性,但带有单元格输出的accumarray
对于根据类的唯一值拆分数组非常有用:
data = sortrows([classes; array].',1) %' stable w.r.t. array
arrayPieces = accumarray(data(:,1),data(:,2)',[],@(x){x.'})
classElements = arrayPieces(classes).'
关于将分组数组拆分为indeces的单元格:
>> array = [1 1 1 2 3 3]
>> arrayinds = accumarray(array',1:numel(array),[],@(x){x'})' %' transpose for rows
arrayinds =
[1x3 double] [4] [1x2 double]
>> arrayinds{:}
ans =
1 2 3
ans =
4
ans =
5 6
答案 1 :(得分:1)
我不知道如何在没有for循环的情况下完成此操作,但您可以使用sort
,diff
和find
的组合来组织和分区等价类标识符。这将为您提供一个主要为矢量化的解决方案,其中M代码级for循环为O(n)
,其中n
是类的数量,而不是整个输入数组的长度。这在实践中应该非常快。
这是一个使用索引修改的粗略示例。小心;因为我刚刚把它搞砸了,所以可能是某个地方出现的一个边缘案例错误。
function [eqVals,eqIx] = equivsets(a,x)
%EQUIVSETS Find indexes of equivalent values
[b,ix] = sort(x);
ixEdges = find(diff(b)); % identifies partitions between equiv classes
ix2 = [0 ixEdges numel(ix)];
eqVals = cell([1 numel(ix2)-1]);
eqIx = cell([1 numel(ix2)-1]);
% Map back to original input indexes and values
for i = 1:numel(ix2)-1
eqIx{i} = ix((ix2(i)+1):ix2(i+1));
eqVals{i} = a(eqIx{i});
end
我在输出中包含了索引,因为它们通常比值本身更有用。你这样称呼它。
% Get indexes of occurrences of each class
equivs = equivsets(array, classes)
% You can expand that to get equivalences for each input element
equivsByValue = equivs(classes)
首先为每个类构建列表然后将它们展开以匹配输入索引会更有效。您不仅需要完成一次工作,而且当您使用b = a(ix)
将小型单元阵列扩展为更大的单元时,Matlab的写时复制优化将最终重用内存对于基础数字mxArrays,您可以在内存中获得更紧凑的表示。
使用unique()
或数据库时,此转换会弹出很多。对于我曾经使用的决策支持系统和数据仓库风格的东西,它发生在各地。我希望它是内置于Matlab。 (也许它近年来被添加到数据库或时间序列工具箱中的一个;我的后面几个版本。)
实际上,如果这对您的代码的性能至关重要,您可能还会考虑下载到Java或C MEX函数并在那里实现它。但是如果你的数据集的基数很低 - 也就是说,有少量的类/不同的值,比如numel(unique(classes)) / numel(array)
往往小于0.1左右 - 那么M代码的实现可能会很好。
答案 2 :(得分:1)
关于第二个问题:
array = [1 1 1 2 3 3]; %// example data
使用diff
查找每次运行相等值的结束,并从中构建组:
ind = [0 find(diff([array NaN])~=0)];
groups = arrayfun(@(n) ind(n)+1:ind(n+1), 1:numel(ind)-1, 'uni', 0);
使用unique
的相同方法:
[~, ind] = unique(array);
ind = [0 ind];
groups = arrayfun(@(n) ind(n)+1:ind(n+1), 1:numel(ind)-1, 'uni', 0);