NumPy:初学者的绝对基础知识#

欢迎来到 NumPy 的绝对初学者指南!如果您有意见或建议,请随时与我们联系

欢迎来到 NumPy!#

NumPy(数值 Python)是一个开源 Python 库,几乎用于科学和工程的每个领域。它是在 Python 中处理数值数据的通用标准,也是科学 Python 和 PyData 生态系统的核心。 NumPy 用户包括从初学者到从事最先进科学和工业研究与开发的经验丰富的研究人员的所有人。 NumPy API 广泛用于 Pandas、SciPy、Matplotlib、scikit-learn、scikit-image 和大多数其他数据科学和科学 Python 包中。

NumPy 库包含多维数组和矩阵数据结构(您将在后面的部分中找到有关此的更多信息)。它提供了 ndarray,一个同构 n 维数组对象,以及对其进行有效操作的方法。 NumPy 可用于对数组执行各种数学运算。它为 Python 添加了强大的数据结构,保证了数组和矩阵的高效计算,并且提供了一个庞大的高级数学函数库,可以对这些数组和矩阵进行操作。

在这里了解有关NumPy 的更多信息!

安装 NumPy #

要安装 NumPy,我们强烈建议使用科学的 Python 发行版。如果您正在寻找在操作系统上安装 NumPy 的完整说明,请参阅安装 NumPy

如果您已经安装了 Python,则可以使用以下命令安装 NumPy:

conda install numpy

或者

pip install numpy

如果您还没有 Python,您可能需要考虑使用Anaconda。这是最简单的入门方法。获得此发行版的好处是,您无需过多担心单独安装 NumPy 或用于数据分析的任何主要软件包,例如 pandas、Scikit-Learn 等。

如何导入 NumPy #

要访问 NumPy 及其函数,请将其导入到您的 Python 代码中,如下所示:

import numpy as np

我们使用 NumPy 缩短导入的名称,以np提高代码的可读性。这是一种广泛采用的约定,可以使您的代码对于每个使用它的人都更具可读性。我们建议始终使用 import numpy as np

阅读示例代码#

如果您还不习惯阅读包含大量代码的教程,您可能不知道如何解释如下所示的代码块:

>>> a = np.arange(6)
>>> a2 = a[np.newaxis, :]
>>> a2.shape
(1, 6)

如果您不熟悉这种风格,也很容易理解。如果您看到>>>,则您正在查看input,或者您要输入的代码。>>>前面没有的所有内容都是输出,或者运行代码的结果。这是您python在命令行上运行时看到的样式,但如果您使用 IPython,您可能会看到不同的样式。请注意,它不是代码的一部分,如果键入或粘贴到 Python shell 中,将会导致错误。它可以安全地输入或粘贴到 IPython shell 中;被>>> 忽略。

Python 列表和 NumPy 数组有什么区别?#

NumPy 为您提供了大量快速有效的方法来创建数组并操作其中的数字数据。虽然 Python 列表可以在单个列表中包含不同的数据类型,但 NumPy 数组中的所有元素都应该是同类的。如果数组不是同质的,则对数组执行的数学运算将非常低效。

为什么使用 NumPy?

NumPy 数组比 Python 列表更快、更紧凑。数组占用内存少,使用方便。 NumPy 使用更少的内存来存储数据,并且提供了指定数据类型的机制。这使得代码可以进一步优化。

什么是数组?#

数组是 NumPy 库的核心数据结构。数组是一个值网格,它包含有关原始数据、如何定位元素以及如何解释元素的信息。它有一个元素网格,可以通过多种方式进行索引。这些元素都是相同类型的,称为数组dtype

数组可以通过非负整数元组、布尔值、另一个数组或整数进行索引。数组的rank是维数。数组的shape是一个整数元组,给出了数组沿每个维度的大小。

我们初始化 NumPy 数组的一种方法是使用 Python 列表,对二维或更高维的数据使用嵌套列表。

例如:

>>> a = np.array([1, 2, 3, 4, 5, 6])

或者:

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

我们可以使用方括号访问数组中的元素。当您访问元素时,请记住 NumPy 中的索引从 0 开始。这意味着如果您想访问数组中的第一个元素,您将访问元素“0”。

>>> print(a[0])
[1 2 3 4]

有关数组的更多信息#

本节涵盖 , , , ,1D array2D arrayndarrayvectormatrix


您可能偶尔会听到称为“ndarray”的数组,它是“N 维数组”的简写。 N 维数组就是具有任意维数的数组。您可能还会听到1-D或一维数组、2-D或二维数组等等。 NumPyndarray类用于表示矩阵和向量。向量是单数组(行向量和列向量没有区别),而矩阵指二维数组。对于3 维或更高维的数组,术语 “张量”也很常用。

数组有哪些属性?

数组通常是相同类型和大小的项目的固定大小容器。数组中的维数和项数由其形状定义。数组的形状是指定每个维度大小的非负整数元组。

在 NumPy 中,维度称为。这意味着如果您有一个如下所示的二维数组:

[[0., 0., 0.],
 [1., 1., 1.]]

你的数组有 2 个轴。第一个轴的长度为 2,第二个轴的长度为 3。

就像在其他 Python 容器对象中一样,可以通过索引或切片数组来访问和修改数组的内容。与典型的容器对象不同,不同的数组可以共享相同的数据,因此对一个数组所做的更改可能在另一个数组中可见。

数组属性反映了数组本身固有的信息。如果需要获取甚至设置数组的属性而不创建新数组,通常可以通过数组的属性来访问该数组。

在此处阅读有关数组属性的更多信息,并在此处了解 有关数组对象的信息。

如何创建一个基本数组#

本节涵盖 np.array(), np.zeros(), np.ones(), np.empty(), np.arange(), np.linspace(),dtype


要创建 NumPy 数组,您可以使用函数np.array()

创建一个简单数组所需要做的就是向其传递一个列表。如果您选择,还可以指定列表中的数据类型。 您可以在此处找到有关数据类型的更多信息

>>> import numpy as np
>>> a = np.array([1, 2, 3])

您可以这样可视化您的数组:

../_images/np_array.png

请注意,这些可视化旨在简化想法并让您对 NumPy 概念和机制有基本的了解。数组和数组操作比这里捕获的要复杂得多!

除了从元素序列创建数组之外,您还可以轻松创建用0' 填充的数组:

>>> np.zeros(2)
array([0., 0.])

1或者用's填充的数组:

>>> np.ones(2)
array([1., 1.])

或者甚至是一个空数组!该函数empty创建一个数组,其初始内容是随机的,并且取决于内存的状态。使用emptyover (或类似的东西)的原因 zeros是速度 - 只要确保之后填充每个元素即可!

>>> # Create an empty array with 2 elements
>>> np.empty(2) 
array([3.14, 42.  ])  # may vary

您可以创建一个包含一系列元素的数组:

>>> np.arange(4)
array([0, 1, 2, 3])

甚至是包含一系列均匀间隔的数组。为此,您将指定第一个数字最后一个数字步长

>>> np.arange(2, 9, 2)
array([2, 4, 6, 8])

您还可以使用np.linspace()以指定间隔线性间隔的值创建数组:

>>> np.linspace(0, 10, num=5)
array([ 0. ,  2.5,  5. ,  7.5, 10. ])

指定您的数据类型

虽然默认数据类型是浮点 ( np.float64),但您可以使用关键字显式指定所需的数据类型dtype

>>> x = np.ones(2, dtype=np.int64)
>>> x
array([1, 1])

在此处了解有关创建数组的更多信息

添加、删除和排序元素#

本节涵盖 np.sort()np.concatenate()


使用 来对元素进行排序很简单np.sort()。您可以在调用函数时指定轴、种类和顺序。

如果你从这个数组开始:

>>> arr = np.array([2, 1, 5, 3, 7, 4, 6, 8])

您可以使用以下命令快速按升序对数字进行排序:

>>> np.sort(arr)
array([1, 2, 3, 4, 5, 6, 7, 8])

除了返回数组的排序副本的排序之外,您还可以使用:

  • argsort,这是沿指定轴的间接排序,

  • lexsort,这是对多个键的间接稳定排序,

  • searchsorted,它将在排序数组中查找元素,并且

  • partition,这是部分排序。

要了解有关数组排序的更多信息,请参阅:sort

如果您从这些数组开始:

>>> a = np.array([1, 2, 3, 4])
>>> b = np.array([5, 6, 7, 8])

您可以将它们连接起来np.concatenate()

>>> np.concatenate((a, b))
array([1, 2, 3, 4, 5, 6, 7, 8])

或者,如果您从这些数组开始:

>>> x = np.array([[1, 2], [3, 4]])
>>> y = np.array([[5, 6]])

您可以将它们连接起来:

>>> np.concatenate((x, y), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])

为了从数组中删除元素,使用索引来选择要保留的元素很简单。

要了解有关连接的更多信息,请参阅:concatenate

你如何知道数组的形状和大小?#

本节涵盖 ndarray.ndim, ndarray.size,ndarray.shape


ndarray.ndim会告诉您数组的轴数或维数。

ndarray.size会告诉你数组元素的总数。这是数组形状元素的乘积。

ndarray.shape将显示一个整数元组,指示沿数组每个维度存储的元素数量。例如,如果您有一个 2 行 3 列的二维数组,则数组的形状为。(2, 3)

例如,如果您创建此数组:

>>> array_example = np.array([[[0, 1, 2, 3],
...                            [4, 5, 6, 7]],
...
...                           [[0, 1, 2, 3],
...                            [4, 5, 6, 7]],
...
...                           [[0 ,1 ,2, 3],
...                            [4, 5, 6, 7]]])

要查找数组的维数,请运行:

>>> array_example.ndim
3

要查找数组中的元素总数,请运行:

>>> array_example.size
24

要查找数组的形状,请运行:

>>> array_example.shape
(3, 2, 4)

你能重塑一个数组吗?#

本节涵盖 arr.reshape()


是的!

使用arr.reshape()将为数组提供新的形状而不更改数据。请记住,当您使用 reshape 方法时,要生成的数组需要与原始数组具有相同数量的元素。如果您从包含 12 个元素的数组开始,则需要确保新数组也总共包含 12 个元素。

如果你从这个数组开始:

>>> a = np.arange(6)
>>> print(a)
[0 1 2 3 4 5]

您可以使用reshape()它来重塑数组。例如,您可以将此数组重塑为三行两列的数组:

>>> b = a.reshape(3, 2)
>>> print(b)
[[0 1]
 [2 3]
 [4 5]]

使用np.reshape,您可以指定一些可选参数:

>>> np.reshape(a, newshape=(1, 6), order='C')
array([[0, 1, 2, 3, 4, 5]])

a是要重塑的数组。

newshape是你想要的新形状。您可以指定一个整数或整数元组。如果指定一个整数,结果将是该长度的数组。形状应与原始形状兼容。

order: C表示使用类 C 索引顺序读/写元素, F表示使用类 Fortran 索引顺序读/写元素,A 表示如果 a 在内存中是 Fortran 连续的,则表示按类 Fortran 索引顺序读/写元素,C -否则类似订单。 (这是一个可选参数,不需要指定。)

如果您想了解有关 C 和 Fortran 顺序的更多信息,可以 在此处阅读有关 NumPy 数组的内部组织的更多信息。本质上,C 和 Fortran 顺序与索引如何对应数组在内存中存储的顺序有关。在 Fortran 中,当移动存储在内存中的二维数组的元素时,第一个 索引是变化最快的索引。当第一个索引发生变化时移动到下一行时,矩阵一次存储一列。这就是为什么 Fortran 被认为是一种列主语言。另一方面,在 C 中,最后一个索引变化最快。矩阵按行存储,使其成为行优先语言。您对 C 或 Fortran 所做的操作取决于保留索引约定更重要还是不重新排序数据更重要。

在此处了解有关形状操作的更多信息

如何将一维数组转换为二维数组(如何向数组添加新轴)#

本节涵盖 np.newaxisnp.expand_dims


您可以使用np.newaxisnp.expand_dims来增加现有数组的维度。

使用np.newaxis一次后,数组的维度就会增加一维。这意味着1D数组将变成2D数组, 2D数组将变成3D数组,依此类推。

例如,如果您从此数组开始:

>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> a.shape
(6,)

您可以使用np.newaxis添加新轴:

>>> a2 = a[np.newaxis, :]
>>> a2.shape
(1, 6)

您可以使用 显式转换具有行向量或列向量的一维数组np.newaxis。例如,您可以通过沿第一维插入轴将一维数组转换为行向量:

>>> row_vector = a[np.newaxis, :]
>>> row_vector.shape
(1, 6)

或者,对于列向量,您可以沿第二维插入轴:

>>> col_vector = a[:, np.newaxis]
>>> col_vector.shape
(6, 1)

您还可以通过在指定位置插入新轴来扩展数组np.expand_dims

例如,如果您从此数组开始:

>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> a.shape
(6,)

您可以使用np.expand_dims以下命令在索引位置 1 添加轴:

>>> b = np.expand_dims(a, axis=1)
>>> b.shape
(6, 1)

您可以使用以下命令在索引位置 0 添加轴:

>>> c = np.expand_dims(a, axis=0)
>>> c.shape
(1, 6)

在此处和 此处查找有关newaxis的更多信息。expand_dimsexpand_dims

索引和切片#

您可以像对 Python 列表进行切片一样对 NumPy 数组进行索引和切片。

>>> data = np.array([1, 2, 3])

>>> data[1]
2
>>> data[0:2]
array([1, 2])
>>> data[1:]
array([2, 3])
>>> data[-2:]
array([2, 3])

你可以这样想象它:

../_images/np_indexing.png

您可能想要获取数组的一部分或特定数组元素以用于进一步分析或其他操作。为此,您需要对数组进行子集化、切片和/或索引。

如果您想从数组中选择满足特定条件的值,使用 NumPy 就很简单。

例如,如果您从此数组开始:

>>> a = np.array([[1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

您可以轻松打印数组中所有小于 5 的值。

>>> print(a[a < 5])
[1 2 3 4]

例如,您还可以选择等于或大于 5 的数字,并使用该条件来索引数组。

>>> five_up = (a >= 5)
>>> print(a[five_up])
[ 5  6  7  8  9 10 11 12]

您可以选择能被 2 整除的元素:

>>> divisible_by_2 = a[a%2==0]
>>> print(divisible_by_2)
[ 2  4  6  8 10 12]

&或者您可以使用and运算符选择满足两个条件的元素|

>>> c = a[(a > 2) & (a < 11)]
>>> print(c)
[ 3  4  5  6  7  8  9 10]

您还可以使用逻辑运算符&|为了返回指定数组中的值是否满足特定条件的布尔值。这对于包含名称或其他分类值的数组非常有用。

>>> five_up = (a > 5) | (a == 5)
>>> print(five_up)
[[False False False False]
 [ True  True  True  True]
 [ True  True  True True]]

您还可以用于np.nonzero()从数组中选择元素或索引。

从这个数组开始:

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

例如,您可以用来np.nonzero()打印小于 5 的元素的索引:

>>> b = np.nonzero(a < 5)
>>> print(b)
(array([0, 0, 0, 0]), array([0, 1, 2, 3]))

在此示例中,返回了一个数组元组:每个维度一个。第一个数组表示找到这些值的行索引,第二个数组表示找到这些值的列索引。

如果要生成元素所在的坐标列表,可以压缩数组,迭代坐标列表,然后打印它们。例如:

>>> list_of_coordinates= list(zip(b[0], b[1]))

>>> for coord in list_of_coordinates:
...     print(coord)
(0, 0)
(0, 1)
(0, 2)
(0, 3)

您还可以使用np.nonzero()以下命令打印数组中小于 5 的元素:

>>> print(a[b])
[1 2 3 4]

如果数组中不存在您要查找的元素,则返回的索引数组将为空。例如:

>>> not_there = np.nonzero(a == 42)
>>> print(not_there)
(array([], dtype=int64), array([], dtype=int64))

在此处和此处了解有关索引和切片的更多信息。

有关使用非零函数的更多信息,请访问:nonzero

如何从现有数据创建数组#

本节涵盖 , , , , ,slicing and indexingnp.vstack()np.hstack()np.hsplit().view()copy()


您可以轻松地从现有数组的一部分创建新数组。

假设您有这个数组:

>>> a = np.array([1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

您可以随时通过指定要对数组进行切片的位置来从数组的一部分创建新数组。

>>> arr1 = a[3:8]
>>> arr1
array([4, 5, 6, 7, 8])

在这里,您从索引位置 3 到索引位置 8 抓取了数组的一部分。

您还可以垂直和水平堆叠两个现有阵列。假设您有两个数组,a1并且a2

>>> a1 = np.array([[1, 1],
...                [2, 2]])

>>> a2 = np.array([[3, 3],
...                [4, 4]])

您可以使用以下命令垂直堆叠它们vstack

>>> np.vstack((a1, a2))
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

或者水平堆叠它们hstack

>>> np.hstack((a1, a2))
array([[1, 1, 3, 3],
       [2, 2, 4, 4]])

您可以使用将一个数组拆分为多个较小的数组hsplit。您可以指定要返回的形状相同的数组的数量或 应其后进行除法的列。

假设您有这个数组:

>>> x = np.arange(1, 25).reshape(2, 12)
>>> x
array([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12],
       [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])

如果你想把这个数组分成三个形状相同的数组,你可以运行:

>>> np.hsplit(x, 3)
  [array([[ 1,  2,  3,  4],
         [13, 14, 15, 16]]), array([[ 5,  6,  7,  8],
         [17, 18, 19, 20]]), array([[ 9, 10, 11, 12],
         [21, 22, 23, 24]])]

如果您想在第三列和第四列之后拆分数组,您可以运行:

>>> np.hsplit(x, (3, 4))
  [array([[ 1,  2,  3],
         [13, 14, 15]]), array([[ 4],
         [16]]), array([[ 5,  6,  7,  8,  9, 10, 11, 12],
         [17, 18, 19, 20, 21, 22, 23, 24]])]

在此处了解有关堆叠和拆分数组的更多信息

您可以使用该view方法创建一个新的数组对象,该对象查看与原始数组(浅表副本)相同的数据。

视图是一个重要的 NumPy 概念! NumPy 函数以及索引和切片等操作将尽可能返回视图。这可以节省内存并且速度更快(无需复制数据)。然而,重要的是要注意这一点 - 修改视图中的数据也会修改原始数组!

假设您创建了这个数组:

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

b1现在我们通过切片创建一个数组a并修改 的第一个元素 b1。这也会修改相应的元素a

>>> b1 = a[0, :]
>>> b1
array([1, 2, 3, 4])
>>> b1[0] = 99
>>> b1
array([99,  2,  3,  4])
>>> a
array([[99,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])

使用该copy方法将制作数组及其数据的完整副本( 深层副本)。要在您的阵列上使用它,您可以运行:

>>> b2 = a.copy()

在此处了解有关副本和视图的更多信息

基本数组操作#

本节涵盖加法、减法、乘法、除法等


创建阵列后,您就可以开始使用它们。例如,假设您创建了两个数组,一个称为“data”,另一个称为“ones”

../_images/np_array_dataones.png

您可以使用加号将数组添加在一起。

>>> data = np.array([1, 2])
>>> ones = np.ones(2, dtype=int)
>>> data + ones
array([2, 3])
../_images/np_data_plus_ones.png

当然,您可以做的不仅仅是加法!

>>> data - ones
array([0, 1])
>>> data * data
array([1, 4])
>>> data / data
array([1., 1.])
../_images/np_sub_mult_divide.png

使用 NumPy 进行基本操作很简单。如果你想求数组中元素的总和,你可以使用sum().这适用于一维数组、二维数组和更高维度的数组。

>>> a = np.array([1, 2, 3, 4])

>>> a.sum()
10

要在二维数组中添加行或列,您需要指定轴。

如果你从这个数组开始:

>>> b = np.array([[1, 1], [2, 2]])

您可以使用以下方法对行轴求和:

>>> b.sum(axis=0)
array([3, 3])

您可以使用以下方法对列轴求和:

>>> b.sum(axis=1)
array([2, 4])

在此处了解有关基本操作的更多信息

广播#

有时您可能想要在数组和单个数字之间或在两个不同大小的数组之间执行运算(也称为向量和标量之间的运算)。例如,您的数组(我们将其称为“数据”)可能包含有关英里距离的信息,但您希望将信息转换为公里。您可以通过以下方式执行此操作:

>>> data = np.array([1.0, 2.0])
>>> data * 1.6
array([1.6, 3.2])
../_images/np_multiply_broadcasting.png

NumPy 知道每个单元格都应该进行乘法。这个概念称为广播。广播是一种允许 NumPy 对不同形状的数组执行操作的机制。数组的维度必须兼容,例如,当两个数组的维度相等或其中一个数组的维度为 1 时。如果维度不兼容,您将得到一个ValueError.

在此处了解有关广播的更多信息

更有用的数组操作#

本节涵盖最大值、最小值、总和、平均值、乘积、标准差等


NumPy 还执行聚合函数。除了minmax、 和 之外sum,您还可以轻松运行mean来获取平均值、prod获取元素相乘的结果、std获取标准差等等。

>>> data.max()
2.0
>>> data.min()
1.0
>>> data.sum()
3.0
../_images/np_aggregation.png

让我们从这个名为“a”的数组开始

>>> a = np.array([[0.45053314, 0.17296777, 0.34376245, 0.5510652],
...               [0.54627315, 0.05093587, 0.40067661, 0.55645993],
...               [0.12697628, 0.82485143, 0.26590556, 0.56917101]])

想要沿着行或列聚合是很常见的。默认情况下,每个 NumPy 聚合函数都会返回整个数组的聚合。要查找数组中元素的总和或最小值,请运行:

>>> a.sum()
4.8595784

或者:

>>> a.min()
0.05093587

您可以指定要在哪个轴上计算聚合函数。例如,您可以通过指定 查找每列中的最小值 axis=0

>>> a.min(axis=0)
array([0.12697628, 0.05093587, 0.26590556, 0.5510652 ])

上面列出的四个值对应于数组中的列数。对于四列数组,您将得到四个值作为结果。

在此处阅读有关数组方法的更多信息。

创建矩阵#

您可以传递 Python 列表列表来创建二维数组(或“矩阵”)以在 NumPy 中表示它们。

>>> data = np.array([[1, 2], [3, 4], [5, 6]])
>>> data
array([[1, 2],
       [3, 4],
       [5, 6]])
../_images/np_create_matrix.png

当您操作矩阵时,索引和切片操作非常有用:

>>> data[0, 1]
2
>>> data[1:3]
array([[3, 4],
       [5, 6]])
>>> data[0:2, 0]
array([1, 3])
../_images/np_matrix_indexing.png

您可以像聚合向量一样聚合矩阵:

>>> data.max()
6
>>> data.min()
1
>>> data.sum()
21
../_images/np_matrix_aggregation.png

您可以聚合矩阵中的所有值,也可以使用参数跨列或行聚合它们axis。为了说明这一点,让我们看一下稍微修改过的数据集:

>>> data = np.array([[1, 2], [5, 3], [4, 6]])
>>> data
array([[1, 2],
       [5, 3],
       [4, 6]])
>>> data.max(axis=0)
array([5, 6])
>>> data.max(axis=1)
array([2, 5, 6])
../_images/np_matrix_aggregation_row.png

创建矩阵后,如果有两个大小相同的矩阵,则可以使用算术运算符对它们进行加法和乘法。

>>> data = np.array([[1, 2], [3, 4]])
>>> ones = np.array([[1, 1], [1, 1]])
>>> data + ones
array([[2, 3],
       [4, 5]])
../_images/np_matrix_arithmetic.png

您可以对不同大小的矩阵执行这些算术运算,但前提是一个矩阵只有一列或一行。在这种情况下,NumPy 将使用其广播规则进行操作。

>>> data = np.array([[1, 2], [3, 4], [5, 6]])
>>> ones_row = np.array([[1, 1]])
>>> data + ones_row
array([[2, 3],
       [4, 5],
       [6, 7]])
../_images/np_matrix_broadcasting.png

请注意,当 NumPy 打印 N 维数组时,最后一个轴的循环速度最快,而第一个轴的循环速度最慢。例如:

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

       [[1., 1.],
        [1., 1.],
        [1., 1.]],

       [[1., 1.],
        [1., 1.],
        [1., 1.]],

       [[1., 1.],
        [1., 1.],
        [1., 1.]]])

在很多情况下,我们希望 NumPy 初始化数组的值。 NumPy 提供了ones()和等函数zeros(),以及 random.Generator用于生成随机数的类。您需要做的就是传入您希望它生成的元素数量:

>>> np.ones(3)
array([1., 1., 1.])
>>> np.zeros(3)
array([0., 0., 0.])
>>> rng = np.random.default_rng()  # the simplest way to generate random numbers
>>> rng.random(3) 
array([0.63696169, 0.26978671, 0.04097352])
../_images/np_ones_zeros_random.png

如果您给它们一个描述矩阵维度的元组,您还可以使用ones()zeros()random()创建一个二维数组:

>>> np.ones((3, 2))
array([[1., 1.],
       [1., 1.],
       [1., 1.]])
>>> np.zeros((3, 2))
array([[0., 0.],
       [0., 0.],
       [0., 0.]])
>>> rng.random((3, 2)) 
array([[0.01652764, 0.81327024],
       [0.91275558, 0.60663578],
       [0.72949656, 0.54362499]])  # may vary
../_images/np_ones_zeros_matrix.png

在数组创建例程0中了解有关创建数组(用's、 's、其他值填充1或未初始化)的更多信息。

生成随机数#

随机数生成的使用是许多数值和机器学习算法的配置和评估的重要组成部分。无论您需要随机初始化人工神经网络中的权重、将数据拆分为随机集,还是随机洗牌数据集,能够生成随机数(实际上是可重复的伪随机数)都是至关重要的。

使用Generator.integers,您可以生成从低位(记住这包括 NumPy)到高位(不包括 NumPy)的随机整数。您可以设置 endpoint=True为包含较高的数字。

您可以使用以下命令生成 2 x 4 的 0 到 4 之间的随机整数数组:

>>> rng.integers(5, size=(2, 4)) 
array([[2, 1, 1, 0],
       [0, 0, 0, 4]])  # may vary

在此处阅读有关随机数生成的更多信息

如何获得独特的物品和数量#

本节涵盖 np.unique()


您可以使用 轻松找到数组中的唯一元素np.unique

例如,如果您从此数组开始:

>>> a = np.array([11, 11, 12, 13, 14, 15, 16, 17, 12, 13, 11, 14, 18, 19, 20])

您可以使用np.unique打印数组中的唯一值:

>>> unique_values = np.unique(a)
>>> print(unique_values)
[11 12 13 14 15 16 17 18 19 20]

要获取 NumPy 数组中唯一值的索引(数组中唯一值的第一个索引位置的数组),只需传入参数return_index 以及np.unique()数组即可。

>>> unique_values, indices_list = np.unique(a, return_index=True)
>>> print(indices_list)
[ 0  2  3  4  5  6  7 12 13 14]

您可以将return_counts参数np.unique()与数组一起传递,以获取 NumPy 数组中唯一值的频率计数。

>>> unique_values, occurrence_count = np.unique(a, return_counts=True)
>>> print(occurrence_count)
[3 2 2 2 1 1 1 1 1 1]

这也适用于二维数组!如果你从这个数组开始:

>>> a_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]])

您可以通过以下方式找到独特的值:

>>> unique_values = np.unique(a_2d)
>>> print(unique_values)
[ 1  2  3  4  5  6  7  8  9 10 11 12]

如果未传递 axis 参数,您的 2D 数组将被展平。

如果您想获取唯一的行或列,请确保传递参数axis 。要查找唯一的行,请指定axis=0,对于列,请指定 axis=1

>>> unique_rows = np.unique(a_2d, axis=0)
>>> print(unique_rows)
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]

要获取唯一行、索引位置和出现次数,您可以使用:

>>> unique_rows, indices, occurrence_count = np.unique(
...      a_2d, axis=0, return_counts=True, return_index=True)
>>> print(unique_rows)
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
>>> print(indices)
[0 1 2]
>>> print(occurrence_count)
[2 1 1]

要了解有关查找数组中唯一元素的更多信息,请参阅unique

转置和重塑矩阵#

本节涵盖 arr.reshape(), arr.transpose(),arr.T


需要转置矩阵是很常见的。 NumPy 数组具有T允许您转置矩阵的属性 。

../_images/np_transpose_reshaping.png

您可能还需要切换矩阵的维度。例如,当您的模型需要与数据集不同的特定输入形状时,就会发生这种情况。这就是该reshape方法可以发挥作用的地方。您只需传入矩阵所需的新维度即可。

>>> data.reshape(2, 3)
array([[1, 2, 3],
       [4, 5, 6]])
>>> data.reshape(3, 2)
array([[1, 2],
       [3, 4],
       [5, 6]])
../_images/np_reshape.png

您还可以.transpose()根据指定的值反转或更改数组的轴。

如果你从这个数组开始:

>>> arr = np.arange(6).reshape((2, 3))
>>> arr
array([[0, 1, 2],
       [3, 4, 5]])

您可以使用 转置数组arr.transpose()

>>> arr.transpose()
array([[0, 3],
       [1, 4],
       [2, 5]])

您还可以使用arr.T

>>> arr.T
array([[0, 3],
       [1, 4],
       [2, 5]])

要了解有关转置和重塑数组的更多信息,请参阅transposereshape

如何反转数组#

本节涵盖 np.flip()


NumPy 的np.flip()函数允许您沿轴翻转或反转数组的内容。使用 时np.flip(),指定要反转的数组和轴。如果您不指定轴,NumPy 将沿输入数组的所有轴反转内容。

反转一维数组

如果您从像这样的一维数组开始:

>>> arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])

您可以通过以下方式反转它:

>>> reversed_arr = np.flip(arr)

如果你想打印反转的数组,你可以运行:

>>> print('Reversed Array: ', reversed_arr)
Reversed Array:  [8 7 6 5 4 3 2 1]

反转二维数组

二维数组的工作原理大致相同。

如果你从这个数组开始:

>>> arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

您可以使用以下命令反转所有行和所有列中的内容:

>>> reversed_arr = np.flip(arr_2d)
>>> print(reversed_arr)
[[12 11 10  9]
 [ 8  7  6  5]
 [ 4  3  2  1]]

您可以轻松地仅反转

>>> reversed_arr_rows = np.flip(arr_2d, axis=0)
>>> print(reversed_arr_rows)
[[ 9 10 11 12]
 [ 5  6  7  8]
 [ 1  2  3  4]]

或者仅反转

>>> reversed_arr_columns = np.flip(arr_2d, axis=1)
>>> print(reversed_arr_columns)
[[ 4  3  2  1]
 [ 8  7  6  5]
 [12 11 10  9]]

您还可以仅反转一列或一行的内容。例如,您可以反转索引位置 1 处的行内容(第二行):

>>> arr_2d[1] = np.flip(arr_2d[1])
>>> print(arr_2d)
[[ 1  2  3  4]
 [ 8  7  6  5]
 [ 9 10 11 12]]

您还可以反转索引位置 1 处的列(第二列):

>>> arr_2d[:,1] = np.flip(arr_2d[:,1])
>>> print(arr_2d)
[[ 1 10  3  4]
 [ 8  7  6  5]
 [ 9  2 11 12]]

阅读有关反转数组的更多信息flip

重塑和展平多维数组#

本节涵盖 .flatten()ravel()


有两种流行的方法来展平数组:.flatten().ravel()。两者之间的主要区别在于,使用创建的新数组 ravel()实际上是对父数组(即“视图”)的引用。这意味着对新数组的任何更改也会影响父数组。由于ravel不创建副本,因此内存效率很高。

如果你从这个数组开始:

>>> x = np.array([[1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

您可以使用flatten将数组展平为一维数组。

>>> x.flatten()
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])

当您使用 时flatten,对新数组的更改不会更改父数组。

例如:

>>> a1 = x.flatten()
>>> a1[0] = 99
>>> print(x)  # Original array
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
>>> print(a1)  # New array
[99  2  3  4  5  6  7  8  9 10 11 12]

但是当您使用 时ravel,对新数组所做的更改将影响父数组。

例如:

>>> a2 = x.ravel()
>>> a2[0] = 98
>>> print(x)  # Original array
[[98  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
>>> print(a2)  # New array
[98  2  3  4  5  6  7  8  9 10 11 12]

阅读有关flattenatndarray.flattenravelat 的更多信息ravel

如何访问文档字符串以获取更多信息#

本节涵盖 help(), ?,??


当谈到数据科学生态系统时,Python 和 NumPy 都是以用户为中心而构建的。最好的例子之一就是对文档的内置访问。每个对象都包含对字符串的引用,该字符串称为docstring。在大多数情况下,此文档字符串包含对象及其使用方法的快速而简洁的摘要。 Python 有一个内置help() 函数可以帮助您访问此信息。这意味着几乎任何时候您需要更多信息时,您都可以使用help()它来快速查找所需的信息。

例如:

>>> help(max)
Help on built-in function max in module builtins:

max(...)
    max(iterable, *[, default=obj, key=func]) -> value
    max(arg1, arg2, *args, *[, key=func]) -> value

    With a single iterable argument, return its biggest item. The
    default keyword-only argument specifies an object to return if
    the provided iterable is empty.
    With two or more arguments, return the largest argument.

由于访问附加信息非常有用,因此 IPython 使用该? 字符作为访问此文档以及其他相关信息的简写。 IPython 是一种用于多种语言交互式计算的命令 shell。 您可以在此处找到有关 IPython 的更多信息

例如:

In [0]: max?
max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value

With a single iterable argument, return its biggest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more arguments, return the largest argument.
Type:      builtin_function_or_method

您甚至可以将此表示法用于对象方法和对象本身。

假设您创建了这个数组:

>>> a = np.array([1, 2, 3, 4, 5, 6])

然后你可以获得很多有用的信息(首先是关于它自己的详细信息,然后是它的实例a的文档字符串):ndarraya

In [1]: a?
Type:            ndarray
String form:     [1 2 3 4 5 6]
Length:          6
File:            ~/anaconda3/lib/python3.9/site-packages/numpy/__init__.py
Docstring:       <no docstring>
Class docstring:
ndarray(shape, dtype=float, buffer=None, offset=0,
        strides=None, order=None)

An array object represents a multidimensional, homogeneous array
of fixed-size items.  An associated data-type object describes the
format of each element in the array (its byte-order, how many bytes it
occupies in memory, whether it is an integer, a floating point number,
or something else, etc.)

Arrays should be constructed using `array`, `zeros` or `empty` (refer
to the See Also section below).  The parameters given here refer to
a low-level method (`ndarray(...)`) for instantiating an array.

For more information, refer to the `numpy` module and examine the
methods and attributes of an array.

Parameters
----------
(for the __new__ method; see Notes below)

shape : tuple of ints
        Shape of created array.
...

这也适用于创建的函数和其他对象。只需记住使用字符串文字(或在文档周围)在您的函数中包含文档字符串。""" """''' '''

例如,如果您创建此函数:

>>> def double(a):
...   '''Return a * 2'''
...   return a * 2

您可以获取有关该功能的信息:

In [2]: double?
Signature: double(a)
Docstring: Return a * 2
File:      ~/Desktop/<ipython-input-23-b5adf20be596>
Type:      function

您可以通过阅读您感兴趣的对象的源代码来获得另一个级别的信息。使用双问号 ( ??) 允许您访问源代码。

例如:

In [3]: double??
Signature: double(a)
Source:
def double(a):
    '''Return a * 2'''
    return a * 2
File:      ~/Desktop/<ipython-input-23-b5adf20be596>
Type:      function

如果相关对象是用 Python 以外的语言编译的,则 using ??将返回与?.您会发现它有很多内置对象和类型,例如:

In [4]: len?
Signature: len(obj, /)
Docstring: Return the number of items in a container.
Type:      builtin_function_or_method

和 :

In [5]: len??
Signature: len(obj, /)
Docstring: Return the number of items in a container.
Type:      builtin_function_or_method

具有相同的输出,因为它们是用 Python 以外的编程语言编译的。

使用数学公式#

易于实现适用于数组的数学公式是 NumPy 在科学 Python 社区中广泛使用的原因之一。

例如,这是均方误差公式(处理回归的监督机器学习模型中使用的中心公式):

../_images/np_MSE_formula.png

在 NumPy 中实现这个公式简单明了:

../_images/np_MSE_implementation.png

之所以如此有效,是因为predictionsandlabels可以包含一个或一千个值。它们只需大小相同即可。

你可以这样想象它:

../_images/np_mse_viz1.png

在此示例中,预测向量和标签向量都包含三个值,即n含义的值为三。执行减法后,向量中的值将被平方。然后 NumPy 对这些值求和,结果就是该预测的误差值和模型质量的分数。

../_images/np_mse_viz2.png ../_images/np_MSE_explanation2.png

如何保存和加载 NumPy 对象#

本节涵盖 np.save, np.savez, np.savetxt, np.load,np.loadtxt


在某些时候,您可能希望将阵列保存到磁盘并将其加载回来,而无需重新运行代码。幸运的是,有多种方法可以使用 NumPy 保存和加载对象。 ndarray 对象可以使用处理普通文本文件的函数、loadtxt处理具有.npy文件扩展名的 NumPy 二进制文件的函数以及处理具有.npz文件扩展名的 NumPy 文件的函数保存到磁盘文件或从磁盘文件加载。savetxtloadsavesavez

.npy和.npz文件以允许正确检索数组的方式存储重建 ndarray 所需的数据、形状、dtype 和其他信息,即使文件位于具有不同体系结构的另一台计算机上也是如此

如果要存储单个 ndarray 对象,请使用 .npy 文件将其存储为 .npy 文件 np.save。如果要在单个文件中存储多个 ndarray 对象,请使用 .npz 文件将其保存为 .npz 文件np.savez。您还可以将多个数组以压缩 npz 格式保存到单个文件中,扩展名为savez_compressed.

使用 可以轻松保存、加载和排列np.save()。只需确保指定要保存的数组和文件名即可。例如,如果您创建此数组:

>>> a = np.array([1, 2, 3, 4, 5, 6])

您可以使用以下命令将其另存为“filename.npy”:

>>> np.save('filename', a)

您可以使用它np.load()来重建您的数组。

>>> b = np.load('filename.npy')

如果你想检查你的数组,你可以运行:

>>> print(b)
[1 2 3 4 5 6]

您可以将 NumPy 数组保存为纯文本文件,例如带有.csv.txtnp.savetxt文件。

例如,如果您创建此数组:

>>> csv_arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])

您可以轻松地将其保存为 .csv 文件,名称为“new_file.csv”,如下所示:

>>> np.savetxt('new_file.csv', csv_arr)

您可以使用以下命令快速轻松地加载保存的文本文件loadtxt()

>>> np.loadtxt('new_file.csv')
array([1., 2., 3., 4., 5., 6., 7., 8.])

和函数接受其他可选参数savetxt()loadtxt()例如页眉、页脚和分隔符。虽然文本文件更容易共享,但 .npy 和 .npz 文件更小且读取速度更快。如果您需要对文本文件进行更复杂的处理(例如,如果您需要处理包含缺失值的行),您将需要使用该genfromtxt 函数。

使用savetxt,您可以指定页眉、页脚、注释等。

在此处了解有关输入和输出例程的更多信息。

导入和导出 CSV #

读取包含现有信息的 CSV 非常简单。最好、最简单的方法是使用 Pandas

>>> import pandas as pd

>>> # If all of your columns are the same type:
>>> x = pd.read_csv('music.csv', header=0).values
>>> print(x)
[['Billie Holiday' 'Jazz' 1300000 27000000]
 ['Jimmie Hendrix' 'Rock' 2700000 70000000]
 ['Miles Davis' 'Jazz' 1500000 48000000]
 ['SIA' 'Pop' 2000000 74000000]]

>>> # You can also simply select the columns you need:
>>> x = pd.read_csv('music.csv', usecols=['Artist', 'Plays']).values
>>> print(x)
[['Billie Holiday' 27000000]
 ['Jimmie Hendrix' 70000000]
 ['Miles Davis' 48000000]
 ['SIA' 74000000]]
../_images/np_pandas.png

使用 Pandas 导出数组也很简单。如果您是 NumPy 新手,您可能需要根据数组中的值创建 Pandas 数据框,然后使用 Pandas 将数据框写入 CSV 文件。

如果你创建了这个数组“a”

>>> a = np.array([[-2.58289208,  0.43014843, -1.24082018, 1.59572603],
...               [ 0.99027828, 1.17150989,  0.94125714, -0.14692469],
...               [ 0.76989341,  0.81299683, -0.95068423, 0.11769564],
...               [ 0.20484034,  0.34784527,  1.96979195, 0.51992837]])

您可以创建一个 Pandas 数据框

>>> df = pd.DataFrame(a)
>>> print(df)
          0         1         2         3
0 -2.582892  0.430148 -1.240820  1.595726
1  0.990278  1.171510  0.941257 -0.146925
2  0.769893  0.812997 -0.950684  0.117696
3  0.204840  0.347845  1.969792  0.519928

您可以使用以下方法轻松保存数据框:

>>> df.to_csv('pd.csv')

并使用以下命令读取您的 CSV:

>>> data = pd.read_csv('pd.csv')
../_images/np_readcsv.png

您还可以使用 NumPy 方法保存数组savetxt

>>> np.savetxt('np.csv', a, fmt='%.2f', delimiter=',', header='1,  2,  3,  4')

如果您使用命令行,则可以随时使用以下命令读取保存的 CSV:

$ cat np.csv
#  1,  2,  3,  4
-2.58,0.43,-1.24,1.60
0.99,1.17,0.94,-0.15
0.77,0.81,-0.95,0.12
0.20,0.35,1.97,0.52

或者您可以随时使用文本编辑器打开该文件!

如果您有兴趣了解有关 Pandas 的更多信息,请查看 Pandas 官方文档。通过Pandas 官方安装信息了解如何安装 Pandas 。

使用 Matplotlib 绘制数组#

如果您需要为您的值生成图表,使用 Matplotlib非常简单。

例如,您可能有一个像这样的数组:

>>> a = np.array([2, 1, 5, 7, 4, 6, 8, 14, 10, 9, 18, 20, 22])

如果您已经安装了 Matplotlib,则可以使用以下命令导入它:

>>> import matplotlib.pyplot as plt

# If you're using Jupyter Notebook, you may also want to run the following
# line of code to display your code in the notebook:

%matplotlib inline

绘制值所需要做的就是运行:

>>> plt.plot(a)

# If you are running from a command line, you may need to do this:
# >>> plt.show()
../_images/matplotlib1.png

例如,您可以像这样绘制一维数组:

>>> x = np.linspace(0, 5, 20)
>>> y = np.linspace(0, 10, 20)
>>> plt.plot(x, y, 'purple') # line
>>> plt.plot(x, y, 'o')      # dots
../_images/matplotlib2.png

借助 Matplotlib,您可以访问大量可视化选项。

>>> fig = plt.figure()
>>> ax = fig.add_subplot(projection='3d')
>>> X = np.arange(-5, 5, 0.15)
>>> Y = np.arange(-5, 5, 0.15)
>>> X, Y = np.meshgrid(X, Y)
>>> R = np.sqrt(X**2 + Y**2)
>>> Z = np.sin(R)

>>> ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='viridis')
../_images/matplotlib3.png

要了解有关 Matplotlib 及其功能的更多信息,请查看 官方文档。有关安装 Matplotlib 的说明,请参阅官方 安装部分


图片来源:Jay Alammar http://jalammar.github.io/