Octave和Matlab中的"wat"矩阵/向量不一致性

6
我注意到在Matlab和Octave中,有些函数可以接受矩阵和向量作为参数,但是对于向量和矩阵的处理方式不同。这可能会让人感到沮丧,因为当你输入一个具有可变行/列数的矩阵时,它可能被解释为一个向量,并在高度/宽度为1时执行您不希望的操作,导致调试困难和奇怪的条件边缘情况。
我列出了一些我发现的情况,但我很好奇其他人遇到了什么问题。
(注意:我只寻找代码接受矩阵作为有效输入的情况。任何在给定非向量矩阵作为参数时引发异常的代码都不算。)
1)“diag”可以用来表示矩阵的对角线或将向量转换为对角矩阵。
由于前者通常只用于方阵,在Matlab中并不太严重,但在Octave中,当Octave将以非零元素开头且其他所有元素为零的向量解释为“对角矩阵”时,这可能特别痛苦。
t=eye(3);
size(diag(t(:,3))) == [3,3]
size(diag(t(:,2))) == [3,3]
size(diag(t(:,1))) == [1,1]

2) 使用逻辑值对行向量进行索引将返回一个行向量

使用逻辑值对其他任何内容进行索引将返回一个列向量

a = 1:3;
b = true(1,3);
size(a(b)) == [1, 3]
a = [a; a];
b = [b; b];
size(a(b)) == [6, 1]

3) 使用索引向量i对向量v进行索引会返回与v相同(行/列)类型的向量。但是,如果v或i是矩阵,则返回值的大小与i相同。

a = 1:3;
b = a';
size(a(b)) == [1, 3]
b = [b,b];
size(a(b)) == [3, 2]

4) max, min, sum等函数会对矩阵M的每一列进行操作,除非M是一个1xn的矩阵,在这种情况下它们将作为一个单独的行向量来对M进行操作。

a = 1:3
size(max(a)) == [1, 1]
a = [a;a]
size(max(a)) == [1, 3]

Max很糟糕,因为它甚至不能将维度作为参数(与sum不同)。

写Octave/Matlab代码时,还应该注意哪些类似的情况?


只是为了澄清:您可以指定最大/最小的维度:min(rand(3),[],1)max(rand(3),[],2) - Amro
2个回答

2
每种语言都有自己的概念。这种语言的一个重要点是经常将矩阵视为向量数组,每列一个条目。然后事情就会开始变得有意义。如果您不想使用这种行为,请在那些函数中使用matrix(:)作为参数,这将传递单个向量,而不是矩阵。例如:
octave> a = magic (5);
octave> max (a)
ans =

   23   24   25   21   22

octave> max (a(:))
ans =  25

1) 至少在Octave 3.6.4中,这是不正确的。我不能100%确定,但可能与this bug有关,该问题已经被修复。

2) 如果您使用布尔值进行索引,它将被视为掩码并相应处理。如果您使用非布尔值进行索引,则将其视为值的索引。这对我来说非常合理。

3) 这是不正确的。返回的大小始终与索引的大小相同,无论它是矩阵还是向量。唯一的例外是,如果索引是向量,则输出将是单行的。这个想法是使用单个向量/矩阵进行索引会返回与其大小相同的东西:

octave> a = 4:7
a =

   4   5   6   7

octave> a([1 1])
ans =

   4   4

octave> a([1 3])
ans =

   4   6

octave> a([1 3; 3 1])
ans =

   4   6
   6   4

4) 在Octave中,max确实接受维度参数。来自max的3.6.4帮助文本:

对于向量参数,返回最大值。对于矩阵参数,返回每列的最大值作为行向量,或者在定义了维度DIM的情况下沿该维度返回最大值,在这种情况下,Y应设置为空矩阵(否则将被忽略)。

其余部分如介绍所述。如果您提供一个矩阵,它会将每列视为一个数据集。


2
我认为你没有理解我的问题。我一般性地抱怨向量没有被视为矩阵(而你似乎认为我的问题是矩阵没有被视为向量)。在情况2中,我只使用布尔索引,从未用数值索引(两种情况都没有),然而其中一种返回行向量,另一种返回列向量。在情况3中,你提到的异常正是我抱怨的问题。如果我有一个需要进行索引的矩阵,但这个矩阵具有可变数量的列,那么我必须针对这个唯一的异常写一个if语句,只有1 - dspyz

1

1) 正如其他用户所指出的那样,在Octave >= 3.6.4中,这是不正确的。

在情况2)中,规则适用于向量,始终返回相同形状的向量,对于其他任何内容,返回列向量,请考虑:

>> a = reshape (1:3, 1,1,3)

a(:,:,1) =

     1.0000e+000


a(:,:,2) =

     2.0000e+000


a(:,:,3) =

     3.0000e+000

>> b = true(1,3)

b =

  1×3 logical array

   1   1   1

>> a(b)

ans(:,:,1) =

     1.0000e+000


ans(:,:,2) =

     2.0000e+000


ans(:,:,3) =

     3.0000e+000

>> a = [a;a]

a(:,:,1) =

     1.0000e+000
     1.0000e+000


a(:,:,2) =

     2.0000e+000
     2.0000e+000


a(:,:,3) =

     3.0000e+000
     3.0000e+000

>> b = [b;b]

b =

  2×3 logical array

   1   1   1
   1   1   1

>> a(b)

ans =

     1.0000e+000
     1.0000e+000
     2.0000e+000
     2.0000e+000
     3.0000e+000
     3.0000e+000

你可以看到这是有道理的,因为向量有明确的“方向”,但其他形状的矩阵在删除元素时没有。编辑:实际上我刚刚检查了一下,Octave似乎并不完全按照这种方式工作,但可能应该这样。

3)这与2)一致。如果您提供索引列表,则保留索引向量的方向。如果您提供类似矩阵的形状的索引,则使用索引矩阵形状的新信息。这更加灵活,因为您始终可以执行a(b(:))以保留a的形状,如果您愿意的话。您可能会说它不一致,但请记住,使用逻辑进行索引可能会减少要返回的元素数量,因此无法以这种方式重新整形。

4)正如评论中指出的那样,您可以指定max/min操作的维度:min(rand(3),[],1)max(rand(3),[],2),但在这种情况下,这些函数存在“遗留”问题,这些问题可以追溯到它们最初创建的时候,现在很难改变而不会让人们感到不满。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接