数组创建#
简介#
有 6 种创建数组的通用机制:
从其他 Python 结构转换(即列表和元组)
NumPy 固有数组创建函数(例如 arange, ones, zeros 等)
复制,连接或改变现有数组
从磁盘读取数组,无论是标准格式还是自定义格式
通过使用字符串或缓冲区从原始字节创建数组
使用特殊库函数(例如,random)
您可以使用这些方法来创建 ndarrays 或 结构化数组 .本文档将介绍用于 ndarray 创建的通用方法.
1) 将 Python 序列转换为 NumPy 数组#
NumPy 数组可以使用 Python 序列(例如列表和元组)来定义.列表和元组分别使用 [...] 和 (...) 定义.列表和元组可以定义 ndarray 创建:
数字列表将创建一个 1D 数组,
列表的列表将创建一个 2D 数组,
进一步嵌套的列表将创建更高维的数组.通常,任何数组对象在 NumPy 中都称为 ndarray.
>>> import numpy as np
>>> a1D = np.array([1, 2, 3, 4])
>>> a2D = np.array([[1, 2], [3, 4]])
>>> a3D = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
当您使用 numpy.array 定义新数组时,应考虑数组中元素的 dtype ,可以显式指定.此功能使您可以更好地控制底层数据结构以及 C/C++ 函数中如何处理元素.当值不适合并且您正在使用 dtype 时,NumPy 可能会引发错误:
>>> import numpy as np
>>> np.array([127, 128, 129], dtype=np.int8)
Traceback (most recent call last):
...
OverflowError: Python integer 128 out of bounds for int8
8 位有符号整数表示 -128 到 127 的整数.将 int8 数组分配给此范围之外的整数会导致溢出.此功能通常会被误解.如果使用不匹配的 dtypes 执行计算,则可能会得到不需要的结果,例如:
>>> import numpy as np
>>> a = np.array([2, 3, 4], dtype=np.uint32)
>>> b = np.array([5, 6, 7], dtype=np.uint32)
>>> c_unsigned32 = a - b
>>> print('unsigned c:', c_unsigned32, c_unsigned32.dtype)
unsigned c: [4294967293 4294967293 4294967293] uint32
>>> c_signed32 = a - b.astype(np.int32)
>>> print('signed c:', c_signed32, c_signed32.dtype)
signed c: [-3 -3 -3] int64
请注意,当对两个具有相同 dtype 的数组执行操作时,结果数组的类型相同.当使用不同的 dtype 进行操作时,NumPy 将分配一个新类型,以满足计算中涉及的所有数组元素,此处 uint32 和 int32 都可以表示为 int64 .
NumPy 的默认行为是创建 32 位或 64 位有符号整数(平台相关,与 C long 大小匹配)或双精度浮点数的数组. 如果您希望整数数组是特定类型,则需要在创建数组时指定 dtype.
2) NumPy 固有数组创建函数#
NumPy 具有 40 多个内置函数,用于创建 Array creation routines 中定义的数组. 这些函数可以大致分为三类,基于它们创建的数组的维度:
1D 数组
2D 数组
ndarray
1 - 1D 数组创建函数#
1D 数组创建函数,例如 numpy.linspace 和 numpy.arange 通常需要至少两个输入, start 和 stop .
numpy.arange 创建具有规则递增值的数组. 查看文档以获取完整信息和示例. 以下是一些示例:
>>> import numpy as np
>>> np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(2, 10, dtype=float)
array([2., 3., 4., 5., 6., 7., 8., 9.])
>>> np.arange(2, 3, 0.1)
array([2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])
注意 numpy.arange 的最佳实践是使用整数起始值,结束值和步长值. 关于 dtype 有一些微妙之处. 在第二个示例中,定义了 dtype . 在第三个示例中,数组是 dtype=float ,以适应步长 0.1 ``. 由于舍入误差,有时会包含 `` stop `` 值.
numpy.linspace will create arrays with a specified number of elements, and
spaced equally between the specified beginning and end values. For
example:
>>> import numpy as np
>>> np.linspace(1., 4., 6)
array([1. , 1.6, 2.2, 2.8, 3.4, 4. ])
此创建函数的优点是,您可以保证元素的数量以及起始点和结束点. 前面的 arange(start, stop, step) 将不包括值 stop .
2 - 2D 数组创建函数#
2D 数组创建函数,例如 numpy.eye , numpy.diag 和 numpy.vander 定义了表示为 2D 数组的特殊矩阵的属性.
np.eye(n, m) 定义一个 2D 单位矩阵. i=j (行索引和列索引相等)的元素为 1,其余元素为 0,如下所示:
>>> import numpy as np
>>> np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
>>> np.eye(3, 5)
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.]])
numpy.diag 可以定义一个沿对角线具有给定值的正方形 2D 数组,或者如果给定一个 2D 数组,则返回一个仅包含对角线元素的 1D 数组. 这两个数组创建函数在进行线性代数时可能很有用,如下所示:
>>> import numpy as np
>>> np.diag([1, 2, 3])
array([[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
>>> np.diag([1, 2, 3], 1)
array([[0, 1, 0, 0],
[0, 0, 2, 0],
[0, 0, 0, 3],
[0, 0, 0, 0]])
>>> a = np.array([[1, 2], [3, 4]])
>>> np.diag(a)
array([1, 4])
vander(x, n) 将范德蒙矩阵定义为 2D NumPy 数组. 范德蒙矩阵的每一列都是输入 1D 数组或列表或元组 x 的递减幂,其中最高多项式阶数为 n-1 . 此数组创建例程有助于生成线性最小二乘模型,如下所示:
>>> import numpy as np
>>> np.vander(np.linspace(0, 2, 5), 2)
array([[0. , 1. ],
[0.5, 1. ],
[1. , 1. ],
[1.5, 1. ],
[2. , 1. ]])
>>> np.vander([1, 2, 3, 4], 2)
array([[1, 1],
[2, 1],
[3, 1],
[4, 1]])
>>> np.vander((1, 2, 3, 4), 4)
array([[ 1, 1, 1, 1],
[ 8, 4, 2, 1],
[27, 9, 3, 1],
[64, 16, 4, 1]])
3 - 通用 ndarray 创建函数#
ndarray 创建函数,例如 numpy.ones , numpy.zeros 和 random 基于所需的形状定义数组. 通过在元组或列表中指定多少个维度以及沿着该维度的长度,ndarray 创建函数可以创建具有任何维度的数组.
numpy.zeros 将创建一个用 0 值填充的具有指定形状的数组. 默认的 dtype 是 float64
>>> import numpy as np
>>> np.zeros((2, 3))
array([[0., 0., 0.],
[0., 0., 0.]])
>>> np.zeros((2, 3, 2))
array([[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]]])
numpy.ones 将创建一个填充了 1 值的数组. 它在所有其他方面与 zeros 相同,如下所示:
>>> import numpy as np
>>> np.ones((2, 3))
array([[1., 1., 1.],
[1., 1., 1.]])
>>> np.ones((2, 3, 2))
array([[[1., 1.],
[1., 1.],
[1., 1.]],
[[1., 1.],
[1., 1.],
[1., 1.]]])
default_rng 结果的 random 方法将创建一个填充了 0 到 1 之间随机值的数组. 它包含在 numpy.random 库中. 下面,分别创建了形状为 (2,3) 和 (2,3,2) 的两个数组. 种子设置为 42,因此您可以重现这些伪随机数:
>>> import numpy as np
>>> from numpy.random import default_rng
>>> default_rng(42).random((2,3))
array([[0.77395605, 0.43887844, 0.85859792],
[0.69736803, 0.09417735, 0.97562235]])
>>> default_rng(42).random((2,3,2))
array([[[0.77395605, 0.43887844],
[0.85859792, 0.69736803],
[0.09417735, 0.97562235]],
[[0.7611397 , 0.78606431],
[0.12811363, 0.45038594],
[0.37079802, 0.92676499]]])
numpy.indices 将创建一组数组(堆叠为一个更高维度的数组),每个维度一个,每个维度代表该维度的变化:
>>> import numpy as np
>>> np.indices((3,3))
array([[[0, 0, 0],
[1, 1, 1],
[2, 2, 2]],
[[0, 1, 2],
[0, 1, 2],
[0, 1, 2]]])
这对于在规则网格上评估多个维度的函数特别有用.
3) 复制,连接或修改现有数组#
一旦创建了数组,就可以复制,连接或修改这些现有数组以创建新数组. 将数组或其元素分配给新变量时,必须显式使用 numpy.copy 复制该数组,否则该变量将成为原始数组的视图.考虑以下示例:
>>> import numpy as np
>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> b = a[:2]
>>> b += 1
>>> print('a =', a, '; b =', b)
a = [2 3 3 4 5 6] ; b = [2 3]
在此示例中,您没有创建新数组.您创建了一个变量 b ,该变量查看 a 的前 2 个元素. 当您向 b 添加 1 时,通过向 a[:2] 添加 1 会得到相同的结果. 如果您要创建新数组,请使用 numpy.copy 数组创建例程,如下所示:
>>> import numpy as np
>>> a = np.array([1, 2, 3, 4])
>>> b = a[:2].copy()
>>> b += 1
>>> print('a = ', a, 'b = ', b)
a = [1 2 3 4] b = [2 3]
有关更多信息和示例,请参见 Copies and Views .
有许多例程可以连接现有数组,例如 numpy.vstack , numpy.hstack 和 numpy.block . 这是一个使用 block 将四个 2x2 数组连接成一个 4x4 数组的示例:
>>> import numpy as np
>>> A = np.ones((2, 2))
>>> B = np.eye(2, 2)
>>> C = np.zeros((2, 2))
>>> D = np.diag((-3, -4))
>>> np.block([[A, B], [C, D]])
array([[ 1., 1., 1., 0.],
[ 1., 1., 0., 1.],
[ 0., 0., -3., 0.],
[ 0., 0., 0., -4.]])
其他例程使用类似的语法来连接 ndarray.有关更多示例和语法,请查阅例程的文档.
4) 从磁盘读取数组,可以是标准格式或自定义格式#
这是创建大型数组的最常见情况. 详细信息在很大程度上取决于磁盘上的数据格式. 本节提供有关如何处理各种格式的一般指针. 有关 IO 的更详细示例,请参见 How to Read and Write files .
标准二进制格式#
各种字段都有数组数据的标准格式. 以下列出了具有已知 Python 库来读取它们并返回 NumPy 数组的格式(可能还有其他格式可以读取并转换为 NumPy 数组,因此也请查看最后一节):
HDF5: h5py
FITS: Astropy
无法直接读取但转换为 NumPy 数组并不困难的格式示例是由 PIL 等库支持的格式(能够读取和写入许多图像格式,例如 jpg,png 等).
常见的 ASCII 格式#
分隔文件,例如逗号分隔值 (csv) 和制表符分隔值 (tsv) 文件,用于 Excel 和 LabView 等程序. Python 函数可以逐行读取和解析这些文件. NumPy 有两个用于导入带分隔数据的文件的标准例程 numpy.loadtxt 和 numpy.genfromtxt . 这些函数在 读取和写入文件 中有更复杂的使用案例. 给定一个 simple.csv 的简单示例:
$ cat simple.csv
x, y
0, 0
1, 1
2, 4
3, 9
使用 numpy.loadtxt 完成导入 simple.csv
>>> import numpy as np
>>> np.loadtxt('simple.csv', delimiter = ',', skiprows = 1)
array([[0., 0.],
[1., 1.],
[2., 4.],
[3., 9.]])
5) 通过使用字符串或缓冲区从原始字节创建数组#
可以使用多种方法. 如果文件具有相对简单的格式,那么可以编写一个简单的 I/O 库并使用 NumPy fromfile() 函数和 .tofile() 方法直接读取和写入 NumPy 数组(注意您的字节顺序!). 如果存在读取数据的良好 C 或 C++ 库,则可以使用各种技术包装该库,但这肯定需要更多的工作,并且需要更多高级知识才能与 C 或 C++ 接口.
6) 使用特殊库函数(例如,SciPy,pandas 和 OpenCV)#
NumPy 是 Python 科学计算堆栈中数组容器的基础库. 许多 Python 库,包括 SciPy,Pandas 和 OpenCV,都使用 NumPy ndarray 作为数据交换的通用格式. 这些库可以创建,操作和使用 NumPy 数组.