简介:本文面向正在学习科学计算与数据处理的开发者,从numpy最基础的数组对象谈起,系统梳理数组创建、轴与形状、随机数生成、广播机制及常用计算接口。阅读后你能快速建立对numpy工作方式的整体认知,并可直接在本地环境中完成安装与基础实践。
numpy是Python生态中面向数值计算的基础库之一。与其把它看作一个功能单一的工具包,不如将它理解为Python在科学计算场景下的“数组计算底座”。很多更高层的数据处理、机器学习或统计分析工具,在底层都依赖类似numpy提供的多维数组对象与向量化计算能力。
如果用一句话概括,numpy的核心是:基于n维数组对象的高效科学计算库。
从这个概括中可以提炼出三个关键特征。
Python原生的列表可以存储一组数据,但当数据维度增加、规模变大时,原生列表在运算效率、内存占用和操作表达上都有明显局限。numpy提供了一种称为ndarray的n维数组对象,用来表示同一类型数据的集合。
这里的“同一类型”很关键。numpy数组通常要求元素类型一致,这使得它在底层可以使用连续内存块存储数据,并通过预编译代码完成批量运算,而不必像Python列表那样对每个元素进行动态类型判断和解释执行。
广播是numpy中非常重要的机制。简单来说,当两个形状不同的数组进行运算时,numpy会在一定规则下自动扩展其中一个数组的维度,使它们能够完成逐元素计算。
例如,一个形状为(3, 3)的数组与一个形状为(3,)的数组相加时,numpy会将后者沿缺失维度扩展,等效为每一行都加上同一个向量。广播并不是简单地把数组复制一份,而是在计算过程中隐式完成形状对齐,既节省内存,又让表达式更简洁。
numpy不仅提供数组容器,还内置了大量数学函数、统计函数、线性代数操作和随机数生成功能。这些接口大多以向量化方式实现,即对数组中的每个元素或某个轴整体执行计算,避免开发者编写显式循环。
例如求和、均值、标准差、点积、矩阵乘法、三角函数、指数对数等操作,都可以直接调用相应接口完成。这种设计让数值计算代码更接近数学表达式,也更容易阅读和验证。
numpy是一个Python库,因此安装方式与普通Python包一致。可以使用Python常见的包管理工具进行安装。安装前需要确认本地已经具备可用的Python环境。
如果使用pip,可以在命令行中执行:
pip install numpy
如果使用conda环境,可以执行:
conda install numpy
安装完成后,通常通过以下方式导入:
import numpy as np
其中np是常见别名,使用别名可以让后续代码更简洁。建议在脚本或交互式环境中优先采用这种导入方式。
对于刚接触numpy的开发者来说,“轴”是一个容易混淆但又必须理解的概念。
轴可以理解为数组的维度编号。二维数组有两个轴:第0轴对应行方向,第1轴对应列方向。三维数组则有三个轴,可以将其视为多个二维数组堆叠形成。
例如:
import numpy as nparr_1d = np.array([1, 2, 3])arr_2d = np.array([[0, 1, 2],[3, 4, 5]])arr_3d = np.array([[[0, 1, 2], [3, 4, 5]],[[6, 7, 8], [9, 10, 11]]])
其中arr_1d是一维数组,只有一个轴;arr_2d是二维数组,有两个轴;arr_3d是三维数组,有三个轴。更高维数组可以依此类推。
数组的shape属性可以查看每个轴的长度。例如arr_2d.shape返回(2, 3),表示第0轴长度为2,第1轴长度为3。理解形状与轴的对应关系,是后续进行索引、切片、聚合和广播运算的基础。
numpy提供多种数组创建方式,可以满足不同场景下的数据初始化需求。
np.array从列表或元组创建最直接的方式是将Python列表或元组传入np.array函数。可以通过dtype参数显式指定元素类型:
import numpy as nparr = np.array([1, 2, 3], dtype=int)print(arr)
输出结果为:
array([1, 2, 3])
对于二维数组,可以传入嵌套列表或嵌套元组:
arr2 = np.array(((1, 2), (3, 4)))print(arr2)
输出结果为:
array([[1, 2],[3, 4]])
这种方式适合数据量较小、内容已知的场景。需要注意的是,如果不指定dtype,numpy会根据输入数据自动推断元素类型。
np.arange创建连续数组np.arange的用法与Python内置的range类似,但它返回的是numpy数组,而不是迭代器:
arr3 = np.arange(1, 6)print(arr3)
输出结果为:
array([1, 2, 3, 4, 5])
np.arange支持起始值、终止值和步长参数,适合快速生成连续整数或浮点数序列。需要注意的是,终止值默认不包含在结果中,这与Python的range行为一致。
np.linspace创建等间隔数组当需要在一个区间内生成固定数量的等间隔点时,可以使用np.linspace。它更关注元素数量,而不是步长:
arr4 = np.linspace(0, 1, 5)print(arr4)
输出结果为:
array([0. , 0.25, 0.5 , 0.75, 1. ])
这类数组在数值计算、绘图和采样场景中非常常见。
np.zeros和np.ones可以快速创建指定形状的数组,元素分别初始化为0或1:
zeros_arr = np.zeros((2, 3))ones_arr = np.ones((3, 2))
这类函数在初始化权重、掩码或占位数组时非常实用。
随机数在模拟、采样、初始化参数和统计实验中经常出现。numpy的random模块提供多种随机数组生成函数。
np.random.rand可以生成[0, 1)区间内均匀分布的随机数。传入的参数表示目标数组的形状:
rand_arr = np.random.rand(2, 2)print(rand_arr)
可能输出:
array([[0.99449146, 0.92339551],[0.1837405 , 0.41719798]])
每次运行结果通常不同,因为随机种子不同。
np.random.randn生成服从标准正态分布的随机数,即均值为0、标准差为1:
randn_arr = np.random.randn(3, 2)print(randn_arr)
可能输出:
array([[-1.27481003, -1.5888111 ],[ 0.16985203, -2.91526479],[ 1.75992671, -2.81304831]])
标准正态分布数据在机器学习参数初始化、假设检验和噪声模拟中经常使用。
numpy数组支持与Python序列类似的索引和切片方式,同时扩展了多维访问能力。
对于一维数组:
arr = np.array([10, 20, 30, 40])print(arr[0])print(arr[-1])
对于二维数组,可以使用逗号分隔不同轴的索引:
arr2 = np.array([[1, 2, 3],[4, 5, 6]])print(arr2[0, 1]) # 第0行第1列print(arr2[1, 2]) # 第1行第2列
这种写法比嵌套索引更清晰。
切片可以按轴获取子数组:
arr3 = np.arange(10)print(arr3[2:7:2])
对于二维数组,可以对不同轴分别切片:
arr4 = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])print(arr4[:2, 1:])
上述代码表示取前两行,以及从第1列到最后一列的子数组。
一维数组可以直接迭代:
for x in np.array([1, 2, 3]):print(x)
二维数组默认沿第0轴迭代,即每次返回一行:
for row in np.array([[1, 2], [3, 4]]):print(row)
如果需要遍历每个元素,可以先使用flatten方法:
for x in arr4.flatten():print(x)
广播是numpy执行形状不同数组之间运算的规则。它允许在满足一定条件时自动扩展数组形状,从而完成逐元素运算。
例如:
a = np.array([[1, 2, 3],[4, 5, 6]])b = np.array([10, 20, 30])c = a + bprint(c)
输出结果为:
array([[11, 22, 33],[14, 25, 36]])
这里b的形状是(3,),在与形状为(2, 3)的a相加时,b被隐式扩展为等效的(2, 3)形状。广播的关键在于从尾部开始比较维度:如果维度相同,或其中一个维度为1,则可以广播;否则会抛出错误。
广播机制避免了手动复制数组,减少了内存占用,也让很多向量化表达式更简洁。
numpy提供大量聚合函数,可以沿指定轴或全局执行计算。
arr = np.array([[1, 2, 3],[4, 5, 6]])print(arr.sum())print(arr.mean())
可以通过axis参数指定轴。axis=0表示沿行方向聚合,即对每一列求和;axis=1表示沿列方向聚合,即对每一行求和:
print(arr.sum(axis=0))print(arr.sum(axis=1))
print(arr.max())print(arr.min())
同样可以使用axis参数按轴计算。
print(arr.std())print(arr.var())
这些接口覆盖了大多数基础统计需求,并且能够直接作用于多维数组。
numpy内置了线性代数相关函数,例如矩阵乘法、转置和逆矩阵等。
可以使用@运算符或np.dot:
a = np.array([[1, 2],[3, 4]])b = np.array([[5, 6],[7, 8]])print(a @ b)print(np.dot(a, b))
可以通过.T属性或np.transpose完成:
print(a.T)
from numpy.linalg import inv, detprint(inv(a))print(det(a))
numpy.linalg子模块集中提供线性代数运算能力,适合处理矩阵分解、特征值计算和线性方程求解等任务。
对于刚开始接触科学计算的开发者,建议按照以下路径练习。
先熟悉数组创建与形状:掌握np.array、np.arange、np.zeros、np.ones和np.linspace的基本用法,并理解shape、ndim、dtype等属性。
再练习索引与切片:重点训练多维数组的轴访问方式,能够快速定位子数组。
理解广播机制:尝试让不同形状的数组进行运算,观察哪些组合能够广播,哪些会报错。
使用聚合函数处理数据:对随机生成的数组执行求和、均值、最值、标准差等操作,并比较axis参数不同时的结果差异。
结合实际问题练习:例如使用numpy生成模拟数据、计算距离矩阵、实现简单线性回归的数值过程等。
numpy的价值不仅在于提供了高效数组结构,更在于它改变了很多数值计算的编写方式:从显式循环转向向量化表达。这种思维方式也会影响后续使用更高层数据处理工具或机器学习框架时的编程习惯。掌握numpy的基础概念,对后续深入学习科学计算、数据分析和机器学习都有直接帮助。