NumPy 数组:分析专用的数据结构

已完成

在本节的讨论开始时,我们提到,数据科学始于将数据表示为数字数组。

你可能在想“稍等!” “不能就使用 Python 列表来实现这个目的吗?”

取决于数据,是的,可以(并且以 Python 处理数据就包括使用列表)。 但为了了解我们需要专用数据结构的原因,让我们来详细了解一下列表。

Python 中的列表

Python 列表只能保存一种对象。 让我们使用一种对象,创建一个全为整数的列表:

myList = list(range(10))
myList

输出为:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

还记得列表理解吗? 可以使用它来探测列表中项的数据类型:

[type(item) for item in myList]

输出为:

[int, int, int, int, int, int, int, int, int, int]

当然,Python 列表的一个便利功能是,它们可以在单个列表对象中保存异类数据:

myList2 = [True, "2", 3.0, 4]
[type(item) for item in myList2]

输出为:

[bool, str, float, int]

但这种灵活性有一定的代价。 列表中的每一项实际上都是一个单独的 Python 对象。 (列表本身就是一个对象,但大体上,这是一个作为容器的对象,用于存储指向构成对象的内存指针。)这意味着列表中的每一项都必须包含其自身的类型信息、引用计数和其他信息。

如果我们在列表中处理成千上万或数百万项,则所有这些信息都可能会消耗大量的内存和性能。 而且,对于数据科学中的许多用途,我们的数组只能存储单一类型的数据(如整数或浮点数)。 因此,此类数组中项的所有对象相关信息都是冗余的。 将数据存储在固定类型的数组中会更有效。

输入固定类型 NumPy 样式数组。

Python 中的固定类型数组

在计算机的实现层面上,ndarray 是 NumPy 包的一部分,其中包含一个指向一个连续数据块的指针。 这在内存和计算方面效率很高。 更好的是,NumPy 对 对象中存储的数据提供高效运算。

备注

在此部分中,我们将频繁地交替使用“数组”、“NumPy 数组”和“ndarray”来表示 ndarray 对象。

创建 NumPy 数组,方法 1:使用 Python 列表

可通过多种方法在 NumPy 中创建数组。 首先使用我们熟悉的传统 Python 列表。 我们将使用 np.array() 函数来执行此操作。 (请记住,我们已将 NumPy 导入为“np”。)

创建整数数组:

np.array([1, 4, 2, 5, 3])

输出为:

array([1, 4, 2, 5, 3])

请记住,与 Python 列表不同,NumPy 将数组约束为包含单一类型。 因此,如果送到 NumPy 数组中的数据类型不匹配,则 NumPy 将尝试向上转换它们(如果可能)。 例如,以下 NumPy 将整数向上转换为浮点数:

np.array([3.14, 4, 2, 3])

输出为:

array([3.14, 4.  , 2.  , 3.  ])

亲自试一试

如果使用包含整数、浮点数和字符串组合的列表构建数组,会发生什么情况?


提示 (展开以显示)
np.array([3.14, 'pi', 3])

输出为:

array(['3.14', 'pi', '3'], dtype='<U32')




如果要在创建数组时显式设置数组的数据类型,可以使用 dtype 关键字:

np.array([1, 2, 3, 4], dtype='float32')

输出为:

array([1., 2., 3., 4.], dtype=float32)

亲自试一试

用不同的 dtype 试试。


提示 (展开以显示)
np.array([1.0, 2.5, 3, 4], dtype='int32')

输出为:

array([1, 2, 3, 4])




请记住,你可始终使用命令 np.array 引用文档。

在数据科学的许多应用程序中非常有用,NumPy 数组明显可以是多维的(如矩阵或张量)。 下面是使用列表的列表创建多维数组的一种方法。

嵌套列表可导致多维数组:

np.array([range(i, i + 3) for i in [2, 4, 6]])

输出为:

array([[2, 3, 4],
       [4, 5, 6],
       [6, 7, 8]])

在列表的列表中,内部列表被视为你创建的二维数组的行。

创建 NumPy 数组,方法 2:从头开始构建

在实践中,使用 NumPy 内置的函数从头开始创建数组通常更有效(特别是对于较大的数组)。 以下是一些示例。 这些示例将帮助介绍多个有用的 NumPy 函数。

创建一个长度为 10 的整数数组,并以 0 填充:

np.zeros(10, dtype=int)

输出为:

array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

创建一个 3 x 5 浮点数组,并以 1 填充:

np.ones((3, 5), dtype=float)

输出为:

array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])

创建一个 3 x 5 数组,并以 3.14 填充。 元组中的第一个数字给出行数。 元组中的第二个数字设置列数。

np.full((3, 5), 3.14)

输出为:

array([[3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14]])

创建一个用线性序列填充的数组。 从 0 开始,到 20 结束,步长为 2。 (这类似于内置的 Python range() 函数。)

np.arange(0, 20, 2).

输出为:

array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

创建一个 5 个值均匀分布的数组,值介于 0 到 1 之间:

np.linspace(0, 1, 5)

输出为:

array([0.  , 0.25, 0.5 , 0.75, 1.  ])

创建一个 3 x 3 均匀分布随机值数组,值介于 0 到 1 之间:

np.random.random((3, 3))

输出为:

array([[0.1293533 , 0.00963681, 0.76015197],
       [0.97076867, 0.16947551, 0.51899825],
       [0.28123745, 0.37741323, 0.01221669]])

创建一个 3 x 3 正态分布随机值数组,平均值为 0、标准偏差为 1:

np.random.normal(0, 1, (3, 3))

输出为:

array([[ 0.41781774,  1.10706673, -1.84875856],
       [ 0.9436157 ,  0.36446661,  0.1319522 ],
       [-1.18743752,  0.48199796,  0.37693047]])

创建一个 3 x 3 随机整数数组,其间隔为 [0, 10):

np.random.randint(0, 10, (3, 3))

输出为:

array([[0, 3, 7],
       [8, 1, 8],
       [0, 5, 7]])

创建 3 x 3 单位矩阵:

np.eye(3)

输出为:

array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

创建一个包含三个整数的未初始化数组。 无论发生什么情况,这些值都将位于那个内存位置。

np.empty(3)

输出为:

array([1., 1., 1.])

现在需要花费几分钟时间返回来使用这些代码片段,并更改参数。 这些函数是创建 NumPy 数组的必备工具。 你需要熟悉它们。

下表列出了 NumPy 中的多个数组创建函数:

函数 描述
array 通过推断 ndarray 或显式指定 dtype,将输入数据(列表、元组、数组或其他序列类型)转换为 dtype。 默认复制输入数据。
asarray 如果输入已是 ndarray,则将输入转换为 ndarray 但不复制。
arange 与内置的 range() 函数类似,但返回 ndarray 而不是列表。
onesones_like ones 生成一个全为 1 的数组,并具有给定的形状和 dtype

ones_like 使用另一个数组,并生成一个形状和 dtype 相同的 1 数组。
zeroszeros_like onesones_like 相似,但生成的是 0 数组。
emptyempty_like 通过分配新内存来创建新数组,但不要像 oneszeros 那样填充值。
fullfull_like full 生成给定形状和 dtype 的数组,并将所有值设置为指示的“填充值”。

full_like 使用另一个数组,并生成一个形状和 dtype 相同的已填充的数组。
eyeidentity 创建一个方形 N x N 单位矩阵(对角线上为 1,其他位置为 0)。

NumPy 数据类型

下表列出了标准的 NumPy 数据类型。 请注意,构造数组时,可以使用字符串指定数据类型:

np.zeros(8, dtype='int16')

或者,可使用 NumPy 对象直接指定数据类型:

np.zeros(8, dtype=np.int16)

数据类型 描述
bool_ 存储为字节的布尔值(TrueFalse
int_ 默认整数类型(与 C long 相同;通常为 int64int32
intc 与 C int 相同(通常为 int32int64
intp 用于索引的整数(与 C ssize_t 相同;通常为 int32int64
int8 字节(-128 到 127)
int16 整数(-32768 到 32767)
int32 整数(-2147483648 到 2147483647)
int64 整数(-9223372036854775808 到 9223372036854775807)
uint8 无符号整数(0 到 255)
uint16 无符号整数(0 到 65535)
uint32 无符号整数(0 到 4294967295)
uint64 无符号整数(0 到 18446744073709551615)
float_ float64 的简写
float16 半精度浮点数:符号位,5 位指数,10 位尾数
float32 单精度浮点数:符号位,8 位指数,23 位尾数
float64 双精度浮点数:符号位,11 位指数,52 位尾数
complex_ complex128 的简写
complex64 复数,由 2 个 32 位浮点数表示
complex128 复数,由 2 个 64 位浮点数表示

如果这些数据类型看起来像 C 中的数据类型,这是因为 NumPy 是使用 C 生成的。

要点

 NumPy 数组是类似于 Python 列表的数据结构,可在存储和处理大量同类数据时提供高性能,而这种数据正是数据科学中经常遇到的数据类型。 NumPy 数组支持许多数据类型,本课程未全部列出。 也就是说,不必费心记住所有 NumPy dtypes。 通常只需关心你要处理的常用数据类型:浮点、整数、布尔值、字符串或常规 Python 对象。