geekdoc-python-zh/docs/realpython/how-to-use-numpy-arange.md

23 KiB
Raw Permalink Blame History

NumPy arange():如何使用 np.arange()

原文:https://realpython.com/how-to-use-numpy-arange/

*立即观看**本教程有真实 Python 团队创建的相关视频课程。配合文字教程一起看,加深理解: 有效使用 NumPy 的 NP . arange()

NumPy 是数值计算的基本 Python 库。它最重要的类型是一个叫做ndarray数组类型。NumPy 为不同的环境提供了许多数组创建例程arange()是一个基于数值范围的函数。它通常被称为np.arange(),因为np是 NumPy 的一个广泛使用的缩写。

当您使用依赖 NumPy 数组的其他 Python 库时,创建 NumPy 数组是很重要的,比如 SciPyPandasMatplotlib 、scikit-learn 等等。NumPy 适合创建和使用数组,因为它提供了有用的例程,使的性能提升,并允许您编写简洁的代码

到本文结束时,你会知道:

  • 什么是np.arange()
  • 如何使用np.arange()
  • np.arange()与 Python 内置类 range 相比如何
  • 哪些套路和np.arange()类似

让我们看看np.arange()的行动吧!

免费奖励: 点击此处获取免费的 NumPy 资源指南,它会为您指出提高 NumPy 技能的最佳教程、视频和书籍。

np.arange()的返回值和参数

NumPy arange()是一个基于数值范围的数组创建例程。它创建一个具有等间距值ndarray实例,并返回对它的引用。

您可以使用四个参数arange()定义数组中包含的值的间隔、它们之间的空间以及它们的类型:

numpy.arange([start, ]stop, [step, ], dtype=None) -> numpy.ndarray

前三个参数确定值的范围,而第四个参数指定元素的类型:

  1. start 是定义数组中第一个值的数字(整数或小数)。
  2. stop 是定义数组结尾的数字,不包含在数组中。
  3. step 是定义数组中每两个连续值之间的间距(差)的数字,默认为1
  4. dtype 是输出数组的元素类型,默认为 None

step不能为零。否则你会得到一个ZeroDivisionError。如果增量或减量是0,你就不能离开start的任何地方。

如果省略dtypearange()将尝试从startstopstep的类型中推导出数组元素的类型。

你可以在官方文档中找到更多关于arange()的参数和返回值的信息。

Remove ads

np.arange()的范围参数

定义数组中包含的值的 NumPy arange()的自变量对应于数字参数startstopstep。你必须通过至少其中一门

下面的例子将向您展示arange()如何根据参数的数量和它们的值进行操作。

提供所有范围参数

使用 NumPy 例程时,必须先导入 NumPy:

>>> import numpy as np

现在,您已经导入了 NumPy并准备应用arange()

让我们看看如何使用 NumPy arange()的第一个例子:

>>> np.arange(start=1, stop=10, step=3)
array([1, 4, 7])

在这个例子中,start就是1。因此,获得的数组的第一个元素是1step3,这就是为什么你的第二个值是 1+3也就是4,而数组中的第三个值是 4+3等于7

按照这种模式,下一个值将是10 (7+3),但是计数必须在到达 stop之前结束*,所以这个不包括在内。*

您也可以将startstopstep作为位置参数传递:

>>> np.arange(1, 10, 3)
array([1, 4, 7])

此代码示例等效于,但比前一个更简洁。

stop的值不包含在数组中。这就是为什么您可以用不同的stop值获得相同的结果:

>>> np.arange(1, 8, 3)
array([1, 4, 7])

此代码示例返回与前两个值相同的数组。任何一个stop值严格大于7小于等于10都可以得到相同的结果。

但是,如果您使stop大于10,那么计数将在达到10后结束:

>>> np.arange(1, 10.1, 3)
array([ 1.,  4.,  7., 10.])

在这种情况下,您将获得包含四个元素的数组,其中包括10

请注意,这个示例创建了一个浮点数数组,这与上一个示例不同。那是因为你还没有定义dtype,是arange()给你推导出来的。在本文的后面,您将了解到更多这方面的内容。

您可以在下图中看到这三个示例的图形表示:

NumPy arange() in action

start显示为绿色,stop显示为红色,而step和数组中包含的值显示为蓝色。

从上图可以看出,前两个例子有三个值(147)。他们不允许10被包括在内。在第三个例子中,stop大于10,它包含在结果数组中。

Remove ads

提供两个范围参数

可以省略step。在这种情况下,arange()使用其默认值1。以下两个语句是等效的:

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

第二个语句更短。step,默认为1,通常是直觉预期的。

arange()与增量1一起使用在实践中是非常常见的情况。同样,您可以用位置参数startstop更简洁地编写前面的例子:

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

这是调用arange()的一种直观而简洁的方式。在这个例子中使用关键字参数并没有真正提高可读性。

**注意:**如果你提供两个位置参数,那么第一个是start,第二个是stop

提供一个范围参数

你必须给提供至少一个arange()的参数。更准确的说,你得提供start

但是如果省略stop会怎么样呢?arange()怎么知道什么时候停止计数?在这种情况下,数组从0开始,在到达start的值之前结束!同样,step的默认值是1

换句话说,arange()假设你已经提供了stop(而不是start),并且start0step1

让我们看一个例子,你想用0开始一个数组,增加1的值,并在10之前停止:

>>> np.arange(start=0, stop=10, step=1)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(0, 10, 1)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(start=0, stop=10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(0, 10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

这些代码示例没问题。它们的工作方式如前面的示例所示。有一种更短、更简洁但仍然直观的方法来做同样的事情。您可以只提供一个位置参数:

>>> np.arange(10)  # Stop is 10, start is 0, and step is 1!
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

这是创建 NumPy 数组的最常用方法,该数组从零开始,增量为 1。

**注意:**单个参数定义了计数停止的位置。输出数组从0开始,增量为1

如果你试图显式地提供没有startstop,那么你将得到一个TypeError:

>>> np.arange(stop=10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: arange() missing required argument 'start' (pos 1)

你得到这个错误是因为arange()不允许你显式避开对应于start的第一个参数。如果你提供一个参数,那么它必须是start,但是arange()将使用它来定义计数停止的位置。

Remove ads

提供否定的论据

如果您为startstartstop都提供负值,并且有一个正的step,那么arange()将以与所有正参数相同的方式工作:

>>> np.arange(-5, -1)
array([-5, -4, -3, -2])
>>> np.arange(-8, -2, 2)
array([-8, -6, -4])
>>> np.arange(-5, 6, 4)
array([-5, -1,  3])

这种行为与前面的例子完全一致。计数从start的值开始,重复递增step,并在达到stop之前结束。

倒数计时

有时你会希望数组的值从左到右递减。在这种情况下,您可以使用负值的step和大于stopstart:

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

在这个例子中,请注意下面的模式:获得的数组从第一个参数的值开始,并朝着第二个参数的值递减step

在最后一个语句中,start7,得到的数组以这个值开始。step-3所以第二个值是 7+(3),也就是4。第三个值是 4+(3),即1。计数在此停止,因为在下一个值(-2)之前到达了stop ( 0)。

您可以在下图中看到此示例的图形表示:

NumPy arange() in action

同样,start显示为绿色,stop显示为红色,而step和数组中包含的值显示为蓝色。

这一次,箭头显示的是从右向左的方向。那是因为start大于stopstep是负数,你基本上是在倒着算。

前面的示例产生了与下面相同的结果:

>>> np.arange(1, 8, 3)[::-1]
array([7, 4, 1])
>>> np.flip(np.arange(1, 8, 3))
array([7, 4, 1])

不过,step为负值的变体更优雅简洁。

获取空数组

在一些极端情况下,您可以使用arange()获得空的 NumPy 数组。这些是没有任何元素的常规实例。

如果您为startstop提供相等的值,那么您将得到一个空数组:

>>> np.arange(2, 2)
array([], dtype=int64)

这是因为计数在达到stop的值之前就结束了。因为start的值等于stop,所以不能到达它,也不能包含在结果数组中。

一种不常见的情况是当start大于stop并且step为正时,或者当start小于stop并且step为负时:

>>> np.arange(8, 2, 1)
array([], dtype=int64)
>>> np.arange(2, 8, -1)
array([], dtype=int64)

正如你所看到的,这些例子导致空数组,而不是出现错误。

Remove ads

np.arange()的数据类型

NumPy 数组中元素的类型是使用它们的一个重要方面。使用arange()时,可以用参数dtype指定元素的类型。

**注意:**下面是关于 NumPy 数组中包含的元素类型的几个要点:

  • NumPy 数组中的所有元素都属于同一类型,称为dtype(数据类型的简称)。
  • NumPy dtypes 比 Python 的内置数字类型允许更细的粒度。
  • 在某些情况下NumPy dtypes 的别名对应于 Python 内置类型的名称。
  • 通常NumPy 例程可以接受 Python 数字类型,反之亦然。
  • 一些 NumPy 数据类型具有依赖于平台的定义。

如果你想了解更多关于 NumPy 数组的 dtypes那么请阅读官方文档。

你可以随意省略dtype。在这种情况下,arange()将尝试推导出结果数组的 dtype。这取决于startstopstep的类型,如下例所示:

>>> x = np.arange(5)
>>> x
array([0, 1, 2, 3, 4])
>>> x.dtype
dtype('int64')
>>> x.itemsize  # In bytes
8

这里,有一个参数(5)定义了值的范围。它的类型是int。这就是为什么数组x的 dtype 会是 NumPy 提供的整数类型之一。在这种情况下NumPy 默认选择int64 dtype。这是一个 64 位(8 字节)整数类型。

上一个示例中的数组相当于这个数组:

>>> x = np.arange(5, dtype=int)
>>> x
array([0, 1, 2, 3, 4])
>>> x.dtype
dtype('int64')

dtype=int 的说法不是指 Python int。它被翻译成 NumPy int64或简单的np.int

NumPy 提供了几种固定大小的整数数据类型,它们在内存和限制方面有所不同:

  • np.int8 : 8 位有符号整数(从-128127
  • np.uint8 : 8 位无符号整数(从0255
  • np.int16 : 16 位有符号整数(从-3276832767
  • np.uint16 : 16 位无符号整数(从065535
  • np.int32 : 32 位有符号整数(从-2**312**31-1
  • np.uint32 : 32 位无符号整数(从02**32-1
  • np.int64 : 64 位有符号整数(从-2**632**63-1
  • np.uint64 : 64 位无符号整数(从02**64-1

如果您希望数组的元素使用其他整数类型,那么只需指定dtype:

>>> x = np.arange(5, dtype=np.int32)
>>> x
array([0, 1, 2, 3, 4], dtype=int32)
>>> x.dtype
dtype('int32')
>>> x.itemsize  # In bytes
4

现在得到的数组具有与前一个例子相同的值,但是元素的类型和大小不同。参数dtype=np.int32(或dtype='int32')强制x的每个元素的大小为 32 位(4 字节)。

当您的参数是十进制数而不是整数时dtype 将是某种 NumPy 浮点类型,在本例中为float64:

>>> y = np.arange(5.0)
>>> y
array([0., 1., 2., 3., 4.])
>>> y.dtype
dtype('float64')

在最后四个例子中,元素的值是相同的,但是数据类型不同。

通常,当您向arange()提供至少一个浮点参数时,得到的数组将具有浮点元素,即使其他参数是整数:

>>> np.arange(1, 5.1)
array([1., 2., 3., 4., 5.])
>>> np.arange(1, 5.1).dtype
dtype('float64')
>>> np.arange(0, 9, 1.5)
array([0\. , 1.5, 3\. , 4.5, 6\. , 7.5])
>>> np.arange(0, 9, 1.5).dtype
dtype('float64')

在上面的例子中,start是一个整数,但是 dtype 是np.float64,因为stopstep是浮点数。

如果您指定了dtype,那么arange()将尝试使用所提供的数据类型的元素生成一个数组:

>>> y = np.arange(5, dtype=float)
>>> y
array([0., 1., 2., 3., 4.])
>>> y.dtype
dtype('float64')

这里的参数dtype=float翻译成 NumPy float64,也就是np.float。它不是指 Python floatfloat64的固定大小别名是np.float64np.float_

当需要精度和大小(以字节为单位)较低的浮点数据类型时,可以显式指定:

>>> z = np.arange(5, dtype=np.float32)
>>> z
array([0., 1., 2., 3., 4.], dtype=float32)
>>> z.dtype
dtype('float32')

使用dtype=np.float32(或dtype='float32')使数组z的每个元素变大 32 位(4 字节)。y每个元素的大小为 64 位(8 字节):

>>> y.itemsize  # In bytes
8
>>> z.itemsize  # In bytes
4

yz的元素之间的区别,以及一般而言np.float64np.float32之间的区别,是所使用的内存和精度:前者比后者更大、更精确。

很多情况下,你不会注意到这种区别。然而,有时这很重要。比如 TensorFlow 使用 float32int32 。同样,当你处理图像时,甚至使用较小的字体,如uint8

step不是整数时,由于浮点运算的限制,结果可能不一致。

Remove ads

np.arange()超越简单范围

您可以方便地将arange()与运算符(如+-*/**等)和其他 NumPy 例程(如abs()sin())组合起来,产生输出值的范围:

>>> x = np.arange(5)
>>> x
array([0, 1, 2, 3, 4])
>>> 2**x
array([ 1,  2,  4,  8, 16])
>>> y = np.arange(-1, 1.1, 0.5)
>>> y
array([-1\. , -0.5,  0\. ,  0.5,  1\. ])
>>> np.abs(y)
array([1\. , 0.5, 0\. , 0.5, 1\. ])
>>> z = np.arange(10)
>>> np.sin(z)
array([ 0\.        ,  0.84147098,  0.90929743,  0.14112001, -0.7568025 ,
 -0.95892427, -0.2794155 ,  0.6569866 ,  0.98935825,  0.41211849])

当你想在 Matplotlib 中创建一个绘图时,这是特别合适的。

如果你需要一个多维数组,那么你可以结合arange().reshape() 或者类似的函数和方法:

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

这就是如何获得包含元素[0, 1, 2, 3, 4, 5]ndarray实例,并将其整形为二维数组。

rangenp.arange()的比较

Python 有一个内置的类range,某种程度上类似于 NumPy arange()rangenp.arange()在应用和性能方面有重要区别。你会看到他们的不同和相似之处。

两者的主要区别在于range是内置的 Python 类,而arange()是属于第三方库(NumPy)的函数。

另外,他们的目的不一样!一般来说,当你需要使用 Python for循环迭代时,range更合适。如果你想创建一个 NumPy 数组,并在幕后应用快速循环,那么arange()是一个更好的解决方案。

参数和输出

rangearange()具有相同的参数,这些参数定义了所获得数字的范围:

  • start
  • stop
  • step

即使在startstop相等的情况下,您也可以类似地应用这些参数。

然而,在使用range时:

  • 您必须提供整数参数。否则,你会得到一个TypeError
  • 您不能指定生成的数字的类型。总是int

rangearange()的返回类型也不同:

  • range 创建该类的一个实例,该实例具有与其他序列(如 listtuple )相同的特性,如成员、连接、重复、切片、比较、长度检查等等。
  • arange() 返回 NumPy ndarray的一个实例。

创建序列

您可以应用range来创建一个listtuple的实例,在预定义的范围内均匀分布数字。你可能会发现理解特别适合这个目的。

然而,创建和操作 NumPy 数组通常比处理列表或元组更快,更 T2更优雅。

让我们比较一下使用理解力创建一个list和使用arange()创建一个等价的 NumPy ndarray的性能:

>>> import timeit
>>> n = 1
>>> timeit.timeit(f'x = [i**2 for i in range({n})]')
>>> timeit.timeit(f'x = np.arange({n})**2', setup='import numpy as np')

对不同的n值重复这段代码,在我的机器上产生了以下结果:

尺寸:n 每循环时间:range 每循环时间:arange() 比例
one 497 纳秒 1.14 秒 Zero point four one
Ten 2.24 秒 1.28 秒 One point seven four
One hundred 20.0 秒 1.37 秒 Fourteen point six
One thousand 211 s 2.92 秒 Seventy-two point three

这些结果可能会有所不同,但是很明显,创建 NumPy 数组比创建 list 要快得多,除了长度非常短的序列。(应用程序通常会带来额外的性能优势!)

这是因为 NumPy 在 C 层执行许多操作包括循环。此外NumPy 为处理向量进行了优化,避免了一些与 Python 相关的开销。

Remove ads

Python for循环

如果您需要在 Python for循环中迭代值,那么range通常是更好的解决方案。根据官方 Python 文档:

与常规的listtuple相比,range类型的优势在于,range对象将总是占用相同(少量)的内存,无论它所代表的范围大小如何(因为它只存储根据需要计算单个项目和子范围的startstopstep值)。(来源)

在 Python 的for循环中使用时,range通常比arange()快,尤其是当循环有可能很快中断的时候。这是因为range在需要的时候以惰性方式生成数字,一次一个。

相比之下,arange()在开头生成所有的数字。

更多关于range的信息,可以查看Python range()函数(指南)官方文档

基于数值范围的其他程序

除了arange()之外,您还可以应用其他基于数值范围的 NumPy 数组创建例程:

  • linspace()arange()相似,都是返回等间距的数字。但是您可以指定要生成的值的数量,以及是否包括端点和是否一次创建多个数组。
  • logspace()geomspace()linspace()类似,只是返回的数字在对数刻度上是均匀分布的。
  • meshgrid() ogrid() mgrid() 返回以数组表示的网格点。

所有这些功能都有自己的特点和使用案例。可以根据自己的需求选择合适的。

正如您已经看到的NumPy 包含了更多的例程来创建ndarray 的实例。

快速总结

要使用 NumPy arange(),需要先导入numpy:

>>> import numpy as np

这里有一个表格,其中有几个例子总结了如何使用 NumPy arange()。记住各种用法可能会有帮助:

例子 结果
np.arange(start=1, stop=10, step=3) array([1, 4, 7])
np.arange(1, 10, 3) array([1, 4, 7])
np.arange(1, 10, 3, dtype=float) array([1., 4., 7.])
np.arange(1.0, 10, 3) array([1., 4., 7.])
np.arange(0, 1.1, 0.5) array([0\. , 0.5, 1\. ])
np.arange(2, 6) array([2, 3, 4, 5])
np.arange(5) array([0, 1, 2, 3, 4])
np.arange(-8, -2, 2) array([-8, -6, -4])
np.arange(7, 0, -3) array([7, 4, 1])
np.arange(8, 2) array([])

不要忘记,您还可以通过用参数dtype指定 NumPy dtypes 来影响用于数组的内存。

结论

你现在知道如何使用 NumPy arange()。函数np.arange()是基本的 NumPy 例程之一,通常用于创建 NumPy ndarray的实例。它有四个论点:

  1. start : 数组的第一个值
  2. stop : 数组结束的地方
  3. step : 增量或减量
  4. dtype : 数组的元素的类型

您还了解了在创建序列和生成要迭代的值时NumPy arange()与 Python 内置类range的比较。

您看到了还有其他基于数值范围的 NumPy 数组创建例程,比如linspace()logspace()meshgrid()等等。

如果你有任何问题或意见,请写在下面的评论区。

立即观看本教程有真实 Python 团队创建的相关视频课程。配合文字教程一起看,加深理解: 有效使用 NumPy 的 NP . arange()*****