NumPy(Numerical Python)是Python科学计算的核心基础库 ,专为数值计算优化设计,提供了高性能的多维数组对象ndarray,以及配套的数组操作、数学计算、线性代数、随机数生成等功能。它解决了Python原生列表在数值计算中效率低、无向量化操作、缺乏数学工具的痛点,是Pandas、Matplotlib、Scikit-learn、TensorFlow等数据分析、可视化、机器学习库的底层依赖,掌握NumPy是Python数值计算和数据分析的必备基础。
本文将从安装、核心对象、基础操作、核心特性、常用函数、输入输出、实战最佳实践七个维度,全面讲解NumPy的所有核心知识点,所有示例均为可直接运行的极简代码,兼顾理解性和实用性。
一、NumPy安装与快速入门
1. 安装方式(pip/conda,二选一)
NumPy并非Python内置库,需手动安装,推荐使用以下命令:
bash
# pip安装(通用,适合纯Python环境)
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple # 国内源加速
# conda安装(适合Anaconda/Miniconda数据分析环境,自动解决依赖)
conda install numpy
2. 快速入门:Hello NumPy
通过简单示例感受NumPy与Python原生列表的区别,核心优势:向量化操作、无需循环、效率更高。
python
import numpy as np # 导入NumPy,约定别名np(行业通用,必须遵守)
# 1. Python原生列表:计算每个元素的平方,需循环
python_list = [1, 2, 3, 4, 5]
list_square = [x ** 2 for x in python_list]
print("Python列表平方:", list_square) # [1, 4, 9, 16, 25]
# 2. NumPy数组:直接向量化操作,无需循环
np_array = np.array([1, 2, 3, 4, 5])
np_square = np_array ** 2
print("NumPy数组平方:", np_square) # [ 1 4 9 16 25]
# 3. 快速数学计算(求和、均值、标准差)
print("求和:", np_array.sum()) # 15
print("均值:", np_array.mean()) # 3.0
print("标准差:", np_array.std()) # 1.41421356
二、NumPy核心对象:ndarray多维数组
ndarray(N-dimensional array)是NumPy的核心数据结构 ,表示同构的多维数组(所有元素类型相同),这是其与Python原生列表(异构,可存不同类型数据)的核心区别,也是NumPy高效的关键原因。
1. ndarray的核心优势
- 同构存储:元素类型统一,内存连续分配,访问速度远快于原生列表;
- 向量化操作:直接对整个数组进行数学运算,无需显式循环,代码简洁且效率提升10~100倍;
- 多维支持:天然支持一维、二维、三维及更高维数组,完美适配矩阵、张量等数值计算场景;
- 丰富方法:内置大量数组操作、数学计算方法,无需手动实现;
- 低内存占用:相比原生列表,存储相同数据的内存占用大幅降低(如存储1000个整数,列表占用约8000字节,ndarray仅约4000字节)。
2. ndarray的创建方式(6种常用方式)
方式1:从Python原生数据结构转换(列表/元组)------最常用
通过np.array()将Python列表、元组(或嵌套列表/元组)转换为ndarray,自动推断元素类型。
python
import numpy as np
# 一维数组:从列表转换
arr1d = np.array([1, 2, 3, 4, 5])
# 二维数组:从嵌套列表转换(矩阵,行×列)
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 三维数组:从三层嵌套列表转换(张量,页×行×列)
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("一维数组:\n", arr1d, "\n维度:", arr1d.ndim)
print("二维数组:\n", arr2d, "\n维度:", arr2d.ndim)
print("三维数组:\n", arr3d, "\n维度:", arr3d.ndim)
方式2:创建固定值数组(全0/全1/空数组/指定值)
适用于初始化数组,指定形状即可,无需手动构造列表,常用在矩阵初始化、占位符场景。
python
import numpy as np
# 全0数组:np.zeros(shape, dtype),shape为形状(整数/元组),dtype为数据类型
zeros_arr = np.zeros((2, 3), dtype=np.float32) # 2行3列的全0浮点数组
# 全1数组:np.ones(shape, dtype)
ones_arr = np.ones(5, dtype=np.int64) # 一维5个1的整数数组
# 空数组:np.empty(shape),初始化内存(值为随机垃圾值),比zeros/ones更快
empty_arr = np.empty((3, 2))
# 指定值数组:np.full(shape, fill_value),所有元素为fill_value
full_arr = np.full((2, 2), 99) # 2行2列全为99的数组
print("全0数组:\n", zeros_arr)
print("全1数组:", ones_arr)
print("指定值数组:\n", full_arr)
方式3:创建有序数值数组(arange/linspace)
替代Python的range(),支持浮点数,可创建等步长/等份数的有序数组,适用于生成序列、坐标轴数据。
python
import numpy as np
# np.arange(start, stop, step):左闭右开,步长可设为浮点数(区别于range)
arr_arange1 = np.arange(0, 10, 2) # [0 2 4 6 8]
arr_arange2 = np.arange(5) # 省略start,默认从0开始:[0 1 2 3 4]
arr_arange3 = np.arange(1.5, 5.5, 1.0) # 浮点数步长:[1.5 2.5 3.5 4.5]
# np.linspace(start, stop, num):左闭右闭,生成num个等间距数值(重点)
arr_linspace = np.linspace(0, 1, 5) # 0到1之间5个等间距数:[0. 0.25 0.5 0.75 1. ]
# 拓展:logspace------生成等对数间距数组(适用于对数坐标)
arr_logspace = np.logspace(0, 2, 3) # 10^0到10^2之间3个值:[ 1. 10. 100.]
print("arange:", arr_arange1)
print("linspace:", arr_linspace)
方式4:创建随机数数组(np.random)------实战高频
NumPy的np.random模块提供了丰富的随机数生成功能,支持均匀分布、正态分布、整数随机等,适用于模拟数据、随机采样、机器学习初始化等场景。
python
import numpy as np
# 1. 均匀分布:np.random.rand(shape) → [0,1)之间的随机浮点数
rand_arr = np.random.rand(2, 3) # 2行3列均匀分布随机数
# 2. 标准正态分布:np.random.randn(shape) → 均值0,方差1的正态分布
randn_arr = np.random.randn(3, 2) # 3行2列标准正态分布
# 3. 整数随机:np.random.randint(low, high, size) → [low,high)之间的随机整数
randint_arr = np.random.randint(0, 10, size=(2, 2)) # 2行2列0~9的随机整数
# 4. 固定随机种子:np.random.seed(n) → 保证随机数可复现(重要)
np.random.seed(42) # 种子值任意,固定后每次运行生成的随机数相同
fixed_rand = np.random.rand(3) # 固定结果:[0.37454012 0.95071431 0.73199394]
print("均匀分布随机数:\n", rand_arr)
print("随机整数:\n", randint_arr)
print("固定种子随机数:", fixed_rand)
方式5:创建单位矩阵/对角矩阵
适用于线性代数计算,单位矩阵(主对角线为1,其余为0)、对角矩阵(仅对角线有值)是线性代数的基础。
python
import numpy as np
# 单位矩阵:np.eye(n, m=None) → n行m列,主对角线为1(m省略则为n阶方阵)
eye_arr = np.eye(3) # 3阶单位矩阵
eye_arr2 = np.eye(2, 3) # 2行3列单位矩阵
# 对角矩阵:np.diag(v) → v为列表/数组,生成以v为对角线的方阵
diag_arr = np.diag([1, 2, 3]) # 3阶对角矩阵,对角线为1,2,3
print("3阶单位矩阵:\n", eye_arr)
print("对角矩阵:\n", diag_arr)
方式6:从文件加载(后续第六部分详细讲解)
通过np.loadtxt()、np.genfromtxt()加载文本文件(如csv、txt),np.load()加载NumPy专用格式文件(npy/npz),适用于实战中加载外部数据。
3. ndarray的核心属性(必记)
ndarray提供了6个核心属性,用于快速获取数组的基本信息,无需手动计算,是操作数组的基础。
python
import numpy as np
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.float64)
# 1. ndim → 数组的维度(阶数)
print("维度:", arr.ndim) # 2(二维数组)
# 2. shape → 数组的形状,返回元组:(行, 列, 页,...)
print("形状:", arr.shape) # (2, 4) → 2行4列
# 3. size → 数组的总元素个数(shape各维度的乘积)
print("总元素数:", arr.size) # 8
# 4. dtype → 数组的元素数据类型(NumPy专属类型,如np.int64、np.float32)
print("数据类型:", arr.dtype) # float64
# 5. itemsize → 单个元素占用的字节数(如float64占8字节,int32占4字节)
print("单个元素字节数:", arr.itemsize) # 8
# 6. nbytes → 数组占用的总字节数(size × itemsize)
print("总字节数:", arr.nbytes) # 64
4. NumPy的常用数据类型(dtype)
NumPy提供了丰富的数值类型,核心是整数型、浮点型、布尔型 ,可通过dtype参数指定,或通过astype()转换,选择合适的类型能节省内存并提升效率。
常用dtype对照表(重点掌握)
| 类型标识 | 描述 | 字节数 | 适用场景 |
|---|---|---|---|
| np.int32 | 32位整数 | 4 | 常规整数计算(无大数值需求) |
| np.int64 | 64位整数 | 8 | 大数值整数计算(避免溢出) |
| np.float32 | 32位浮点 | 4 | 常规浮点计算(内存敏感场景) |
| np.float64 | 64位浮点 | 8 | 高精度浮点计算(默认,推荐) |
| np.bool_ | 布尔型 | 1 | 条件判断、掩码筛选 |
| np.str_ | 字符串型 | 可变 | 存储字符串(尽量避免,用Pandas) |
数据类型转换:astype()
astype()是安全的类型转换方法,返回新数组(原数组不变),支持所有常用类型转换。
python
import numpy as np
# 整数转浮点
arr_int = np.array([1, 2, 3])
arr_float = arr_int.astype(np.float64)
# 浮点转整数(直接截断小数部分,非四舍五入)
arr_float2 = np.array([1.9, 2.1, 3.5])
arr_int2 = arr_float2.astype(np.int32)
# 数值转布尔(0→False,非0→True)
arr_bool = arr_int.astype(np.bool_)
print("整数转浮点:", arr_float, arr_float.dtype) # [1. 2. 3.] float64
print("浮点转整数:", arr_int2, arr_int2.dtype) # [1 2 3] int32
print("数值转布尔:", arr_bool, arr_bool.dtype) # [ True True True] bool_
三、ndarray基础操作(核心,实战高频)
1. 索引与切片:获取/修改数组元素
NumPy的索引与切片语法与Python原生列表高度相似 ,但支持多维索引 ,是获取数组子集、修改元素的核心操作,分为基础索引切片、花式索引、布尔索引三类,覆盖所有场景。
(1)基础索引切片(一维/二维/三维)
- 一维数组:与Python列表完全一致,
arr[start:stop:step](左闭右开); - 二维数组:
arr[行索引, 列索引],行/列均可单独切片,逗号分隔; - 三维数组:
arr[页索引, 行索引, 列索引],依次按维度切片。
核心特性 :基础切片返回的是原数组的视图(view),修改视图会同步修改原数组(节省内存,避免拷贝)。
python
import numpy as np
# 一维数组切片
arr1d = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print("一维切片(2~8,步长2):", arr1d[2:9:2]) # [2 4 6 8]
print("一维逆序:", arr1d[::-1]) # [9 8 7 6 5 4 3 2 1 0]
# 二维数组切片(重点,矩阵操作)
arr2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print("取第2行:", arr2d[1]) # [5 6 7 8](行索引从0开始)
print("取第1列:", arr2d[:, 0]) # [1 5 9](:表示所有行)
print("取前2行,后2列:\n", arr2d[:2, 2:]) # [[3 4],[7 8]]
print("取第2行第3列元素:", arr2d[1, 2]) # 7(单个元素,标量)
# 视图特性:修改切片会改变原数组
slice_arr = arr2d[:2, :2]
slice_arr[:] = 0 # 切片所有元素设为0
print("修改视图后原数组:\n", arr2d)
# 结果:[[ 0 0 3 4],[ 0 0 7 8],[ 9 10 11 12]]
(2)花式索引(Fancy Indexing):整数数组索引
通过整数列表/数组 指定要获取的索引,适用于非连续、任意顺序 的元素获取,返回的是原数组的拷贝(修改不会影响原数组)。
python
import numpy as np
arr1d = np.arange(10)
arr2d = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
# 一维花式索引:取索引1、3、5的元素
print("一维花式索引:", arr1d[[1, 3, 5]]) # [1 3 5]
# 二维花式索引:取第0、2、3行,第1列的元素
print("二维花式索引:", arr2d[[0, 2, 3], 1]) # [2 6 8]
# 二维花式索引:取第1、3行,第0、1列(形成新矩阵)
print("二维花式索引(多行多列):\n", arr2d[[1, 3]][:, [0, 1]]) # [[3 4],[7 8]]
(3)布尔索引(Boolean Indexing):条件筛选
通过与原数组形状相同的布尔数组 筛选元素,适用于按条件过滤数据 (实战最常用,如筛选大于0、小于均值的元素),返回的是拷贝。
python
import numpy as np
arr = np.array([[1, -2, 3], [-4, 5, -6], [7, -8, 9]])
# 生成布尔数组:判断元素是否大于0
bool_arr = arr > 0
print("布尔数组:\n", bool_arr)
# 布尔索引:筛选所有大于0的元素(返回一维数组)
positive_arr = arr[bool_arr]
print("大于0的元素:", positive_arr) # [1 3 5 7 9]
# 直接简写(实战常用):一行完成条件筛选
negative_arr = arr[arr < 0]
print("小于0的元素:", negative_arr) # [-2 -4 -6 -8]
# 多条件筛选:用&(且)、|(或)、~(非),条件需加括号
cond_arr = arr[(arr > 0) & (arr < 8)]
print("大于0且小于8的元素:", cond_arr) # [1 3 5 7]
2. 形状操作:修改数组的维度/形状
实战中常需根据需求修改数组形状(如将一维数组转为二维矩阵、将三维张量展平为一维),NumPy提供了5种核心形状操作方法,均不改变原数组 (除resize),返回新数组/视图。
| 方法 | 核心作用 | 关键特性 | 适用场景 |
|---|---|---|---|
| reshape() | 改变数组形状 | 返回视图,支持-1(自动计算维度) | 任意形状转换(推荐) |
| flatten() | 展平为一维数组 | 返回拷贝,修改不影响原数组 | 需独立展平数组时 |
| ravel() | 展平为一维数组 | 返回视图,修改影响原数组 | 仅展平,无需独立数组时(高效) |
| transpose()/T | 数组转置 | 返回视图,二维用T更简洁 | 矩阵转置、维度交换 |
| resize() | 原地修改形状 | 无返回值,直接修改原数组 | 需覆盖原数组形状时 |
核心技巧 :reshape()中的-1表示自动计算该维度的大小(根据总元素数和其他维度),是实战中最常用的简化写法。
python
import numpy as np
arr = np.arange(12) # 一维数组:[0 1 2 ... 11],size=12
# 1. reshape:一维转二维(3行4列)
arr2d = arr.reshape(3, 4)
# reshape用-1:自动计算行(总元素12/列4=3行)
arr2d_1 = arr.reshape(-1, 4)
# 一维转三维(2页×3行×2列),-1自动计算列
arr3d = arr.reshape(2, 3, -1)
print("一维转二维:\n", arr2d)
print("三维数组形状:", arr3d.shape) # (2, 3, 2)
# 2. 展平数组:flatten(拷贝)vs ravel(视图)
flat_arr = arr2d.flatten()
ravel_arr = arr2d.ravel()
flat_arr[0] = 99 # 修改拷贝,原数组不变
ravel_arr[1] = 88 # 修改视图,原数组同步改变
print("修改视图后原二维数组:\n", arr2d)
# 3. 转置:二维数组用T(简洁),高维用transpose
arr2d_T = arr2d.T # 二维转置:4行3列
arr3d_T = arr3d.transpose(1, 0, 2) # 三维转置:交换0和1维度
print("二维数组转置:\n", arr2d_T)
# 4. resize:原地修改(无返回值)
arr.resize(4, 3)
print("原地修改形状后:\n", arr)
3. 数组的拼接与分割
(1)数组拼接:将多个数组合并为一个
NumPy提供了通用拼接 np.concatenate()和简化拼接 np.vstack()/np.hstack(),核心是指定拼接轴(axis):
axis=0:垂直拼接(按行),要求数组列数相同(二维);axis=1:水平拼接(按列),要求数组行数相同(二维);- 一维数组默认按
axis=0拼接。
python
import numpy as np
# 二维数组准备
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
# 1. 通用拼接:np.concatenate([arr1, arr2], axis=0/1)
v_concat = np.concatenate([arr1, arr2], axis=0) # 垂直拼接
h_concat = np.concatenate([arr1, arr2], axis=1) # 水平拼接
# 2. 简化拼接:vstack(垂直)、hstack(水平)(推荐,无需记axis)
v_stack = np.vstack([arr1, arr2])
h_stack = np.hstack([arr1, arr2])
print("垂直拼接:\n", v_stack)
print("水平拼接:\n", h_stack)
# 一维数组拼接
arr3 = np.array([1, 2])
arr4 = np.array([3, 4])
print("一维拼接:", np.hstack([arr3, arr4])) # [1 2 3 4]
(2)数组分割:将一个数组拆分为多个
与拼接对应,提供通用分割 np.split()和简化分割 np.vsplit()/np.hsplit(),指定分割轴 和分割点即可。
python
import numpy as np
arr = np.arange(12).reshape(4, 3) # 4行3列数组
# 1. 通用分割:np.split(arr, 分割数/分割点, axis=0/1)
arr_list1 = np.split(arr, 2, axis=0) # 垂直分割为2个数组(各2行)
arr_list2 = np.split(arr, [1, 3], axis=1) # 水平分割,在第1、3列处分割
# 2. 简化分割:vsplit(垂直)、hsplit(水平)
v_split = np.vsplit(arr, 2)
h_split = np.hsplit(arr, 3) # 水平分割为3个数组(各1列)
print("垂直分割为2个:\n", arr_list1[0], "\n", arr_list1[1])
print("水平分割为3个:", h_split)
4. 数组的复制:视图(view)vs 拷贝(copy)
NumPy中数组的"复制"分为视图 和拷贝,这是极易混淆的点,直接影响内存使用和数据修改,必须明确区分:
(1)视图(View)------浅拷贝
- 定义:仅复制数组的元数据(形状、维度、dtype),不复制实际数据,数据与原数组共享同一块内存;
- 特性:修改视图会同步修改原数组,创建视图速度快、内存占用低;
- 产生场景:基础切片、
ravel()、transpose()/T、reshape()(大部分情况)。
(2)拷贝(Copy)------深拷贝
- 定义:完全复制数组的元数据和实际数据,创建新的内存空间,与原数组完全独立;
- 特性:修改拷贝不会影响原数组,创建拷贝速度慢、内存占用高;
- 产生场景:花式索引、布尔索引、
flatten()、arr.copy()(显式拷贝,推荐)、数组运算。
示例:视图与拷贝的区别
python
import numpy as np
arr = np.array([1, 2, 3, 4])
# 1. 视图:基础切片
view_arr = arr[1:3]
view_arr[:] = 99 # 修改视图
print("修改视图后原数组:", arr) # [ 1 99 99 4](同步修改)
# 2. 拷贝:显式copy()
copy_arr = arr.copy()
copy_arr[:] = 0 # 修改拷贝
print("修改拷贝后原数组:", arr) # [ 1 99 99 4](无影响)
# 3. 拷贝:布尔索引
bool_copy = arr[arr > 50]
bool_copy[:] = 100
print("布尔索引拷贝修改后原数组:", arr) # [ 1 99 99 4](无影响)
实战建议 :若需独立使用数组子集,显式调用arr.copy() 创建拷贝,避免因视图修改导致原数组数据混乱。
四、NumPy核心特性:向量化操作与广播机制
这是NumPy高效的核心根源,也是与Python原生列表的本质区别,掌握这两个特性,才能真正写出简洁、高效的NumPy代码。
1. 向量化操作(Vectorization)
定义
无需显式编写for循环,直接对整个数组进行数学运算(加减乘除、幂运算、三角函数等),NumPy会自动将运算应用到每个元素上,这种操作称为向量化操作。
核心优势
- 代码简洁:省去循环代码,一行完成批量运算;
- 效率极高 :向量化操作由C语言底层实现,比Python原生循环快10~100倍(数据量越大,优势越明显);
- 支持所有数学运算:算术运算、比较运算、数学函数均支持向量化。
示例:向量化操作vs Python原生循环
python
import numpy as np
import time
# 生成大数组(100万个元素),模拟实战场景
np_arr = np.arange(10**6)
py_list = list(range(10**6))
# 1. NumPy向量化操作:计算平方
start = time.time()
np_square = np_arr ** 2
print("向量化操作耗时:", time.time() - start, "秒") # 约0.001秒
# 2. Python原生循环:计算平方
start = time.time()
py_square = [x ** 2 for x in py_list]
print("原生循环耗时:", time.time() - start, "秒") # 约0.1秒(慢100倍)
# 其他向量化操作示例
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print("加法:", a + b) # [5 7 9]
print("乘法:", a * b) # [4 10 18](元素级乘法,非矩阵乘法)
print("幂运算:", a ** 2) # [1 4 9]
print("三角函数:", np.sin(a)) # [0.84147098 0.90929743 0.14112001]
print("比较运算:", a > 2) # [False False True]
2. 广播机制(Broadcasting)
定义
当对形状不同的数组进行向量化操作时,NumPy会自动扩展数组的形状,使它们满足"可广播"条件,然后进行元素级运算,这种自动扩展机制称为广播。
核心价值
无需手动扩展数组形状(避免不必要的数据拷贝),即可对不同形状的数组进行运算,进一步简化代码并提升效率。
广播的3条核心规则(必须遵守,否则报错)
NumPy会从后往前逐维度比较两个数组的形状,只有满足以下规则,才能进行广播:
- 维度相同:两个数组的对应维度大小相同;
- 其中一个维度为1:若对应维度大小不同,其中一个必须为1,NumPy会将该维度扩展为另一个数组的维度大小;
- 维度缺失 :若一个数组的维度数少于另一个,自动在其前面补1,再按规则1、2判断。
简单记:从后比,要么相等,要么有一个是1。
常见广播示例(实战高频)
python
import numpy as np
# 示例1:标量与数组广播(最常用)
a = np.array([1, 2, 3])
b = 2
print(a + b) # [3 4 5] → 标量b被广播为[2,2,3]?不,[2,2,2]
# 示例2:一维数组与二维数组广播
a = np.array([[1, 2, 3], [4, 5, 6]]) # (2,3)
b = np.array([10, 20, 30]) # (3,) → 补1为(1,3) → 广播为(2,3)
print(a + b) # [[11 22 33],[14 25 36]]
# 示例3:两个数组均需广播
a = np.array([[1], [2], [3]]) # (3,1)
b = np.array([10, 20]) # (2,) → 补1为(1,2)
# a广播为(3,2),b广播为(3,2),再运算
print(a + b) # [[11 21],[12 22],[13 23]]
# 示例4:不满足广播规则(报错)
c = np.array([[1, 2], [3, 4]]) # (2,2)
d = np.array([1, 2, 3]) # (3,) → 补1为(1,3),2≠3,报错
# print(c + d) # ValueError: operands could not be broadcast together with shapes (2,2) (1,3)
五、NumPy常用函数(分模块,实战全覆盖)
NumPy提供了上千个内置函数 ,覆盖数值计算、线性代数、统计分析、随机数、逻辑判断等所有场景,无需手动实现。以下按实战使用频率分类讲解核心函数,均为必记内容。
1. 基础数学函数(np.xxx)
覆盖所有常用数学运算,均支持向量化操作,直接作用于整个数组。
python
import numpy as np
arr = np.array([1, -2, 3, -4, 5])
# 绝对值、平方、开方
print("绝对值:", np.abs(arr)) # [1 2 3 4 5]
print("平方:", np.square(arr)) # [ 1 4 9 16 25]
print("开方:", np.sqrt(np.abs(arr))) # [1. 1.41421356 1.73205081 2. 2.23606798]
# 指数、对数(np.exp: e^x;np.log: 自然对数;np.log10: 以10为底)
print("指数:", np.exp([1, 2, 3])) # [ 2.71828183 7.3890561 20.78460969]
print("自然对数:", np.log([1, e, e**2])) # [0. 1. 2.]
# 三角函数、反三角函数
print("正弦:", np.sin(np.pi/2)) # 1.0
print("反正切:", np.arctan(1)) # 0.7853981633974483(π/4)
# 取整函数(np.round: 四舍五入;np.ceil: 向上取整;np.floor: 向下取整;np.trunc: 截断小数)
arr_float = np.array([1.2, 1.9, -2.3, -2.8])
print("四舍五入:", np.round(arr_float)) # [ 1. 2. -2. -3.]
print("向上取整:", np.ceil(arr_float)) # [ 2. 2. -2. -2.]
print("向下取整:", np.floor(arr_float)) # [ 1. 1. -3. -3.]
2. 统计函数(np.xxx/arr.xxx,两种调用方式)
用于数组的统计分析,核心支持按指定维度计算 (axis参数),是数据分析的基础,两种调用方式完全等价(np.sum(arr) = arr.sum())。
核心统计函数+axis参数使用(重点)
python
import numpy as np
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 全局统计(无axis)
print("全局求和:", arr2d.sum()) # 45
print("全局均值:", arr2d.mean()) # 5.0
print("全局最大值:", arr2d.max()) # 9
print("全局最小值:", arr2d.min()) # 1
print("方差:", arr2d.var()) # 6.666666666666667
print("标准差:", arr2d.std()) # 2.581988897471611
print("中位数:", np.median(arr2d)) # 5.0(注意:中位数只有np.xxx方式)
print("求和积:", arr2d.prod()) # 362880(1×2×3×...×9)
# 按维度统计(axis=0:按行,列维度聚合;axis=1:按列,行维度聚合)
print("按行求和(每列的和):", arr2d.sum(axis=0)) # [12 15 18]
print("按列求均值(每行的均值):", arr2d.mean(axis=1)) # [2. 5. 8.]
print("按行求最大值(每列的最大值):", arr2d.max(axis=0)) # [7 8 9]
# 拓展:找最大/最小值的索引(argmax/argmin)
print("全局最大值索引:", arr2d.argmax()) # 8(一维索引)
print("按列求最小值索引(每行的最小值索引):", arr2d.argmin(axis=1)) # [0 0 0]
3. 线性代数函数(np.linalg.xxx)
NumPy的np.linalg模块是线性代数计算的核心,提供了矩阵乘法、逆矩阵、行列式、特征值等所有线性代数常用操作,适用于矩阵计算、机器学习模型求解等场景。
注意 :NumPy中数组的*是元素级乘法 ,矩阵乘法需用np.dot()或@(Python3.5+,推荐)。
python
import numpy as np
from numpy import linalg as la # 别名,简化调用
# 矩阵定义(二维数组)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
v = np.array([1, 2])
# 1. 矩阵乘法:np.dot(A,B) / A @ B
print("矩阵乘法:\n", A @ B) # [[19 22],[43 50]]
# 矩阵与向量乘法
print("矩阵与向量乘法:", A @ v) # [5 11]
# 2. 逆矩阵:la.inv(A)(仅方阵可求逆,且行列式≠0)
A_inv = la.inv(A)
print("A的逆矩阵:\n", A_inv)
print("A × A逆 = 单位矩阵:\n", np.round(A @ A_inv)) # [[1. 0.],[0. 1.]]
# 3. 行列式:la.det(A)
print("A的行列式:", la.det(A)) # -2.0000000000000004
# 4. 特征值与特征向量:la.eig(A)
eigenvalues, eigenvectors = la.eig(A)
print("特征值:", eigenvalues) # [-0.37228132 5.37228132]
print("特征向量:\n", eigenvectors)
# 5. 转置(简单操作,用A.T即可)
print("A的转置:\n", A.T) # [[1 3],[2 4]]
4. 逻辑与条件函数(实战高频)
用于数组的条件判断、值替换,替代繁琐的循环条件,核心是np.where()(三目运算符向量化)。
python
import numpy as np
arr = np.array([1, -2, 3, -4, 5, -6])
# 1. np.where(条件, 满足条件的值, 不满足条件的值) → 三目运算符向量化(实战最常用)
# 示例:将负数替换为0,正数保持不变
new_arr = np.where(arr > 0, arr, 0)
print("负数替换为0:", new_arr) # [1 0 3 0 5 0]
# 示例:将大于3的数设为10,小于-2的设为-10,其余保持不变
new_arr2 = np.where(arr > 3, 10, np.where(arr < -2, -10, arr))
print("多条件替换:", new_arr2) # [ 1 -2 3 -10 10 -10]
# 2. np.any():任意元素满足条件返回True;np.all():所有元素满足条件返回True
print("是否有正数:", np.any(arr > 0)) # True
print("是否所有元素都大于0:", np.all(arr > 0)) # False
# 3. np.unique():去重并排序(返回去重后的数组+索引+计数,实战常用)
arr_dup = np.array([3, 1, 2, 3, 1, 2, 4])
unique_arr, counts = np.unique(arr_dup, return_counts=True)
print("去重数组:", unique_arr) # [1 2 3 4]
print("元素计数:", counts) # [2 2 2 1]
# 4. np.clip():限制数组元素的范围(超出范围则截断)
arr_clip = np.array([1, -2, 3, 8, 5])
clipped_arr = np.clip(arr_clip, 0, 5) # 最小值0,最大值5
print("范围限制后:", clipped_arr) # [1 0 3 5 5]
5. 随机数函数(np.random.xxx,补充)
除了基础的随机数生成,np.random还有两个实战高频函数:打乱数组 、随机选择。
python
import numpy as np
np.random.seed(42) # 固定种子,可复现
arr = np.arange(10)
# 1. np.random.shuffle():原地打乱数组(一维/二维)
np.random.shuffle(arr)
print("打乱后数组:", arr) # [6 3 7 4 5 0 1 2 9 8]
# 2. np.random.choice():从数组中随机选择元素
# choice(数组, 选择个数, replace=True/False(是否可重复), p=概率分布)
sample1 = np.random.choice(arr, 3) # 随机选3个,可重复
sample2 = np.random.choice(arr, 3, replace=False) # 随机选3个,不重复
sample3 = np.random.choice([0,1], 5, p=[0.2, 0.8]) # 按概率选(0占20%,1占80%)
print("随机选择3个(可重复):", sample1)
print("随机选择3个(不重复):", sample2)
print("按概率选择:", sample3)
六、NumPy数组的输入与输出(IO操作)
实战中常需将NumPy数组保存到文件 或从文件加载数组 ,NumPy提供了专门的IO函数,支持专用格式(npy/npz) 和文本格式(csv/txt),兼顾效率和可读性。
1. 保存/加载NumPy专用格式(npy/npz)------推荐
- npy :保存单个 ndarray数组,二进制格式,保存/加载速度最快,不丢失数组属性(shape、dtype等);
- npz :保存多个ndarray数组,压缩二进制格式,自动将数组封装为字典。
python
import numpy as np
# 准备数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([[4, 5], [6, 7]])
# 1. 保存单个数组:np.save(文件名, 数组) → 自动加.npy后缀
np.save("single_arr.npy", arr1)
# 2. 保存多个数组:np.savez(文件名, 数组1名=数组1, 数组2名=数组2) → 自动加.npz后缀
np.savez("multi_arr.npz", arr1=arr1, arr2=arr2)
# 3. 加载单个数组:np.load(文件名)
loaded_arr1 = np.load("single_arr.npy")
print("加载的单个数组:", loaded_arr1)
# 4. 加载多个数组:np.load(文件名) → 返回字典,通过键获取数组
loaded_multi = np.load("multi_arr.npz")
print("加载的多个数组-arr1:", loaded_multi["arr1"])
print("加载的多个数组-arr2:", loaded_multi["arr2"])
2. 保存/加载文本格式(csv/txt)------易读性强
适用于需要人工查看 或与其他语言/工具交互 的场景,核心函数np.savetxt()(保存)、np.loadtxt()(加载),支持指定分隔符、数据类型、跳过行等。
python
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 1. 保存为文本文件:np.savetxt(文件名, 数组, delimiter=分隔符, fmt=格式)
np.savetxt("arr.csv", arr, delimiter=",", fmt="%d") # 逗号分隔,整数格式
np.savetxt("arr.txt", arr, delimiter="\t", fmt="%.2f") # 制表符分隔,保留2位小数
# 2. 从文本文件加载:np.loadtxt(文件名, delimiter=分隔符, dtype=数据类型)
loaded_csv = np.loadtxt("arr.csv", delimiter=",", dtype=np.int32)
loaded_txt = np.loadtxt("arr.txt", delimiter="\t", dtype=np.float32)
print("从csv加载:\n", loaded_csv)
print("从txt加载:\n", loaded_txt)
# 拓展:加载带表头的csv → skiprows=1(跳过第一行)
# np.loadtxt("with_header.csv", delimiter=",", skiprows=1)
七、NumPy实战最佳实践(避坑+效率提升)
结合实战经验,总结10条NumPy核心最佳实践,帮助你写出高效、健壮、易维护的代码,规避常见坑点。
1. 始终使用import numpy as np
这是Python数据分析领域的行业通用约定 ,所有第三方库(Pandas、Scikit-learn)均遵循,使用别名np可大幅简化代码,提升可读性。
2. 优先使用向量化操作,彻底抛弃Python原生循环
这是NumPy效率的核心,任何需要循环遍历数组的场景,都有对应的向量化解决方案 (如条件判断用np.where(),统计用arr.sum()),数据量越大,向量化优势越明显。
3. 合理选择数据类型(dtype),节省内存
- 常规整数计算用
np.int32,大数值用np.int64,避免默认的int64浪费内存; - 常规浮点计算用
np.float32(如机器学习模型训练),高精度计算用np.float64(NumPy默认,推荐); - 避免用NumPy存储字符串,字符串处理优先使用Pandas的
str方法。
4. 明确区分视图(view)和拷贝(copy),显式拷贝用arr.copy()
- 基础切片返回视图,若需独立使用子集,务必显式调用
arr.copy()创建拷贝,避免修改视图导致原数组数据混乱; - 花式索引、布尔索引返回拷贝,可直接修改,无需额外拷贝。
5. 利用reshape(-1)快速展平数组,替代flatten()/ravel()
reshape(-1)是通用的展平方法,支持任意维度数组展平为一维,且返回视图(高效),是实战中展平数组的首选:
python
arr = np.array([[1,2],[3,4],[5,6]])
flat_arr = arr.reshape(-1) # [1 2 3 4 5 6](推荐)
6. 矩阵乘法用@或np.dot(),拒绝使用*
NumPy中*是元素级乘法 ,并非矩阵乘法,矩阵乘法必须用@(Python3.5+,简洁推荐)或np.dot(),避免因乘法符号错误导致计算结果错误。
7. 固定随机种子,保证实验可复现
使用np.random.seed(n)(n为任意整数)固定随机数种子,确保每次运行代码生成的随机数完全相同,这是机器学习、模拟实验中保证结果可复现的关键。
8. 优先使用np.vstack()/np.hstack(),替代np.concatenate()
np.vstack()(垂直拼接)、np.hstack()(水平拼接)无需指定axis参数,更符合人类直觉,代码更简洁,且完全等价于np.concatenate(),是实战中数组拼接的首选。
9. 处理缺失值用np.isnan()/np.isfinite(),避免直接比较
NumPy中缺失值用np.nan表示,np.nan == np.nan返回False,无法通过直接比较判断缺失值,必须用专用函数:
python
arr = np.array([1, np.nan, 3, np.inf, 5])
print("缺失值位置:", np.isnan(arr)) # [False True False False False]
print("有限值位置:", np.isfinite(arr)) # [ True False True False True]
10. 大数组运算避免频繁创建中间数组
NumPy的数组运算会创建中间数组(如a + b * c会先创建b*c的中间数组),大数组运算时可通过原地操作 (arr += 1)或指定out参数减少中间数组创建,提升效率:
python
a = np.ones(10**6)
b = np.ones(10**6)
c = np.empty(10**6)
np.add(a, b, out=c) # 将a+b的结果直接存入c,不创建中间数组(推荐)
11. 与Python原生列表转换用tolist(),而非list()
将ndarray转为Python原生列表时,arr.tolist()比list(arr)更高效 ,且支持多维数组转换为嵌套列表,list(arr)仅能将多维数组转为一维列表的嵌套:
python
arr2d = np.array([[1,2],[3,4]])
print(arr2d.tolist()) # [[1,2],[3,4]](推荐,嵌套列表)
print(list(arr2d)) # [array([1,2]), array([3,4])](不推荐)
八、NumPy核心知识点总结
- NumPy是Python科学计算的核心基础库,是Pandas、Matplotlib、机器学习库的底层依赖,核心优势是高性能、向量化、多维支持;
- 核心对象是
ndarray多维数组,同构存储 是其高效的关键,与Python原生列表的核心区别是元素类型统一、内存连续; - ndarray的创建方式包括:
np.array()(列表转换)、np.zeros()/np.ones()(固定值)、np.arange()/np.linspace()(有序值)、np.random(随机数); - 核心属性:
ndim(维度)、shape(形状)、size(元素数)、dtype(数据类型),是操作数组的基础; - 索引与切片支持基础切片、花式索引、布尔索引,布尔索引是实战中条件筛选的首选;
- 向量化操作 和广播机制是NumPy高效的核心,无需循环,直接对整个数组运算,广播需遵守"从后比,相等或为1"的规则;
- 常用函数覆盖数学计算、统计分析、线性代数、随机数、条件判断 ,均支持向量化,
np.where()是实战高频的条件函数; - 数组IO支持npy/npz(高效) 和csv/txt(易读),npy/npz是NumPy专用格式,推荐实战使用;
- 实战最佳实践:优先向量化、合理选择dtype、明确视图/拷贝、矩阵乘法用
@、固定随机种子、高效转换列表。