处理 NumPy 数组:基础知识
现在你已了解如何在 NumPy 中创建数组,你需要熟悉如何操作它们,原因有两个。 首先,你将处理 NumPy 数组,这是数据科学的探索过程的一部分。 其次,我们另一个重要的 Python 数据科学工具 pandas 是围绕 NumPy 构建的。 我们将在下一节(第 4 节)及后续部分介绍擅长处理 NumPy 数组带来的好处。 NumPy 数组是 Python pandas 库中 Series 和 DataFrame 数据结构的构建基块。 它们将大量用于数据科学中。 为了帮助你熟悉数组操作,我们将介绍五个特定主题:
- 数组特性:评估数组的大小、形状和数据类型
- 对数组编制索引:获取和设置各个数组元素的值
- 对数组进行切片:在较大的数组中获取和设置较小的子数组
- 改变数组的形状:更改给定数组的形状
- 联接和拆分数组:将多个数组组合并到一个数组中,以及将一个数组拆分成多个数组
数组特性
首先来看一些数组特性。 我们首先定义三个用随机数填充的数组:一个是一维数组,另一个是二维数组,最后一个是三维数组。 由于我们将使用 NumPy 的随机数生成器,因此我们将设置种子值,以确保每次运行此代码时获得相同的随机数组:
import numpy as np
np.random.seed(0) # Seed for reproducibility
a1 = np.random.randint(10, size=6) # One-dimensional array
a2 = np.random.randint(10, size=(3, 4)) # Two-dimensional array
a3 = np.random.randint(10, size=(3, 4, 5)) # Three-dimensional array
每个数组都具有属性 ndim(数组的维度数)、shape(数组每个维度的大小)以及 size(数组中元素的总数):
print("a1 ndim: ", a1.ndim)
print("a1 shape:", a1.shape)
print("a1 size: ", a1.size)
输出为:
a1 ndim: 1
a1 shape: (6,)
a1 size: 6
亲自试一试
更改此代码片段中的值,以查看 a2 和 a3 的特性:
提示(展开以显示)
对于 a2:
print("a2 ndim: ", a2.ndim)
print("a2 shape:", a2.shape)
print("a2 size: ", a2.size)
输出为:
a2 ndim: 2
a2 shape: (3, 4)
a2 size: 12
对于 a3:
print("a3 ndim: ", a3.ndim)
print("a3 shape:", a3.shape)
print("a3 size: ", a3.size)
输出为:
a3 ndim: 3
a3 shape: (3, 4, 5)
a3 size: 60
另一个有用的数组特性是 dtype,我们已在本节前面部分讨论过该特性,它是确定数组中数据类型的一种方法:
print("dtype:", a3.dtype)
输出为:
dtype: int64
亲自试一试
浏览其他数组的 dtype 值。
预测它们有哪些 dtype 值?
提示(展开以显示)
print("dtype:", a3.dtype)
输出为:
dtype: int64
对数组编制索引
NumPy 中的索引类似于标准 Python 中的索引列表。 事实上,一维数组中的索引与在 Python 列表中的效果完全相同。
请尝试:
a1
输出为:
array([5, 0, 3, 3, 7, 9])
然后尝试:
a1[0]
输出为:
5
下一步:
a1[4]
输出为:
7
与常规 Python 列表一样,若要从数组末尾开始编制索引,可以使用负索引。
例如:
a1[-1]
输出为:
9
以及:
a1[-2]
输出为:
7
亲自试一试
多维 NumPy 数组的工作方式类似于 Python 列表的列表吗?
尝试一些组合(如 a2[1][1] 或 a3[0][2][1]),并查看返回的内容。
提示(展开以显示)
a2[1][1]
输出为:
6
当你使用:
a3[0][2][1]
输出为:
0
你可能已注意到,我们可以将多维数组视为列表的列表。 但要访问多维数组中的项,更常见的方法是使用以逗号分隔的索引元组。
(是的,我们意识到这些逗号分隔的元组使用方括号,而不是名称可能暗示的括号。它们仍称为元组。)
请尝试:
a2
输出为:
array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
并使用:
a2[0, 0]
输出为:
3
接下来查看:
a2[2, 0]
输出为:
1
请尝试:
a2[2, -1]
输出为:
7
还可使用相同的以逗号分隔的索引表示法来修改值:
a2[0, 0] = 12
a2
输出为:
array([[12, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
请记住,在定义NumPy 数组后,它们就具有固定的数据类型。 因此,如果尝试在整数数组中插入浮点数,将无提示地截断值。
a1[0] = 3.14159
a1
输出为:
array([3, 0, 3, 3, 7, 9])
亲自试一试
如果尝试将字符串插入 a1 中,会发生什么情况? 请尝试插入 '3' 和 'three' 这样的字符串。
提示(展开以显示)
a1[1] = '3'
a1
输出为:
array([3, 3, 3, 3, 7, 9])
但当你尝试:
a1[1] = 'three'
a1
输出为:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
----> 1 a1[1] = 'three'
2 a1
ValueError: invalid literal for int() with base 10: 'three'
对数组进行切片
与使用方括号访问各个数组元素的方式类似,你还可以使用方括号来访问子数组。 为此,可使用切片表示法(用冒号 字符标记):。 NumPy 切片语法遵循标准 Python 列表的语法。 因此,若要访问数组 a 的切片,请使用此表示法:
a[start:stop:step]
如未指定这些元素中的任何一个,则它们的默认值为 start=0、stop=size of dimension、step=1。 接下来了解如何访问一个维度和多个维度中的子数组。
一维切片
如果使用此代码:
a = np.arange(10)
a
输出为:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
可以获取前五个元素:
a[:5]
输出为:
array([0, 1, 2, 3, 4])
可以返回索引 5 之后的元素:
a[5:]
输出为:
array([5, 6, 7, 8, 9])
或中间子数组:
a[4:7]
输出为:
array([4, 5, 6])
下面介绍如何获取其他所有元素:
a[::2]
输出为:
array([0, 2, 4, 6, 8])
若要获取从索引 1 开始的其他所有元素:
a[1::2]
输出为:
array([1, 3, 5, 7, 9])
亲自试一试
如何访问数组 的最后五个元素?a 如何访问 a 的最后五个元素之外的其他所有元素? 请回顾 Python 中的列表索引。
提示(展开以显示)
请尝试:
a[-5:]
输出为:
array([5, 6, 7, 8, 9])
以及:
a[-5::2]
输出为:
array([5, 7, 9])
对step 使用负值时,请谨慎操作。 如果 step 具有负值,则 start 和 stop 的默认值会互换。 你可使用此功能来反转数组。
此代码提供已反转的所有元素:
a[::-1]
输出为:
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
此代码将为你提供索引 5 中已反转的其他所有元素:
a[5::-2]
输出为:
array([5, 3, 1])
亲自试一试
如何创建一个切片,使其包含 a 中每三个元素的最后一个,从倒数第二个元素起降序排列?
提示(展开以显示)
请尝试:
a[-2::-3]
输出为:
array([8, 5, 2])
多维切片
多维切片使用与一维子数组相同的切片表示法,混合使用多维数组的以逗号分隔的表示法。 一些示例有助于说明这一概念:
a2
输出为:
array([[12, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
两行,三列:
a2[:2, :3]
输出为:
array([[12, 5, 2],
[ 7, 6, 8]])
所有行,每隔一列:
a2[:3, ::2]
输出为:
array([[12, 2],
[ 7, 8],
[ 1, 7]])
最后,子数组维度甚至可以一起反转:
a2[::-1, ::-1]
输出为:
array([[ 7, 7, 6, 1],
[ 8, 8, 6, 7],
[ 4, 2, 5, 12]])
访问数组行和列
操作数据时,通常需要访问数组中的单个行或单个列。 可以通过结合使用索引和切片来实现此目的。 具体而言,你将使用由单个冒号 (:) 标记的空切片。 同样,一些示例将有助于说明这一概念。
若要获取 x2 的第一列:
print(a2[:, 0])
输出为:
[12 7 1]
若要获取 x2 的第一行:
print(a2[0, :])
输出为:
[12 5 2 4]
若要访问行,可省略空切片以获取更简洁的语法:
print(a2[0]) # Equivalent to a2[0, :]
输出为:
[12 5 2 4]
亲自试一试
如何访问 a3 的第三列?
如何访问 a3 的第三行?
提示(展开以显示)
a3[:,:,2]
输出为:
array([[5, 3, 2, 3],
[9, 3, 0, 8],
[8, 9, 0, 4]])
而对于:
a3[2,:,:]
输出为:
array([[4, 9, 8, 1, 1],
[7, 9, 9, 3, 6],
[7, 2, 0, 3, 5],
[9, 4, 4, 6, 4]])