给定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);
除非不起作用。
但有一点需要注意,由于各种原因我无法使用线性索引 - 必须使用原始索引返回结果。而且这些矩阵的大小可能非常大,所以我也不想使用循环。
答案 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
矩阵的顺序访问 - 但是在创建该矩阵期间,您会随机访问内存...
请注意,您遇到的一个问题是“是否有一个班轮” - 答案是“是”。如果您定义了数组x
和y
,那么
z = arrayfun(@(a,b)x(a,b),y(:,1),y(:,2));
确实只是一行,并没有使用线性索引......