技术文章

MathWorks 见解

MATLAB 中的矩阵索引


作者:

  • Steve Eddins, MathWorks
  • Loren Shure, MathWorks

阅读时间:8 分钟

标签:

小结

  • 矩阵索引支持高效选择和修改数据,构成数组操作和基于矩阵的算法的基础。
  • MATLAB 支持多种索引方式,包括下标索引和向量索引,以及冒号运算符和 end 关键字,用于访问元素范围和边界元素。
  • 索引既支持提取也支持赋值,能够实现简洁的变换,例如重排元素、替换值以及对子数组执行运算。
  • 有效的索引支持向量化,减少对循环的依赖,生成的代码通常更短、更清晰且执行速度更快。

对矩阵进行索引是从矩阵中选择或修改部分元素的一种方式。MATLAB® 提供多种索引方式,不仅功能强大、灵活,而且兼具可读性和表现力。。矩阵是 MATLAB 用来组织和分析数据的一个核心组件,索引是以可理解的方式有效操作矩阵的关键。

对于 MATLAB 用户来说,索引往往与另一个术语密切相关:向量化。向量化意味着使用 MATLAB 矩阵和向量运算而不是标量运算,这通常会生成更短的代码,更具数学表现力和可读性,有时执行速度还会更快。

对向量进行索引

我们从向量和下标的简单情况开始。

 v = [16 5 9 4 2 11 7 14];

下标可以是单个值:

 v(3) % 提取第三个元素
 ans =
 9

下标本身也可以是另一个向量。

 v([1 5 6]) % 提取第一个、第五个和第六个元素
 ans =
 16 2 11

MATLAB 中的冒号表示法提供一种从 v 中提取一系列元素的简单方法。

 v(3:7) % 提取第三个到第七个元素
 ans =
 9 4 2 11 7

交换 v 的前后两半,创建一个新向量。

 v2 = v([5:8 1:4]) % 提取并交换 v 的前后两半
 v2 =
 2 11 7 14 16 5 9 4

特殊的 end 运算符是引用 v 的最后一个元素的简便快捷方法。

 v(end) % 提取最后一个元素
 ans =
 14

end 运算符可以用在范围表达式中。

 v(5:end) % 提取第五个到最后一个元素
 ans =
 2 11 7 14

您甚至可以使用 end 进行算术运算。

 v(2:end-1) % 提取第二个到倒数第二个元素
 ans =
 5 9 4 2 11 7

将冒号运算符和 end 结合使用可以实现多种效果,例如提取每第 k 个元素或翻转整个向量。

 v(1:2:end) % 提取所有奇数位置的元素
 ans =
 16 9 2 7
 v(end:-1:1) % 反转元素的顺序
 ans =
 14 7 11 2 4 9 5 16

通过使用等号左侧的索引表达式,您可以替换向量的某些元素。

 v([2 3 4]) = [10 15 20] % 替换 v 的某些元素
 v =
 16 10 15 20 2 11 7 14

通常,右侧的元素数必须与左侧的索引表达式所引用的元素数相同。然而,您始终可以在右侧使用标量。这称为标量扩展。

 v([2 3]) = 30 % 用 30 替换第二个和第三个元素
 v =
 16 30 30 20 2 11 7 14

请牢记:MATLAB 使用从 1 开始的索引。在对矩阵进行索引时,有些语言使用从 0 开始的索引。其他语言,如 MATLAB,使用从 1 开始的索引。MATLAB 采用的表示法与您在数学教科书中常见的表示法一致。MATLAB 为什么使用从 1 开始的索引?MATLAB 创始人 Cleve Moler 对此解释道,“这就是数学的表示方式。”

使用两个下标对矩阵进行索引

现在考虑对矩阵进行索引。我们将在示例中使用幻方。

 A = magic(4)
 A =
 16 2 3 13
 5 11 10 8
 9 7 6 12
 4 14 15 1

通常,对矩阵进行索引使用两个下标:第一个表示行,第二个表示列。

最简单的形式是选择一个元素。

 A(2,4) % 提取第 2 行第 4 列中的元素
 ans =
 8

更广泛地说,其中的一个或两个下标可以是向量。

 A(2:4,1:2)
 ans =
 5 11
 9 7
 4 14

下标位置中的单个“:”是 1:end 的简写表示法,通常用于选择整行或整列。

 A(3,:) % 提取第 3 行
 ans =
 9 7 6 12
 A(:,end) % 提取最后一列
 ans =
 13
 8
 12
 1

有时人们对如何从矩阵中选择分散的元素感到困惑。例如,假设您要从 A 中提取元素 (2,1)、(3,2) 和 (4,4)。

4×4 矩阵,其中三个突出显示的值分散在矩阵中的不同位置。它们分别位于第 2 行第 1 列;第 3 行第 2 列;以及第 4 行第 4 列。

矩阵中的分散元素。
我们如何表示这种期望的输出?

表达式 A([2 3 4], [1 2 4]) 不会实现想要的效果。下图说明双下标索引的工作原理。

从矩阵中提取分散的元素需要另一种索引方式,这就引出了下一个主题。

线性索引

表达式 A(14) 的作用是什么?

MATLAB 会将 A 视为其元素按列依次向下串成的一个长列向量,如下所示:

16
5
9
...
8
12
1

提示:MATLAB 采用列优先存储:线性索引按列依次向下进行。

表达式 A(14) 只提取隐式列向量的第 14 个元素。以这种方式使用单个下标对矩阵进行索引,通常称为线性索引。

下图在每个矩阵元素的左上角显示了线性索引,从中可以看出 A(14) 等同于 A(2,4)。

单下标也可以是包含多个线性索引的向量,例如:

 A([6 12 15])
 ans =
 11 15 12

再次考虑只提取 A 的元素 (2,1)、(3,2) 和 (4,4)。您可以使用线性索引来提取这些元素。

 A([2 7 16])
 ans =
 5 7 1

此示例很容易理解,但一般情况下如何计算线性索引?MATLAB 提供了名为 sub2ind 的函数,用于将行下标和列下标转换为线性索引。您可以通过以下方式使用它来提取所需的元素:

 idx = sub2ind(size(A), [2 3 4], [1 2 4])
 ans =
 2 7 16
 A(idx)
 ans =
 5 7 1

逻辑索引

另一种索引变体是逻辑索引,它是一种紧凑而富有表现力的表示法,适用于包括图像处理在内的许多应用。在逻辑索引中,使用单个逻辑数组来表示矩阵下标。

您可以使用以下逻辑数组示例:

A > 12 

ans =
4×4 logical array

1  0  0  1
0  0  0  0
0  0  0  0
0  1  1  0

这些是矩阵中逻辑表达式为真的位置,在本例中是任何大于 12 的位置。

现在表达式 A(A > 12) 提取对应于逻辑数组的非零值的矩阵元素。输出始终以列向量形式出现。

A(A > 12) 

ans =

 16
 14
 15
 13

许多以 is 开头的 MATLAB 函数返回逻辑数组,对于逻辑索引非常有用。例如,通过在一行代码中结合使用 isnan、逻辑索引和标量扩展,可以将数组中的所有 NaN 元素替换为另一个值。

 B(isnan(B)) = 0

MATLAB 有许多返回逻辑数组的字符串数组函数,例如 contains、startsWith 和 matches。您可以使用这些函数,通过逻辑索引对文本进行操作。例如,您可以提取所有包含“Skylab”的航天计划名称。

>> names

names =

  6×1 string array

    "Mercury"
    "Gemini"
    "Apollo"
    "Skylab"
    "Skylab B"
    "ISS"

>> names(contains(names,"Skylab"))

ans =

  2×1 string array

    "Skylab"
    "Skylab B"

逻辑索引与 find 函数密切相关。表达式 A(A > 5) 等效于 A(find(A > 5))。逻辑索引表达式在简单情况下执行速度更快,但如果您在计算中还需要用到这些索引值本身,则可以使用 find 函数。例如,假设您要用零临时替换 NaN 值,执行一些计算,然后将 NaN 值放回其原始位置。在此示例中,计算过程是使用 filter2 进行二维滤波。您可以这样做:

 nan_locations = find(isnan(A)); 

 A(nan_locations) = 0; 

 A = filter2(ones(3,3), A); 

 A(nan_locations) = NaN; 

我们希望本文中的这些示例能帮助您了解如何简洁高效地表达算法。将这些方法和相关函数纳入您的 MATLAB 编程工具箱,能够增强您编写简洁、易读且向量化代码的能力。

2024 年发布


使用的产品: MATLAB

继续探索