目录
NumPy ndarray:多维数组对象
NumPy 的主要功能之一是它的 N 维数组对象或 ndarray,它是 Python 中大型数据集的快速、灵活的容器。数组使您能够使用与标量元素之间的等效运算类似的语法对整个数据块执行数学运算。
为了让您了解 NumPy 如何启用与内置 Python 对象上的标量值语法相似的批处理计算,我首先导入 NumPy 并创建一个小型数组:
In [12]: import numpy as np
In [13]: data = np.array([[1.5, -0.1, 3], [0, -3, 6.5]])
In [14]: data
Out[14]:
array([[ 1.5, -0.1, 3. ],
[ 0. , -3. , 6.5]])
然后我用以下语言编写数学运算:data
In [15]: data * 10
Out[15]:
array([[ 15., -1., 30.],
[ 0., -30., 65.]])
In [16]: data + data
Out[16]:
array([[ 3. , -0.2, 6. ],
[ 0. , -6. , 13. ]])
在第一个示例中,所有元素都乘以 10。在第二种情况下,数组中每个“单元格”中的相应值已相互相加。
ndarray 是用于同构数据的通用多维容器;也就是说,所有元素必须是相同的类型。每个数组都有一个 ,一个表示每个维度大小的元组,以及一个描述数组数据类型的对象:shape dtype
In [17]: data.shape
Out[17]: (2, 3)
In [18]: data.dtype
Out[18]: dtype('float64')
创建 ndarrays
创建数组的最简单方法是使用该函数。这接受任何类似序列的对象(包括其他数组),并生成包含传递数据的新 NumPy 数组。
In [19]: data1 = [6, 7.5, 8, 0, 1]
In [20]: arr1 = np.array(data1)
In [21]: arr1
Out[21]: array([6. , 7.5, 8. , 0. , 1. ])
嵌套序列,如等长列表列表,将被转换为多维数组:
In [22]: data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
In [23]: arr2 = np.array(data2)
In [24]: arr2
Out[24]:
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
由于是列表,因此 NumPy 数组具有两个维度,从数据推断出形状。我们可以通过检查属性来确认这一点:data2 arr2 ndim shape
In [25]: arr2.ndim
Out[25]: 2
In [26]: arr2.shape
Out[26]: (2, 4)
除非显式指定,否则会尝试为其创建的数组推断出良好的数据类型。数据类型存储在特殊的元数据对象中;例如,在前两个示例中,我们有:numpy.array dtype
In [27]: arr1.dtype
Out[27]: dtype('float64')
In [28]: arr2.dtype
Out[28]: dtype('int64')
除此之外,还有许多其他函数用于创建新数组。例如,分别创建具有给定长度或形状的 0 或 1 数组。 创建一个数组,而不将其值初始化为任何特定值。若要使用这些方法创建更高维数组,请传递具有形状的元组:numpy.array numpy.zeros numpy.ones numpy.empty
In [29]: np.zeros(10)
Out[29]: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [30]: np.zeros((3, 6))
Out[30]:
array([[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.]])
In [31]: np.empty((2, 3, 2))
Out[31]:
array([[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]]])
假设这将返回一个包含所有零的数组是不安全的。此函数返回未初始化的内存,因此可能包含非零的“垃圾”值。仅当您打算用数据填充新数组时,才应使用此函数。numpy.empty
numpy.arange是内置 Python 函数: range的数组值版本
In [32]: np.arange(15)
Out[32]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
由于 NumPy 专注于数值计算,因此如果未指定数据类型,则在许多情况下将为(浮点数)float64
函数 | 描述 |
---|---|
array | 通过推断数据类型或显式指定数据类型,将输入数据(列表、元组、数组或其他序列类型)转换为 ndarray;默认情况下复制输入数据 |
asarray | 将输入转换为 ndarray,但如果输入已经是 ndarray,则不要复制 |
arange | 像内置的一样,但返回一个 ndarray 而不是一个列表 range |
ones, ones_like | 生成一个包含所有 1 的数组,具有给定的形状和数据类型; 获取另一个数组并生成相同形状和数据类型的数组 ones_like ones |
zeros, zeros_like | 像ones, ones_like函数一样,但生成值是0的数组 |
empty, empty_like | 通过分配新内存创建新数组,但不要填充任何值,如 ones zeros |
full, full_like | 生成给定形状和数据类型的数组,所有值都设置为指示的“填充值”; 获取另一个数组并生成相同形状和数据类型的填充数组full_like |
eye, identity | 创建一个正方形 N × N 单位矩阵(对角线上为 1,其他地方为 0 |
ndarrays 的数据类型
数据类型 or 是一个特殊对象,其中包含 ndarray 将内存块解释为特定类型的数据所需的信息(或元数据、有关数据的数据):dtype
In [33]: arr1 = np.array([1, 2, 3], dtype=np.float64)
In [34]: arr2 = np.array([1, 2, 3], dtype=np.int32)
In [35]: arr1.dtype
Out[35]: dtype('float64')
In [36]: arr2.dtype
Out[36]: dtype('int32')
数据类型是NumPy与来自其他系统的数据交互的灵活性的来源。在大多数情况下,它们直接提供到底层磁盘或内存表示的映射,从而可以在磁盘上读取和写入二进制数据流,并连接到用C或FORTRAN等低级语言编写的代码。数字数据类型的命名方式相同:类型名,如或,后跟表示每个元素位数的数字。一个标准的双精度浮点值(Python对象中隐藏使用的值)占用8个字节或64位。因此,这种类型在NumPy中被广泛所知。
类型 | 类型代码 | 描述 |
---|---|---|
int8, uint8 | i1, u1 | 有符号和无符号 8 位(1 字节)整数类型 |
int16, uint16 | i2, u2 | 有符号和无符号 16 位整数类型 |
int32, uint32 | i4, u4 | 有符号和无符号的 32 位整数类型 |
int64, uint64 | i8, u8 | 有符号和无符号 64 位整数类型 |
float16 | f2 | 半精度浮点 |
float32 | f4 or f | 标准单精度浮点数;兼容 C 浮点数 |
float64 | f8 or d | 标准双精度浮点;兼容 C double 和 Python 对象float |
float128 | f16 or g | 扩展精度浮点 |
complex64, complex128, complex256 | c8, c16, c32 | 分别由两个 32、64 或 128 浮点数表示的复数 |
bool | ? | 布尔类型存储和值True False |
object | O | Python 对象类型;值可以是任何 Python 对象 |
string_ | S | 固定长度的 ASCII 字符串类型(每个字符 1 个字节);例如,若要创建长度为 10 的字符串数据类型,请使用‘S10’ |
unicode_ | U | 固定长度的 Unicode 类型(特定于平台的字节数);与(例如,string_‘U10’) |
有符号整数可以表示正整数和负整数,而无符号整数只能表示非零整数。例如,(有符号的 8 位整数)可以表示从 -128 到 127(含)的整数,而(无符号的 8 位整数)可以表示 0 到 255。int8 uint8
使用 ndarray 的方法将数组从一种数据类型显式转换或强制转换为另一种数据类型:astype
In [37]: arr = np.array([1, 2, 3, 4, 5])
In [38]: arr.dtype
Out[38]: dtype('int64')
In [39]: float_arr = arr.astype(np.float64)
In [40]: float_arr
Out[40]: array([1., 2., 3., 4., 5.])
In [41]: float_arr.dtype
Out[41]: dtype('float64')
在此示例中,整数被强制转换为浮点数。如果我将一些浮点数转换为整数数据类型,则小数部分将被截断:
In [42]: arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
In [43]: arr
Out[43]: array([ 3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
In [44]: arr.astype(np.int32)
Out[44]: array([ 3, -1, -2, 0, 12, 10], dtype=int32)
如果有一个表示数字的字符串数组,则可以使用它们转换为数字形式:astype
In [45]: numeric_strings = np.array(["1.25", "-9.6", "42"], dtype=np.string_)
In [46]: numeric_strings.astype(float)
Out[46]: array([ 1.25, -9.6 , 42. ])
NumPy 中的字符串数据是固定大小的,可能会在没有警告的情况下截断输入。Pandas在非数字数据上具有更直观的开箱即用行为。numpy.string_
由于某种原因(如无法转换为的字符串)可能导致强制转换失败,NumPy将Python类型别名为自己的等效数据类型。float64 ValueError float np.float64
您还可以使用另一个数组的属性:dtype
In [47]: int_array = np.arange(10)
In [48]: calibers = np.array([.22, .270, .357, .380, .44, .50], dtype=np.float64)
In [49]: int_array.astype(calibers.dtype)
Out[49]: array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
还有一些速记类型的代码字符串,你也可以用它来指代一个:dtype
In [50]: zeros_uint32 = np.zeros(8, dtype="u4")
In [51]: zeros_uint32
Out[51]: array([0, 0, 0, 0, 0, 0, 0, 0], dtype=uint32)
调用始终会创建一个新数组(数据的副本),即使新数据类型与旧数据类型相同也是如此。astype
使用 NumPy 数组进行运算
数组能够在不写入任何循环的情况下对数据进行批处理操作,称之为矢量化。等大小数组之间的任何算术运算都按元素应用运算:for
In [52]: arr = np.array([[1., 2., 3.], [4., 5., 6.]])
In [53]: arr
Out[53]:
array([[1., 2., 3.],
[4., 5., 6.]])
In [54]: arr * arr
Out[54]:
array([[ 1., 4., 9.],
[16., 25., 36.]])
In [55]: arr - arr
Out[55]:
array([[0., 0., 0.],
[0., 0., 0.]])
使用标量的算术运算将标量参数传播到数组中的每个元素:
In [56]: 1 / arr
Out[56]:
array([[1. , 0.5 , 0.3333],
[0.25 , 0.2 , 0.1667]])
In [57]: arr ** 2
Out[57]:
array([[ 1., 4., 9.],
[16., 25., 36.]])
相同大小的数组之间的比较产生布尔数组:
In [58]: arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
In [59]: arr2
Out[59]:
array([[ 0., 4., 1.],
[ 7., 2., 12.]])
In [60]: arr2 > arr
Out[60]:
array([[False, True, False],
[ True, False, True]])
评估不同大小的数组之间的操作称为broadcasting,更多细节见高级NumPy。
基本索引和切片
NumPy 数组索引可以通过多种方式选择数据的子集或单个元素。一维数组很简单;从表面上看,它们的行为类似于 Python 列表:
In [61]: arr = np.arange(10)
In [62]: arr
Out[62]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [63]: arr[5]
Out[63]: 5
In [64]: arr[5:8]
Out[64]: array([5, 6, 7])
In [65]: arr[5:8] = 12
In [66]: arr
Out[66]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
如果将标量值分配给切片,则该值将传播、应用到整个选择 arr[5:8] = 12
与 Python 内置列表的第一个重要区别是数组切片是原始数组上的视图。这意味着不会复制数据,并且对视图的任何修改都将反映在源数组中。
举个例子,首先创建一个切片:arr
In [67]: arr_slice = arr[5:8]
In [68]: arr_slice
Out[68]: array([12, 12, 12])
现在,当更改 arr_slice中的值时,突变会反映在原始数组中:arr_slice arr
In [69]: arr_slice[1] = 12345
In [70]: arr
Out[70]:
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,
9])
“裸”切片将分配给数组中的所有值:[:]
In [71]: arr_slice[:] = 64
In [72]: arr
Out[72]: array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
使用更高维的数组,有更多的选择。在二维数组中,每个索引处的元素不再是标量,而是一维数组:
In [73]: arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
In [74]: arr2d[2]
Out[74]: array([7, 8, 9])
因此,可以递归访问单个元素。但这有点太多了,所以你可以传递一个逗号分隔的索引列表来选择单个元素。所以这些是等价的:
In [75]: arr2d[0][2]
Out[75]: 3
In [76]: arr2d[0, 2]
Out[76]: 3
有关二维数组索引的图示,将轴 0 视为数组的“行”,将轴 1 视为“列”。
在多维数组中,如果省略后面的索引,则返回的对象将是一个低维 ndarray,由沿高维的所有数据组成。所以在 2 × 2 × 3 数组中:arr3d
In [77]: arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
In [78]: arr3d
Out[78]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[0]c是一个 2 × 3 数组:
In [79]: arr3d[0]
Out[79]:
array([[1, 2, 3],
[4, 5, 6]])
标量值和数组都可以分配给:arr3d[0]
In [80]: old_values = arr3d[0].copy()
In [81]: arr3d[0] = 42
In [82]: arr3d
Out[82]:
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [83]: arr3d[0] = old_values
In [84]: arr3d
Out[84]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
类似地,为您提供索引以 开头的所有值,形成一个一维数组:arr3d [1, 0] (1, 0)
In [85]: arr3d[1, 0]
Out[85]: array([7, 8, 9])
此表达式与我们分两步编制索引的表达式相同:
In [86]: x = arr3d[1]
In [87]: x
Out[87]:
array([[ 7, 8, 9],
[10, 11, 12]])
In [88]: x[0]
Out[88]: array([7, 8, 9])
请注意,在所有这些情况下,如果选择了数组的子部分,则返回的数组都是视图。
NumPy 数组的这种多维索引语法不适用于常规 Python 对象,例如列表
使用切片编制索引
与一维对象(如 Python 列表)一样,ndarrays 可以使用熟悉的语法进行切片:
In [89]: arr
Out[89]: array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
In [90]: arr[1:6]
Out[90]: array([ 1, 2, 3, 4, 64])
考虑前面的二维数组。对这个数组进行切片有点不同:arr2d
In [91]: arr2d
Out[91]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
In [92]: arr2d[:2]
Out[92]:
array([[1, 2, 3],
[4, 5, 6]])
如您所见,它已沿轴 0(第一个轴)切片。因此,切片沿轴选择一系列元素。将表达式读作“选择的前两行”。arr2d[:2] arr2d
您可以传递多个切片,就像您可以传递多个索引一样:
In [93]: arr2d[:2, 1:]
Out[93]:
array([[2, 3],
[5, 6]])
像这样切片时,您始终会获得相同维度数的数组视图。通过混合整数索引和切片,可以得到低维切片。
例如,我可以选择第二行,但只能选择前两列,如下所示:
In [94]: lower_dim_slice = arr2d[1, :2]
这里,虽然是二维的,但也是一维的,它的形状是一个轴大小为一个元组:arr2d lower_dim_slice
In [95]: lower_dim_slice.shape
Out[95]: (2,)
同样,我可以选择第三列,但只能选择前两行,如下所示:
In [96]: arr2d[:2, 2]
Out[96]: array([3, 6])
冒号本身意味着采用整个轴,因此您可以通过以下操作仅对更高维的轴进行切片:
In [97]: arr2d[:, :1]
Out[97]:
array([[1],
[4],
[7]])
当然,赋值给切片表达式会赋值给整个选择:
In [98]: arr2d[:2, 1:] = 0
In [99]: arr2d
Out[99]:
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
布尔索引
让我们考虑一个例子,在这个例子中,我们在一个数组和一个具有重复项的名称数组中有一些数据:
In [100]: names = np.array(["Bob", "Joe", "Will", "Bob", "Will", "Joe", "Joe"])
In [101]: data = np.array([[4, 7], [0, 2], [-5, 6], [0, 0], [1, 2],
.....: [-12, -4], [3, 4]])
In [102]: names
Out[102]: array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')
In [103]: data
Out[103]:
array([[ 4, 7],
[ 0, 2],
[ -5, 6],
[ 0, 0],
[ 1, 2],
[-12, -4],
[ 3, 4]])
假设每个名称对应于数组中的一行,并且我们希望选择具有相应名称的所有行。与算术运算一样,与数组的比较(如)也被矢量化。因此,与字符串进行比较会产生一个布尔数组:data"Bob"==names"Bob"
In [104]: names == "Bob"
Out[104]: array([ True, False, False, True, False, False, False])
索引数组时可以传递此布尔数组:
In [105]: data[names == "Bob"]
Out[105]:
array([[4, 7],
[0, 0]])
布尔数组的长度必须与其索引的数组轴的长度相同。您甚至可以将布尔数组与切片或整数(或整数序列;稍后会详细介绍)混合匹配。
在这些示例中,我从其中的行中进行选择,并对列进行索引:names==“Bob”
In [106]: data[names == "Bob", 1:]
Out[106]:
array([[7],
[0]])
In [107]: data[names == "Bob", 1]
Out[107]: array([7, 0])
要选择所有内容,但您可以使用以下命令使用或否定条件:“Bob” != ~
In [108]: names != "Bob"
Out[108]: array([False, True, True, False, True, True, True])
In [109]: ~(names == "Bob")
Out[109]: array([False, True, True, False, True, True, True])
In [110]: data[~(names == "Bob")]
Out[110]:
array([[ 0, 2],
[ -5, 6],
[ 1, 2],
[-12, -4],
[ 3, 4]])
当您想要反转由变量引用的布尔数组时,运算符可能很有用:~
In [111]: cond = names == "Bob"
In [112]: data[~cond]
Out[112]:
array([[ 0, 2],
[ -5, 6],
[ 1, 2],
[-12, -4],
[ 3, 4]])
若要从三个名称中选择两个来组合多个布尔条件,请使用布尔算术运算符,如 (and) 和 (or):& |
In [113]: mask = (names == "Bob") | (names == "Will")
In [114]: mask
Out[114]: array([ True, False, True, True, True, False, False])
In [115]: data[mask]
Out[115]:
array([[ 4, 7],
[-5, 6],
[ 0, 0],
[ 1, 2]])
通过布尔索引从数组中选择数据并将结果分配给新变量始终会创建数据的副本,即使返回的数组未更改也是如此。
Python 关键字 和 不适用于布尔数组。请改用 (and) 和 (or)。and or & |
使用布尔数组设置值的工作原理是将右侧的一个或多个值代入布尔数组的值所在的位置。要将所有负值设置为 0,我们只需要执行以下操作:True data
In [116]: data[data < 0] = 0
In [117]: data
Out[117]:
array([[4, 7],
[0, 2],
[0, 6],
[0, 0],
[1, 2],
[0, 0],
[3, 4]])
您还可以使用一维布尔数组设置整行或整列:
In [118]: data[names != "Joe"] = 7
In [119]: data
Out[119]:
array([[7, 7],
[0, 2],
[7, 7],
[7, 7],
[7, 7],
[0, 0],
[3, 4]])
正如我们稍后将看到的,这些类型的二维数据操作对于pandas来说很方便。
花式索引
花式索引是 NumPy 采用的一个术语,用于描述使用整数数组的索引。假设我们有一个 8 × 4 数组:
In [120]: arr = np.zeros((8, 4))
In [121]: for i in range(8):
.....: arr[i] = i
In [122]: arr
Out[122]:
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
要按特定顺序选择行的子集,只需传递指定所需顺序的整数列表或 ndarray 即可:
In [123]: arr[[4, 3, 0, 6]]
Out[123]:
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
希望这段代码能达到你的预期!使用负索引从末尾选择行:
In [124]: arr[[-3, -5, -7]]
Out[124]:
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
传递多个索引数组会做一些稍微不同的事情;它选择对应于每个索引元组的一维元素数组:
In [125]: arr = np.arange(32).reshape((8, 4))
In [126]: arr
Out[126]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
In [127]: arr[[1, 5, 7, 2], [0, 3, 1, 2]]
Out[127]: array([ 4, 23, 29, 10])
这里选择了元素,并被选中。使用与轴一样多的整数数组进行花式索引的结果始终是一维的。(1, 0), (5, 3), (7, 1) (2, 2)
在这种情况下,花式索引的行为与某些用户的预期略有不同,后者是通过选择矩阵的行和列的子集形成的矩形区域。这是获得此目的的一种方法:
In [128]: arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
Out[128]:
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
请记住,与切片不同,花式索引在将结果分配给新变量时总是将数据复制到新数组中。如果使用花式索引来分配值,则将修改索引值:
In [129]: arr[[1, 5, 7, 2], [0, 3, 1, 2]]
Out[129]: array([ 4, 23, 29, 10])
In [130]: arr[[1, 5, 7, 2], [0, 3, 1, 2]] = 0
In [131]: arr
Out[131]:
array([[ 0, 1, 2, 3],
[ 0, 5, 6, 7],
[ 8, 9, 0, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 0],
[24, 25, 26, 27],
[28, 0, 30, 31]])
转置数组和交换轴
转置是一种特殊的重塑形式,它同样在不复制任何内容的情况下返回底层数据的视图。数组具有方法和特殊属性:transpose T
In [132]: arr = np.arange(15).reshape((3, 5))
In [133]: arr
Out[133]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In [134]: arr.T
Out[134]:
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
在进行矩阵计算时,您可能会经常这样做,例如,在使用以下方法计算内矩阵乘积时:numpy.dot
In [135]: arr = np.array([[0, 1, 0], [1, 2, -2], [6, 3, 2], [-1, 0, -1], [1, 0, 1
]])
In [136]: arr
Out[136]:
array([[ 0, 1, 0],
[ 1, 2, -2],
[ 6, 3, 2],
[-1, 0, -1],
[ 1, 0, 1]])
In [137]: np.dot(arr.T, arr)
Out[137]:
array([[39, 20, 12],
[20, 14, 2],
[12, 2, 10]])
中缀运算符是执行矩阵乘法的另一种方法:@
In [138]: arr.T @ arr
Out[138]:
array([[39, 20, 12],
[20, 14, 2],
[12, 2, 10]])
简单的转置是交换轴的特殊情况。 ndarray具有方法,该方法采用一对轴编号,并切换指示的轴以重新排列数据:.T swapaxes
In [139]: arr
Out[139]:
array([[ 0, 1, 0],
[ 1, 2, -2],
[ 6, 3, 2],
[-1, 0, -1],
[ 1, 0, 1]])
In [140]: arr.swapaxes(0, 1)
Out[140]:
array([[ 0, 1, 6, -1, 1],
[ 1, 2, 3, 0, 0],
[ 0, -2, 2, -1, 1]])
swapaxes同样,它返回数据视图,而不进行复制。
伪随机数生成
该模块补充了内置的 Python 模块,其中包含用于从多种概率分布中有效生成整个样本值数组的函数。例如,您可以使用以下方法从标准正态分布中获取 4 × 4 个样本数组:numpy.random random numpy.random.standard_normal
In [141]: samples = np.random.standard_normal(size=(4, 4))
In [142]: samples
Out[142]:
array([[-0.2047, 0.4789, -0.5194, -0.5557],
[ 1.9658, 1.3934, 0.0929, 0.2817],
[ 0.769 , 1.2464, 1.0072, -1.2962],
[ 0.275 , 0.2289, 1.3529, 0.8864]])
相比之下,Python 的内置模块一次只采样一个值。从这个基准测试中可以看出,对于生成非常大的样本来说,速度要快一个数量级以上:random numpy.randomc
In [143]: from random import normalvariate
In [144]: N = 1_000_000
In [145]: %timeit samples = [normalvariate(0, 1) for _ in range(N)]
490 ms +- 2.23 ms per loop (mean +- std. dev. of 7 runs, 1 loop each)
In [146]: %timeit np.random.standard_normal(N)
32.6 ms +- 271 us per loop (mean +- std. dev. of 7 runs, 10 loops each)
这些随机数不是真正的随机数(更确切地说是伪随机数),而是由可配置的随机数生成器生成的,该随机数生成器确定创建的值。函数,例如使用模块的默认随机数生成器,但可以将代码配置为使用显式生成器:numpy.random.standard_normal numpy.random
In [147]: rng = np.random.default_rng(seed=12345)
In [148]: data = rng.standard_normal((2, 3))
参数决定了生成器的初始状态,每次使用对象生成数据时,状态都会发生变化。生成器对象也与可能使用该模块的其他代码隔离:seed rng rng numpy.random
In [149]: type(rng)
Out[149]: numpy.random._generator.Generator
随机生成器对象上可用的部分方法列表
方法 | 描述 |
---|---|
permutation | 返回序列的随机排列,或返回排列范围 |
shuffle | 随机置换序列 |
uniform | 从均匀分布中抽取样本 |
integers | 从给定的从低到高范围绘制随机整数 |
standard_normal | 从均值为 0、标准差为 1 的正态分布中抽取样本 |
binomial | 从二项分布中抽取样本 |
normal | 从正态(高斯)分布中抽取样本 |
beta | 从 beta 分布中抽取样本 |
chisquare | 从卡方分布中抽取样本 |
gamma | 从 gamma 分布中抽取样本 |
uniform | 从均匀的 [ 0,1)分布中抽取样本 |
通用函数:快速的逐元素数组函数
通用函数 (ufunc) 是对 ndarray 中的数据执行元素级运算的函数。您可以将它们视为简单函数的快速矢量化包装器,这些函数采用一个或多个标量值并生成一个或多个标量结果。
许多 ufunc 都是简单的元素转换,例如 或:numpy.sqrt numpy.exp
In [150]: arr = np.arange(10)
In [151]: arr
Out[151]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [152]: np.sqrt(arr)
Out[152]:
array([0. , 1. , 1.4142, 1.7321, 2. , 2.2361, 2.4495, 2.6458,
2.8284, 3. ])
In [153]: np.exp(arr)
Out[153]:
array([ 1. , 2.7183, 7.3891, 20.0855, 54.5982, 148.4132,
403.4288, 1096.6332, 2980.958 , 8103.0839])
这些被称为一元 ufunc。其他的,如采用两个数组(因此是二进制 ufunc)并返回一个数组作为结果:numpy.add numpy.maximum
In [154]: x = rng.standard_normal(8)
In [155]: y = rng.standard_normal(8)
In [156]: x
Out[156]:
array([-1.3678, 0.6489, 0.3611, -1.9529, 2.3474, 0.9685, -0.7594,
0.9022])
In [157]: y
Out[157]:
array([-0.467 , -0.0607, 0.7888, -1.2567, 0.5759, 1.399 , 1.3223,
-0.2997])
In [158]: np.maximum(x, y)
Out[158]:
array([-0.467 , 0.6489, 0.7888, -1.2567, 2.3474, 1.399 , 1.3223,
0.9022])
在本例中,计算了 .numpy.maximum x y 中元素的元素最大值
虽然不常见,但一个 ufunc 可以返回多个数组。一个例子:内置Python的矢量化版本,它返回浮点数组的小数和整数部分:numpy.modf math.modf
In [159]: arr = rng.standard_normal(7) * 5
In [160]: arr
Out[160]: array([ 4.5146, -8.1079, -0.7909, 2.2474, -6.718 , -0.4084, 8.6237])
In [161]: remainder, whole_part = np.modf(arr)
In [162]: remainder
Out[162]: array([ 0.5146, -0.1079, -0.7909, 0.2474, -0.718 , -0.4084, 0.6237])
In [163]: whole_part
Out[163]: array([ 4., -8., -0., 2., -6., -0., 8.])
Ufuncs 接受一个可选参数,该参数允许它们将结果分配到现有数组中,而不是创建一个新数组:out
In [164]: arr
Out[164]: array([ 4.5146, -8.1079, -0.7909, 2.2474, -6.718 , -0.4084, 8.6237])
In [165]: out = np.zeros_like(arr)
In [166]: np.add(arr, 1)
Out[166]: array([ 5.5146, -7.1079, 0.2091, 3.2474, -5.718 , 0.5916, 9.6237])
In [167]: np.add(arr, 1, out=out)
Out[167]: array([ 5.5146, -7.1079, 0.2091, 3.2474, -5.718 , 0.5916, 9.6237])
In [168]: out
Out[168]: array([ 5.5146, -7.1079, 0.2091, 3.2474, -5.718 , 0.5916, 9.6237])
方法 | 描述 |
---|---|
abs, fabs | 按元素计算整数、浮点值或复数值的绝对值 |
sqrt | 计算每个元素的平方根(等于arr ** 0.5) |
square | 计算每个元素的平方(相当于arr ** 2) |
exp | 计算指数 ex 每个元素 |
log, log10, log2, log1p | 自然对数(以 e 为基数)、对数以 10 为基数、以 2 为基数的对数和 log(1 + x) |
sign | 计算每个元素的符号:1(正)、0(零)或 –1(负) |
ceil | 计算每个元素的上限(即大于或等于该数字的最小整数) |
floor | 计算每个元素的下限(即小于或等于每个元素的最大整数) |
rint | 将元素舍入到最接近的整数,保留 dtype |
modf | 将数组的小数部分和整数部分作为单独的数组返回 |
isnan | 返回指示每个值是否为 (Not a Number) 的布尔数组 NaN |
isfinite, isinf | 返回布尔数组,分别指示每个元素是有限的(非、非)还是无限的 inf NaN |
cos, cosh, sin, sinh, tan, tanh | 正则三角函数和双曲三角函数 |
arccos, arccosh, arcsin, arcsinh, arctan, arctanh | 反三角函数 |
logical_not | 逐个元素计算真值(相当于not x ~arr) |
方法 | 描述 |
---|---|
add | 在数组中添加相应的元素 |
subtract | 从第一个数组中减去第二个数组中的元素 |
multiply | 乘以数组元素 |
divide, floor_divide | 分隔或地板分隔(截断余数) |
power | 将第一个数组中的元素提升到第二个数组中指示的幂 |
maximum, fmax | 元素最大值; 忽略fmax NaN |
minimum, fmin | 元素最小值; 忽略fmin NaN |
mod | 元素比率(除法余数) |
copysign | 将第二个参数中的值符号复制到第一个参数中的值 |
greater, greater_equal, less, less_equal, equal, not_equal | 执行元素比较,生成布尔数组(相当于中缀运算符 >, >=, <, <=, ==, != ) |
logical_and | 计算 AND () 逻辑运算的元素真值 & |
logical_or | 计算 OR () 逻辑运算的元素真值 | |
logical_xor | 计算 XOR () 逻辑运算的元素真值 ^ |
数组面向数组编程
使用 NumPy 数组,可以将多种数据处理任务表示为简洁的数组表达式,否则可能需要写入循环。这种用数组表达式替换显式循环的做法被一些人称为向量化。一般来说,矢量化数组运算通常比纯Python运算快得多,在任何类型的数值计算中影响最大。
作为一个简单的例子,假设我们希望通过一个规则的值网格来评估函数。该函数采用两个一维数组,并生成两个二维矩阵,对应于这两个数组中的所有对:lsqrt(x^2 + y^2) numpy.meshgrid (x, y)
In [169]: points = np.arange(-5, 5, 0.01) # 100 equally spaced points
In [170]: xs, ys = np.meshgrid(points, points)
In [171]: ys
Out[171]:
array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],
[-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
[-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
...,
[ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],
[ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],
[ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
现在,评估函数就是编写与您编写的表达式相同的表达式,其中包含两点:
In [172]: z = np.sqrt(xs ** 2 + ys ** 2)
In [173]: z
Out[173]:
array([[7.0711, 7.064 , 7.0569, ..., 7.0499, 7.0569, 7.064 ],
[7.064 , 7.0569, 7.0499, ..., 7.0428, 7.0499, 7.0569],
[7.0569, 7.0499, 7.0428, ..., 7.0357, 7.0428, 7.0499],
...,
[7.0499, 7.0428, 7.0357, ..., 7.0286, 7.0357, 7.0428],
[7.0569, 7.0499, 7.0428, ..., 7.0357, 7.0428, 7.0499],
[7.064 , 7.0569, 7.0499, ..., 7.0428, 7.0499, 7.0569]])
使用 matplotlib 创建这个二维数组的可视化:
In [174]: import matplotlib.pyplot as plt
In [175]: plt.imshow(z, cmap=plt.cm.gray, extent=[-5, 5, -5, 5])
Out[175]: <matplotlib.image.AxesImage at 0x17f04b040>
In [176]: plt.colorbar()
Out[176]: <matplotlib.colorbar.Colorbar at 0x1810661a0>
In [177]: plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
Out[177]: Text(0.5, 1.0, 'Image plot of $\\sqrt{x^2 + y^2}$ for a grid of values'
)
使用 matplotlib 函数从函数值的二维数组创建图像图。c
如果您在 IPython 中工作,您可以通过执行以下命令关闭所有打开的绘图窗口:plt.close(“all”)
In [179]: plt.close("all")
将条件逻辑表示为数组运算
该函数是三元表达式的向量化版本。假设我们有一个布尔数组和两个值数组:numpy.wherex if condition else y
In [180]: xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
In [181]: yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
In [182]: cond = np.array([True, False, True, True, False])
假设我们想从 xarr 中获取一个值,只要在 cond 对应的值是 True 就执行,否则就从 yarr 中获取值
In [183]: result = [(x if c else y)
.....: for x, y, c in zip(xarr, yarr, cond)]
In [184]: result
Out[184]: [1.1, 2.2, 1.3, 1.4, 2.5]
这有多个问题。首先,对于大型数组,它不会很快(因为所有工作都是在解释的Python代码中完成的)。其次,它不适用于多维数组。对于多维数组,你可以通过一个函数调用来实现:numpy.where
In [185]: result = np.where(cond, xarr, yarr)
In [186]: result
Out[186]: array([1.1, 2.2, 1.3, 1.4, 2.5])
第二个和第三个参数不需要是数组;它们中的一个或两个可以是标量。数据分析中的典型用法是根据另一个数组生成一个新的值数组。假设你有一个随机生成的数据矩阵,你想用2替换所有正值,用-2替换所有负值。这可以通过使用:numpy.where来实现。
In [187]: arr = rng.standard_normal((4, 4))
In [188]: arr
Out[188]:
array([[ 2.6182, 0.7774, 0.8286, -0.959 ],
[-1.2094, -1.4123, 0.5415, 0.7519],
[-0.6588, -1.2287, 0.2576, 0.3129],
[-0.1308, 1.27 , -0.093 , -0.0662]])
In [189]: arr > 0
Out[189]:
array([[ True, True, True, False],
[False, False, True, True],
[False, False, True, True],
[False, True, False, False]])
In [190]: np.where(arr > 0, 2, -2)
Out[190]:
array([[ 2, 2, 2, -2],
[-2, -2, 2, 2],
[-2, -2, 2, 2],
[-2, 2, -2, -2]])
你可以同时使用标量和数组,例如:可以用常数 2 替换中的所有正值 numpy.where arr
In [191]: np.where(arr > 0, 2, arr) # set only positive values to 2
Out[191]:
array([[ 2. , 2. , 2. , -0.959 ],
[-1.2094, -1.4123, 2. , 2. ],
[-0.6588, -1.2287, 2. , 2. ],
[-0.1308, 2. , -0.093 , -0.0662]])
数学和统计方法
计算关于整个数组或沿轴的数据的统计信息的一组数学函数可以作为数组类的方法访问。您可以通过调用数组实例方法或使用顶级NumPy函数来使用聚合,如标准差、方差。当使用NumPy函数时,例如,必须传递要聚合的数组作为第一个参数。sum mean std numpy.sum
在这里,我生成一些正态分布的随机数据并计算一些聚合统计量:
In [192]: arr = rng.standard_normal((5, 4))
In [193]: arr
Out[193]:
array([[-1.1082, 0.136 , 1.3471, 0.0611],
[ 0.0709, 0.4337, 0.2775, 0.5303],
[ 0.5367, 0.6184, -0.795 , 0.3 ],
[-1.6027, 0.2668, -1.2616, -0.0713],
[ 0.474 , -0.4149, 0.0977, -1.6404]])
In [194]: arr.mean()
Out[194]: -0.08719744457434529
In [195]: np.mean(arr)
Out[195]: -0.08719744457434529
In [196]: arr.sum()
Out[196]: -1.743948891486906
函数 like and 采用一个可选参数,用于计算给定轴上的统计数据,从而生成一个维度的数组:mean sum axis
In [197]: arr.mean(axis=1)
Out[197]: array([ 0.109 , 0.3281, 0.165 , -0.6672, -0.3709])
In [198]: arr.sum(axis=0)
Out[198]: array([-1.6292, 1.0399, -0.3344, -0.8203])
这里,分别表示 “计算各行的平均值”、“计算各列的总和”。arr.mean(axis=1) arr.sum(axis=0)
其他方法类似,但不聚合,而是生成中间结果数组,如:cumsum cumprod
In [199]: arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
In [200]: arr.cumsum()
Out[200]: array([ 0, 1, 3, 6, 10, 15, 21, 28])
在多维数组中,累积函数(如cumsum)返回一个与原数组相同大小的数组,但沿指定轴计算每个较低维度切片的部分累积值。
In [201]: arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
In [202]: arr
Out[202]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
表达式arr.cumsum(axis=0) 计算沿着行的累积和,而 arr.cumsum(axis=1) 计算沿着列的和:
In [203]: arr.cumsum(axis=0)
Out[203]:
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]])
In [204]: arr.cumsum(axis=1)
Out[204]:
array([[ 0, 1, 3],
[ 3, 7, 12],
[ 6, 13, 21]])
方法 | 描述 |
---|---|
sum | 数组中或沿轴的所有元素的总和;零长度数组的总和为零 |
mean | 算术平均值;对零长度数组无效(返回)NaN |
std, var | 分别是标准差和方差 |
min, max | 最小值和最大值 |
argmin, argmax | 最小元素和最大元素的索引 |
cumsum | 从 0 开始元素的累加值 |
cumprod | 从 1 开始元素的累积值 |
布尔数组的方法
在上述方法中,布尔值被强制为 1 () 和 0 ()。因此,通常用作计算布尔数组中值的方法:True False sum True
In [205]: arr = rng.standard_normal(100)
In [206]: (arr > 0).sum() # Number of positive values
Out[206]: 48
In [207]: (arr <= 0).sum() # Number of non-positive values
Out[207]: 52
表达式中的括号对于能够调用的临时结果是必要的。(arr > 0).sum() sum() arr>0
测试数组中的一个或多个值是否为 True,同时检查每个值是否为 :True
In [208]: bools = np.array([False, False, True, False])
In [209]: bools.any()
Out[209]: True
In [210]: bools.all()
Out[210]: False
这些方法也适用于非布尔数组,其中非零元素被视为:True
排序
与 Python 的内置列表类型一样,可以使用 sort 方法对 NumPy 数组进行排序
In [211]: arr = rng.standard_normal(6)
In [212]: arr
Out[212]: array([ 0.0773, -0.6839, -0.7208, 1.1206, -0.0548, -0.0824])
In [213]: arr.sort()
In [214]: arr
Out[214]: array([-0.7208, -0.6839, -0.0824, -0.0548, 0.0773, 1.1206])
您可以通过将轴号传递给 sort 方法,来对多维数组中的每个一维部分进行原地排序。
In [215]: arr = rng.standard_normal((5, 3))
In [216]: arr
Out[216]:
array([[ 0.936 , 1.2385, 1.2728],
[ 0.4059, -0.0503, 0.2893],
[ 0.1793, 1.3975, 0.292 ],
[ 0.6384, -0.0279, 1.3711],
[-2.0528, 0.3805, 0.7554]])
arr.sort(axis=0) 对每一列内的值进行排序,而arr.sort(axis=1)对每一行的值进行排序
In [217]: arr.sort(axis=0)
In [218]: arr
Out[218]:
array([[-2.0528, -0.0503, 0.2893],
[ 0.1793, -0.0279, 0.292 ],
[ 0.4059, 0.3805, 0.7554],
[ 0.6384, 1.2385, 1.2728],
[ 0.936 , 1.3975, 1.3711]])
In [219]: arr.sort(axis=1)
In [220]: arr
Out[220]:
array([[-2.0528, -0.0503, 0.2893],
[-0.0279, 0.1793, 0.292 ],
[ 0.3805, 0.4059, 0.7554],
[ 0.6384, 1.2385, 1.2728],
[ 0.936 , 1.3711, 1.3975]])
像Python内置函数样的顶层方法,返回数组的排序副本,而不是就地修改数组。
In [221]: arr2 = np.array([5, -10, 7, 1, 0, -3])
In [222]: sorted_arr2 = np.sort(arr2)
In [223]: sorted_arr2
Out[223]: array([-10, -3, 0, 1, 5, 7])
唯一和其他集合逻辑
NumPy 对一维ndarray有一些基本的操作。一个常用的是,它返回数组中排序的唯一值:numpy.unique
In [224]: names = np.array(["Bob", "Will", "Joe", "Bob", "Will", "Joe", "Joe"])
In [225]: np.unique(names)
Out[225]: array(['Bob', 'Joe', 'Will'], dtype='<U4')
In [226]: ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
In [227]: np.unique(ints)
Out[227]: array([1, 2, 3, 4])
numpy.unique 与纯Python相比
In [228]: sorted(set(names))
Out[228]: ['Bob', 'Joe', 'Will']
在许多情况下,NumPy版本更快,并且返回NumPy数组而不是Python列表。
另一个函数,测试一个数组中值在另一个数组中的隶属关系,返回一个布尔数组:numpy.in1d
In [229]: values = np.array([6, 0, 0, 3, 2, 5, 6])
In [230]: np.in1d(values, [2, 3, 6])
Out[230]: array([ True, False, False, True, True, False, True])
方法 | 描述 |
---|---|
unique(x) | 计算已排序的唯一元素 x |
intersect1d(x, y) | 计算 和 中排序的公共元素 x y |
union1d(x, y) | 计算元素的排序并集 |
in1d(x, y) | 计算一个布尔数组,指示 的每个元素是否包含在 x y |
setdiff1d(x, y) | 设置差异,元素中不在 x y |
setxor1d(x, y) | 设置对称差分;元素在任一数组中,但不能同时在数组中 |
使用数组进行文件输入和输出
numpy.save 和 numpy.load 是在磁盘上有效地保存和加载数组数据的两个主要函数。默认情况下,数组以未压缩的原始二进制格式保存,文件扩展名为 .npy
In [231]: arr = np.arange(10)
In [232]: np.save("some_array", arr)
如果文件路径尚未以 .npy 结尾,则将附加扩展名。然后,磁盘上的数组可以加载:numpy.load
In [233]: np.load("some_array.npy")
Out[233]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
您可以使用数组作为关键字参数将数组保存在未压缩的存档中:numpy.savez
In [234]: np.savez("array_archive.npz", a=arr, b=arr)
加载 .npz 文件时,您会得到一个类似字典的对象,该对象会延迟加载各个数组:
In [235]: arch = np.load("array_archive.npz")
In [236]: arch["b"]
Out[236]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
如果您的数据压缩良好,您可能希望改用:numpy.savez_compressed
In [237]: np.savez_compressed("arrays_compressed.npz", a=arr, b=arr)
线性代数
线性代数运算,如矩阵乘法、分解、行列式和其他平方矩阵数学,是许多数组库的重要组成部分。将两个二维数组相乘是元素乘积,而矩阵乘法需要使用函数或中缀运算符。 既是数组方法,又是命名空间中用于执行矩阵乘法的函数:*dot @dot numpy
In [241]: x = np.array([[1., 2., 3.], [4., 5., 6.]])
In [242]: y = np.array([[6., 23.], [-1, 7], [8, 9]])
In [243]: x
Out[243]:
array([[1., 2., 3.],
[4., 5., 6.]])
In [244]: y
Out[244]:
array([[ 6., 23.],
[-1., 7.],
[ 8., 9.]])
In [245]: x.dot(y)
Out[245]:
array([[ 28., 64.],
[ 67., 181.]])
x.dot(y)相当于:np.dot(x, y)
In [246]: np.dot(x, y)
Out[246]:
array([[ 28., 64.],
[ 67., 181.]])
二维数组和适当大小的一维数组之间的矩阵乘积产生一维数组:
In [247]: x @ np.ones(3)
Out[247]: array([ 6., 15.])
numpy.linalg 有一组标准的矩阵分解,以及逆分解和行列式之类的东西:
In [248]: from numpy.linalg import inv, qr
In [249]: X = rng.standard_normal((5, 5))
In [250]: mat = X.T @ X
In [251]: inv(mat)
Out[251]:
array([[ 3.4993, 2.8444, 3.5956, -16.5538, 4.4733],
[ 2.8444, 2.5667, 2.9002, -13.5774, 3.7678],
[ 3.5956, 2.9002, 4.4823, -18.3453, 4.7066],
[-16.5538, -13.5774, -18.3453, 84.0102, -22.0484],
[ 4.4733, 3.7678, 4.7066, -22.0484, 6.0525]])
In [252]: mat @ inv(mat)
Out[252]:
array([[ 1., 0., 0., 0., 0.],
[ 0., 1., 0., 0., 0.],
[ 0., 0., 1., -0., 0.],
[ 0., 0., 0., 1., 0.],
[-0., 0., 0., 0., 1.]])
方法 | 描述 |
---|---|
diag | 将方阵的对角线(或非对角线)元素作为一维数组返回,或将一维数组转换为非对角线上为零的方阵 |
dot | 矩阵乘法 |
trace | 计算对角线元素的总和 |
det | 计算矩阵行列式 |
eig | 计算方阵的特征值和特征向量 |
inv | 计算平方矩阵的倒数 |
pinv | 计算矩阵的摩尔-彭罗斯伪逆函数 |
qr | 计算二维码分解 |
svd | 计算奇异值分解 (SVD) |
solve | 求解 x 的线性系统 Ax = b,其中 A 是方阵 |
lstsq | 计算最小二乘解Ax = b |
随机游走
随机游走也称随机漫步,下面是一个纯 Python 方法,使用内置模块实现 1,000 步的单个随机游走
#! blockstart
import random
position = 0
walk = [position]
nsteps = 1000
for _ in range(nsteps):
step = 1 if random.randint(0, 1) else -1
position += step
walk.append(position)
#! blockend
In [255]: plt.plot(walk[:100])
您可以进行观察,该观察值是随机步骤的累积总和,并且可以计算为数组表达式。因此,我使用该模块一次抽取 1,000 次抛硬币,将它们设置为 1 和 –1,并计算累积总和:walk numpy.random
In [256]: nsteps = 1000
In [257]: rng = np.random.default_rng(seed=12345) # fresh random generator
In [258]: draws = rng.integers(0, 2, size=nsteps)
In [259]: steps = np.where(draws == 0, 1, -1)
In [260]: walk = steps.cumsum()
由此,我们可以开始提取统计数据,例如步行轨迹上的最小值和最大值:
In [261]: walk.min()
Out[261]: -8
In [262]: walk.max()
Out[262]: 50
In [263]: (np.abs(walk) >= 10).argmax()
Out[263]: 155
在NumPy高级应用中,将深入探讨 NumPy 的功能,以帮助您进一步发展您的阵列计算技能。
标签:arr,True,矢量化,基础知识,数组,np,array,NumPy,Out From: https://blog.csdn.net/m0_63287589/article/details/137408907