拓冰建站拓冰建站
首页 / 资讯中心 / 正文

NumPy 数组创建完全指南:六大机制、dtype 陷阱与最佳实践

NumPy 数组创建完全指南六大机制、dtype 陷阱与最佳实践【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy本指南以 NumPy 用户文档 Array creation 为核心骨架系统讲解创建ndarray的六种通用机制并结合当前仓库源码numpy/_core与numpy/lib深入解析dtype溢出、视图与副本、浮点舍入等易错细节。读完本文你将掌握从 Python 序列、内置创建函数、现有数组、磁盘文件、原始字节到第三方库六条完整的建数组路径并能正确规避arange浮点误差与无符号整数回绕等经典陷阱。前置说明NumPy 中的任意数组对象统称为ndarrayN 维数组。本文讨论的是创建通用ndarray的方法结构化数组的创建可参见 basics.rec。六种数组创建机制总览NumPy 提供了 6 条通用途径来创建数组从其他 Python 结构如列表、元组转换使用 NumPy 内建的数组创建函数如arange、ones、zeros等复制、连接或修改现有数组从磁盘读取数组标准格式或自定义格式通过字符串或缓冲区从原始字节创建数组使用特殊库函数如random。其中前两类序列转换与内建函数覆盖了绝大多数日常场景后四类则用于数据交换、持久化和科学计算流水线。接下来逐一展开。1) 从 Python 序列转换为 NumPy 数组使用numpy.array可以直接把 Python 列表[...]和元组(...)转换为数组嵌套深度决定了数组的维度数字列表创建一个 1D 数组列表的列表创建一个 2D 数组更深层的嵌套列表创建更高维数组。 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]]])dtype 的显式指定与溢出错误使用np.array创建新数组时应考虑元素的 dtype数据类型并可显式指定。这能让你更精确地控制底层数据结构以及元素在 C/C 函数中的处理方式。当数值超出指定dtype的范围时NumPy 会抛出错误 import numpy as np np.array([127, 128, 129], dtypenp.int8) Traceback (most recent call last): ... OverflowError: Python integer 128 out of bounds for int8原因在于 8 位有符号整数只能表示 -128 到 127超出即溢出。这一特性常常被误解如果混用不匹配的dtype进行运算会得到意外结果例如 import numpy as np a np.array([2, 3, 4], dtypenp.uint32) b np.array([5, 6, 7], dtypenp.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相同如都是uint32时结果保持同类型减法产生无符号回绕当dtype不同uint32与int32时NumPy 会推导一个新的、能同时容纳所有参与运算元素类型的类型——这里int64可以同时表示uint32与int32的全部取值。默认行为NumPy 默认创建的数组为 32 位或 64 位有符号整数取决于平台与 C 的long大小一致或双精度浮点数。如果你的整型数组期望是特定类型必须在创建时显式指定dtype。2) 内建的数组创建函数NumPy 拥有 40 多个内建的数组创建函数详见 Array creation routines 参考文档位于 doc/source/reference/ 的routines.array-creation.rst与本文档互为参见。按创建数组的维度这些函数大致分为三类1D 数组创建函数2D 数组创建函数通用 ndarray 创建函数。1D 数组arange 与 linspace1D 创建函数如numpy.linspace、numpy.arange通常至少需要两个输入start和stop。numpy.arange创建步长规律递增的数组支持三种调用形态见 arange 官方文档 import numpy as np np.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) np.arange(2, 10, dtypenp.float64) 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])使用 arange 的最佳实践是使用整数的 start、end 和 step。第二个例子显式指定了dtype第三个例子中数组自动采用float64以容纳0.1的步长。由于舍入误差stop值有时会被包含进来——从 arange 文档源码 可以看到两条重要警告输出长度可能不稳定实际用于填充数组的步长是dtype(start step) - dtype(start)而非step当start远大于step时会发生精度损失例如np.arange(0, 5, 0.5, dtypenp.int_)会得到全 0整数溢出np.arange产生的是numpy.int32/int64而非 Python 任意精度整数大整数运算可能出错。因此官方建议非整数步长请优先使用numpy.linspace。numpy.linspace在指定的起止值之间生成指定数量、等间距分布的元素实现见 numpy/_core/function_base.py import numpy as np np.linspace(1., 4., 6) array([1. , 1.6, 2.2, 2.8, 3.4, 4. ])linspace的核心优势在于保证元素个数与起止点。与arange(start, stop, step)不含stop不同linspace默认包含两端点可通过endpointFalse排除。其关键参数包括num采样个数默认 50必须非负endpoint为True时stop是最后一个采样点默认为False时排除retstep为True时返回(samples, step)元组dtype未指定时从start/stop推断且推断结果永远不会是整数即使参数全为整数也会选择floataxis当start/stop为数组时指定采样沿结果中的哪条轴存放默认 0即插入新轴在开头。从实现细节看linspace内部会先处理start stop的退化情况避免inf - inf产生nan和无效值警告再调用_nx.arange(0, num, ...)生成序号序列最后完成插值计算。2D 数组eye、diag 与 vander2D 创建函数如numpy.eye、numpy.diag、numpy.vander定义以 2D 数组表示的特殊矩阵性质。np.eye(n, m)定义 2D 单位矩阵行索引等于列索引ij处为 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.]])np.eye(N, MNone, k0, dtypefloat)实现见 numpy/lib/_twodim_base_impl.py的M参数可指定列数默认等于Nk指定对角线偏移。注意np.eye(3)的结果是float64默认dtypefloat而非整数。numpy.diag具有双重用途实现见 numpy/lib/_twodim_base_impl.py给定一维序列时构造对角线上为该值的方阵给定 2D 数组时返回仅包含对角线元素的一维数组。二者在线性代数中都很常用 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])第二个示例展示了k1时将主对角线上方第一条副对角线填充为给定值。vander(x, n)定义范德蒙德矩阵实现见 numpy/lib/_twodim_base_impl.py每一列都是输入 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]])从源码看vander(x, NNone, increasingFalse)的N缺省时返回方阵N len(x)increasingTrue时幂次从左到右递增x^0, x^1, ..., x^(N-1)默认则递减首列为x^(N-1)。要求输入x必须为一维否则抛出ValueError。方阵范德蒙德矩阵的行列式等于输入向量两两差值的乘积可用np.linalg.det(np.vander(x))验证。通用 ndarray 创建函数zeros、ones、random 与 indices通用创建函数如numpy.ones、numpy.zeros、Generator.random依据期望的形状定义数组在元组或列表中指定维数及各维长度即可创建任意维数组。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.]]])从 numpy/_core/numeric.py 中 ones 的实现 可以看到其内部机制先调用empty(shape, dtype, order)分配未初始化内存再通过multiarray.copyto(a, 1, castingunsafe)批量填充 1。因此ones/zeros都支持shape、dtype、orderC 行优先 / F 列优先参数并自 NumPy 2.0 起支持仅用于 Array-API 互操作性的device参数只能传cpu。default_rng结果的Generator.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]]])使用default_rng(42)的推荐做法而非旧式全局np.random.seed可以确保可复现且不污染全局随机状态。numpy.indices创建一组数组堆叠为高一个维度的数组每个维度一个各自表示该维度的变化实现见 numpy/_core/numeric.py 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]]])这在规则网格上求值多元函数时尤其有用配合dtypeint与sparseTrue可节省内存。3) 复制、连接或修改现有数组创建数组后可以复制、连接或修改现有数组以生成新数组。关键陷阱当你把数组或其元素赋值给新变量时必须显式numpy.copy否则该变量只是原数组的一个视图view 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前两个元素的视图对b加 1 等价于对a[:2]加 1。若想创建新的数组使用numpy.copy实现见 numpy/lib/_function_base_impl.pyorderK表示尽可能保持原内存布局 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 以及快速入门中的相关章节 quickstart.rst。连接现有数组则有多个例程如numpy.vstack、numpy.hstack、numpy.block实现见 numpy/_core/shape_base.pyvstack/hstack自 NumPy 2.0 起还支持dtype与casting参数。下面用block把四个 2×2 数组拼成 4×4 数组 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.]])block接受嵌套列表作为块布局其他连接例程使用类似的语法具体示例可查阅各自文档。4) 从磁盘读取数组标准与自定义格式这是大型数组创建最常见的情形细节高度依赖磁盘上的数据格式。本节给出通用指引更完整的 IO 示例参见 How to Read and Write files。标准二进制格式许多领域都有数组数据的标准格式以下是已知可通过 Python 库读取并返回 NumPy 数组的典型代表HDF5: h5py FITS: Astropy还有一些格式虽不能直接读取为数组但转换并不困难例如 PIL 支持的众多图像格式jpg、png 等——先由 PIL 读为图像再转为 ndarray。常见 ASCII 格式逗号分隔csv、制表符分隔tsv等定界文件常用于 Excel、LabView 等程序。Python 函数可以逐行读取并解析这些文件NumPy 提供两个标准例程numpy.loadtxt和numpy.genfromtxt实现见 numpy/lib/_npyio_impl.pygenfromtxt还支持缺失值处理与列名解析进阶用法见 basics.io.genfromtxt。给定一个simple.csv$ cat simple.csv x, y 0, 0 1, 1 2, 4 3, 9用numpy.loadtxt导入 import numpy as np np.loadtxt(simple.csv, delimiter ,, skiprows 1) array([[0., 0.], [1., 1.], [2., 4.], [3., 9.]])loadtxt的关键参数包括delimiter定界符默认任意空白、skiprows跳过前 N 行表头、comments注释字符默认#、dtype默认float。更通用的 ASCII 文件还可借助scipy.io与pandas读取在需要处理混合类型列时pandas 通常更方便再通过.to_numpy()得到 ndarray。5) 通过字符串或缓冲区从原始字节创建数组这类场景有多种实现路径如果文件格式相对简单可以编写一个小型 IO 库使用 NumPy 的fromfile()函数和.tofile()方法直接读写 NumPy 数组注意字节序 byteorder如果已有读取数据的 C/C 库可以通过多种技术包装该库如 Cython、cffi、ctypes但这显然工作量更大且需要相当深入的 C/C 交互知识。numpy.fromfile(file, dtypefloat, count-1, sep)从二进制或文本文件构建数组count-1表示读取全部数据.tofile()则是把数组以原始二进制形式写入文件。由于这种读写方式不做格式转换跨平台交换数据时必须自行保证字节序一致。6) 使用特殊库函数SciPy、pandas、OpenCV 等NumPy 是 Python 科学计算栈中数组容器的基础库。SciPy、pandas、OpenCV 等众多 Python 库都以 NumPy ndarray 作为数据交换的公共格式这些库既能创建 NumPy 数组也能对其操作和处理。例如pandas.DataFrame.to_numpy()/.values返回 ndarraySciPy 的scipy.io.loadmat读取 MATLAB 文件返回 ndarrayOpenCV 的cv2.imread返回的即是 ndarrayBGR 通道序。这种ndarray 作为公共交换格式的设计使六种创建机制可以与整个生态无缝衔接。结语与最佳实践速查均匀整数序列用np.arange(start, stop[, step])推荐整数参数均匀浮点序列、需要精确控制点数或包含端点用np.linspace(start, stop, num)定形状的 0/1/常量/未初始化数组用np.zeros、np.ones、np.full、np.empty并按需显式指定dtype默认float64与order特殊矩阵单位阵、对角阵、范德蒙德阵用np.eye、np.diag、np.vander需要新数据而非共享内存时务必用.copy()区分视图与副本定界文本文件用np.loadtxt/np.genfromtxtHDF5/FITS用 h5py/Astropy原始字节用fromfile/tofile随机数组使用default_rng(seed).random(shape)保证可复现且不污染全局状态。六种机制覆盖了从内存到磁盘、从纯 Python 到 C/C 扩展的全部建数组场景理解dtype的溢出与类型提升规则是避免无符号回绕和精度陷阱的第一步。【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门