Matlab:从矩阵中删除行/列是否昂贵?

Vim*_*Vim 5 memory performance matlab matrix

在MATLAB中将行/列附加到矩阵似乎需要考虑.例如,当我尝试将列附加到A具有许多行和多列的矩阵时,例如

A = [A, added_col]
Run Code Online (Sandbox Code Playgroud)

Matlab会警告我,由于这必须在内存中复制A,我最好使用预分配来提高速度.这是可以理解的,因为底层数据A占用了连续的内存块.

我的问题是,删除行/列会导致类似的问题吗?例如,要删除第二行A:

A(2,:) = []
Run Code Online (Sandbox Code Playgroud)

这个操作是否就地?我真的感到不确定,因为有一件事它似乎没有为内存中的数据创造任何新的空间,而另一方面,行将A被非连续地存储(因为第2行被删除).

那么内部会发生什么?这项操作是否足以在实践中使用?谢谢!


刚刚测试它的复杂性100000:

clc; clear;
N = 100000;
A = zeros(N, 3);

t1 = tic;
for ii = 1:N
    A(ii, :) = [1 2 3];
end
t2 = toc;
Run Code Online (Sandbox Code Playgroud)

clc; clear;
N = 100000;
A = zeros(N, 3);

t1 = tic;
for ii = (N-1):-1:2
    A(ii, :) = [];
end
t2 = toc;
Run Code Online (Sandbox Code Playgroud)

结果:第一个(修改预分配的矩阵)为0.009s,第二个为53.429(从矩阵中删除行).我认为这基本上解决了这个问题:不,从矩阵中删除行/列是无效的,因为它肯定涉及深度复制数据和重新分配内存.

此外,删除而不是行也不是一个好主意.正如我测试的那样,在上述复杂程度上,它仍然需要大约两分钟的时间:

N = 100000;
test_m = zeros(3, N);
tic
for ii = (N - 1):-1:2
    test_m(:, ii) = [];
end
toc
% result: 105.436595 seconds. 
% This was run on a different machine than the previous examples.
% But is still enough evidence that dynamically resizing a big matrix is a BAD idea.
Run Code Online (Sandbox Code Playgroud)

所以,故事的结尾:不要试图以这种方式删除列或行,除非你有一个非常小的矩阵.对于庞大的矩阵,请始终使用预分配.

Jim*_*mbo 2

这里有几个问题:

  1. 是否为删除分配内存
  2. 行主内存访问与列主内存访问
  3. 代码示例
  4. 预分配修改与删除?

1)不使用mex,您无法控制矩阵移除是否使用相同的内存。但是,您可以判断它是否发生。一种方法是用 mex 写一些东西。或者您可以激活format debug

N = 100000;
test_m = zeros(3, N);
t = evalc('disp(test_m)');
disp(t(1:100))
test_m(:,2:N-1) = [];
disp(t(1:100))
Run Code Online (Sandbox Code Playgroud)

这会产生输出

Structure address = 1259f6da0
m = 3
n = 100000
pr = 15d6d2020
pi = 0
  Columns 1 through 9

     0 

Structure address = 1259f6b70
m = 3
n = 2
pr = 608001c95320
pi = 0
     0     0
     0     0
     0

     0 
Run Code Online (Sandbox Code Playgroud)

请注意,为了保持显示合理,我捕获显示变量的输出,然后仅显示其中的一部分。该输出pr(指向实际数据的指针)尤其表明发生了重新分配。我找不到任何没有发生重新分配的情况。

2)正如一些评论中提到的和问题中提到的,内存以列优先存储。因此,当您删除列时,它可能比删除行更有效......

3)我不完全确定代码示例是否真实,但一次性删除所有列或行更有意义。这种情况发生得非常快。

N = 100000;
test_m = zeros(3, N);
test_m(:,2:N-1) = [];
Run Code Online (Sandbox Code Playgroud)

4)最后,我不确定你的措辞是指预分配修改还是删除。从大局来看,最好避免在循环中删除行或列。相反,保留一个数组来指示应删除哪些列或行,然后一次性执行此操作。