优化从MATLAB矩阵中提取数据?

时间:2009-11-05 13:23:15

标签: matlab matrix

给定n维值矩阵:通过任意索引(即坐标)检索值的最有效方法是什么?

E.g。在一个随机的5x5矩阵中,如果我想要(1,1)(2,3)和(4,5)的值,那么只返回这些坐标值的最有效方法是什么?

如果我在一个单独的矩阵中提供这些坐标,例如是否有一行MATLAB可以完成这项工作?类似的东西:

    x=rand(5,5);

    y=[[1,1];[2,3];[4,5]];

    z=x(y);

除非不起作用。

但有一点需要注意,由于各种原因我无法使用线性索引 - 必须使用原始索引返回结果。而且这些矩阵的大小可能非常大,所以我也不想使用循环。

3 个答案:

答案 0 :(得分:4)

如果你反对使用线性索引和循环,唯一的另一种选择,AFAIK,是逻辑索引。但如果y始终以您建议的形式出现,则需要根据y中指定的索引创建逻辑矩阵。

你能解释为什么不允许线性索引吗?

无论如何,如果你想要一个非常愚蠢的答案(我可以提供这么多信息):

z = diag(x(y(:,1),y(:,2)))

当然,这将不必要地创建一个巨大的矩阵并从中提取对角元素(你需要的元素) - 但它可以在一行中完成它等等。

编辑:如果限制是对原始数据使用线性索引,则可以使用线性索引创建逻辑矩阵并使用该索引编制x。 E.g。

% Each element of L is only one byte
L = false(size(x)); 
% Create the logical mask
L(sub2ind(size(x),y(:,1),y(:,2))) = true;
% Extract the required elements
z = x(L);

同样,对于三维矩阵:

x = rand(3,3,3);
y = [1 1 1;2 2 2;3 3 3];
L = false(size(x));
L(sub2ind(size(x),y(:,1),y(:,2),y(:,3))) = true;
z = x(L);

此外,逻辑索引应该比线性索引更快,所以除了构建掩码之外,你的状态还不错。

答案 1 :(得分:0)

为什么不单独sub2ind适合这个问题?我不认为需要逻辑掩码; e.g。

z = x(sub2ind(size(x),y(:,1),y(:,2)))

应该也可以。

答案 2 :(得分:0)

音乐停止后很久就参加了聚会,但我忍不住了......

如果由于工具箱中的错误而需要“完整”索引,并且工具箱一次只加载矩阵的一部分,您可能会考虑跟随工具箱的行为。通过两件事可以获得大矩阵的大效率增益

1)不要复制不需要复制的东西;例如,这包括创建一个原始矩阵大小的逻辑数组(虽然它名义上是“有效的”,每个元素需要一个字节。如果你的矩阵太大而不能同时存储在内存中,甚至是一个矩阵,是1/8大小可能是重要的)

2)保持内存一致性:“在同一区域内”访问内存,或者发现自己因大量磁盘交换而放慢速度;即使所有内容都适合内存,保留“缓存一致性”也可以显着提高性能。如果您可以按照存储顺序访问矩阵元素,那么事情就会大大加快。

要解决第一点,您需要寻找一种不需要创建完整副本的方法(因此雅各布的答案将会出来)。要解决第二个问题,您需要在访问矩阵之前对索引进行排序 - 这样,任何可以“从同一内存块”访问的元素都将是。

以下结合使用这两种技术。我假设numel(y) << numel(x) - 换句话说,你只想看x的相对少量的元素。如果情况并非如此,那么对y向量进行排序实际上会让你失望很多:

x = rand(5,5);
y = [1 1; 2 3; 4 5];
s = sub2ind(size(x), y(:,1), y(:,2)); % from the linear index we get access order
[ySorted yOrder] = sort(s);

% find the first, second index in the right access order:
y1 = y(yOrder, 1);
y2 = y(yOrder, 2);

% access the array using conventional indexing:
z = arrayfun(@(a,b)x(a,b), y1, y2);

% now put things back in the right order:
[rev revOrder] = sort(yOrder);
z = z(revOrder);

我使用10000x10000矩阵x和5000x2随机元素查找向量y对此进行了基准测试。与雅各布的代码相比,我获得了

my method:   51 ms
his method: 225 ms

将查找向量的大小增加到50000x2,值为

my method:  523 ms
his method: 305 ms

换句话说 - 哪种方法更好地工作取决于您要访问的元素数量。另请注意,使用逻辑L矩阵会隐式地导致对大x矩阵的顺序访问 - 但是在创建该矩阵期间,您会随机访问内存...

请注意,您遇到的一个问题是“是否有一个班轮” - 答案是“是”。如果您定义了数组xy,那么

z = arrayfun(@(a,b)x(a,b),y(:,1),y(:,2));

确实只是一行,并没有使用线性索引......