SciPy 教程
SciPy 教程
SciPy(Scientific Python)是基于 NumPy 的 Python 科学计算库,提供优化、线性代数、积分、插值、信号处理、统计等高级数学功能,是数据科学和科研计算的核心工具。
SciPy 生态
NumPy 数组与基础数值计算 SciPy 高级科学计算(本教程) Matplotlib 数据可视化 Pandas 数据处理与分析 SymPy 符号计算 scikit-learn 机器学习
SciPy 模块
| 模块 | 功能 |
|---|---|
| scipy.constants | 物理常量 |
| scipy.optimize | 优化与求根 |
| scipy.sparse | 稀疏矩阵 |
| scipy.sparse.csgraph | 图结构算法 |
| scipy.spatial | 空间数据(KNN、凸包、距离) |
| scipy.io | Matlab 等格式读写 |
| scipy.interpolate | 插值 |
| scipy.stats | 统计分析 |
快速示例
import numpy as np
from scipy.optimize import minimize
from scipy import stats
# 求函数最小值
result = minimize(lambda x: (x[0]-1)**2 + (x[1]-2)**2,
[0, 0])
print(result.x) # [1. 2.]
# 正态分布
dist = stats.norm(loc=0, scale=1)
print(dist.cdf(1.96)) # 0.975
SciPy 安装
SciPy 安装
1. pip 安装
# 安装 pip install scipy # 或安装科学计算全家桶 pip install numpy scipy matplotlib pandas # 指定版本 pip install scipy==1.13.0
2. conda 安装
conda install scipy # 或 conda install -c conda-forge scipy
3. 验证安装
import scipy print(scipy.__version__) # 1.13.1 # 测试常用功能 from scipy import constants print(constants.pi) # 3.141592653589793 print(constants.c) # 光速 # 检查依赖 import numpy print(numpy.__version__)
4. Jupyter 环境
# Jupyter 中直接使用 # 与 pandas、matplotlib 组合工作 import scipy import numpy as np import matplotlib.pyplot as plt # 交互式绘图 %matplotlib inline
5. 常见问题
# 安装失败
pip install --upgrade pip
pip install numpy --upgrade
pip install scipy
# 版本冲突
# 用虚拟环境或 conda 环境
# 检查构建
python -c "from scipy.optimize import minimize; print('OK')"
SciPy 模块列表
SciPy 模块列表
1. 模块总览
scipy.cluster 聚类(层次聚类、向量量化) scipy.constants 物理与数学常量 scipy.fft 傅里叶变换 scipy.integrate 积分与常微分方程 scipy.interpolate 插值 scipy.io 输入输出(Matlab等) scipy.linalg 线性代数 scipy.ndimage n 维图像处理 scipy.odr 正交距离回归 scipy.optimize 优化与求根 scipy.signal 信号处理 scipy.sparse 稀疏矩阵 scipy.spatial 空间数据结构与算法 scipy.special 特殊函数 scipy.stats 统计
2. 常用模块详解
# 优化 from scipy.optimize import minimize, root, curve_fit # 线性代数 from scipy.linalg import solve, eig, svd # 积分 from scipy.integrate import quad, odeint # 插值 from scipy.interpolate import interp1d, griddata # 统计 from scipy import stats # 信号 from scipy.signal import find_peaks, butter, filtfilt
3. 查看模块内容
# 列出模块所有函数 import scipy.optimize as opt print(dir(opt)) # 查看函数帮助 help(opt.minimize) # 查看文档 scipy.optimize.minimize?
4. 与 NumPy 分工
# NumPy: 数组、基础数学、随机数 # SciPy: 高级算法(优化/积分/统计/信号) # 典型工作流 data = np.array(...) # NumPy 数据 result = scipy.stats.ttest_ind(a, b) # SciPy 分析 plt.plot(...) # Matplotlib 可视化
SciPy 常量模块
SciPy 常量模块
1. 常用常量
from scipy import constants # 数学常量 constants.pi # 3.141592653589793 constants.e # 2.718281828459045 constants.golden # 黄金比例 constants.inf # 无穷 # 物理常量 constants.c # 光速 299792458.0 m/s constants.g # 重力加速度 9.80665 m/s² constants.h # 普朗克常数 constants.k # 玻尔兹曼常数 constants.N_A # 阿伏伽德罗常数 constants.e # 元电荷
2. 单位转换
# 长度 constants.inch # 0.0254 米 constants.mile # 1609.344 米 constants.astronomical_unit # 天文单位 # 质量 constants.pound # 0.45359237 千克 constants.ounce # 0.028349523125 千克 # 时间 constants.minute # 60 秒 constants.hour # 3600 秒 constants.day # 86400 秒 constants.year # 31556952 秒 # 温度 constants.zero_Celsius # 273.15 开尔文 # 压力 constants.atm # 标准大气压(帕斯卡)
3. 前缀单位
# 单位前缀 constants.kilo # 1e3 constants.mega # 1e6 constants.giga # 1e9 constants.milli # 1e-3 constants.micro # 1e-6 constants.nano # 1e-9 # 示例 # 1 兆帕 = 1e6 帕 pressure_pa = 5 * constants.mega
4. 查找常量
# 查找含指定词的常量
constants.find("speed of light")
# ['speed of light', 'speed of light in vacuum']
# 查看物理常量字典
constants.physical_constants["speed of light in vacuum"]
# (299792458.0, 'm s^-1', 0.0)
SciPy 优化器
SciPy 优化器
1. 函数最小值
import numpy as np
from scipy.optimize import minimize
# 目标函数
def f(x):
return (x[0] - 1)**2 + (x[1] - 2)**2
# 最小化
result = minimize(f, [0, 0]) # 初始点
print(result.x) # [1. 2.](最优解)
print(result.fun) # 最小值
print(result.success) # 是否成功
# 带约束
result = minimize(
f, [0, 0],
bounds=[(-5, 5), (-5, 5)] # 变量范围
)
print(result.x)
2. 约束优化
# 不等式约束 x + y >= 1
cons = [{"type": "ineq",
"fun": lambda x: x[0] + x[1] - 1}]
result = minimize(f, [0, 0], constraints=cons)
print(result.x)
# 等式约束 x + y = 1
cons = [{"type": "eq",
"fun": lambda x: x[0] + x[1] - 1}]
result = minimize(f, [0, 1], constraints=cons)
3. 求根(root)
from scipy.optimize import root
# 解方程 f(x) = 0
def func(x):
return x**2 - 4
sol = root(func, 1.0) # 从 1 开始找
print(sol.x) # [2.]
# 多变量方程组
def eqs(vars):
x, y = vars
return [x**2 + y**2 - 1, x - y]
sol = root(eqs, [1, 1])
print(sol.x)
4. 曲线拟合
from scipy.optimize import curve_fit
# 生成带噪声数据
x = np.linspace(0, 10, 50)
true_a, true_b = 2.5, 1.3
y_true = true_a * np.exp(-true_b * x)
y = y_true + np.random.normal(0, 0.1, x.size)
# 拟合函数
def model(x, a, b):
return a * np.exp(-b * x)
popt, pcov = curve_fit(model, x, y)
a, b = popt
print(f"拟合结果: a={a:.2f}, b={b:.2f}")
# 与原参数接近 2.5, 1.3
# 误差
perr = np.sqrt(np.diag(pcov))
print(f"参数误差: {perr}")
5. 全局优化
from scipy.optimize import differential_evolution
# 全局最小值(避免局部最优)
result = differential_evolution(
lambda x: np.sin(x[0]) * x[0] + x[1]**2,
bounds=[(-10, 10), (-10, 10)]
)
print(result.x)
SciPy 稀疏矩阵
SciPy 稀疏矩阵
1. 什么是稀疏矩阵
当矩阵中绝大多数元素为 0 时,用稀疏矩阵存储可节省内存并加速运算。
# 稠密矩阵
import numpy as np
dense = np.array([
[0, 0, 1],
[2, 0, 0],
[0, 3, 0]
])
# 稀疏矩阵(只存非零值)
from scipy.sparse import csr_matrix
sparse = csr_matrix(dense)
print(sparse)
# (0, 2) 1
# (1, 0) 2
# (2, 1) 3
2. 创建稀疏矩阵
from scipy.sparse import csr_matrix, csc_matrix, coo_matrix # 从稠密转换 A = csr_matrix([[1, 0, 0], [0, 2, 0]]) # 从 (行,列,值) 三元组 row = [0, 1, 2] col = [0, 2, 1] data = [10, 20, 30] B = coo_matrix((data, (row, col)), shape=(3, 3)) # 常用格式 csr_matrix # 行压缩(运算快) csc_matrix # 列压缩(列操作快) coo_matrix # 坐标格式(便于构建) dok_matrix # 字典格式(便于赋值)
3. 常用操作
import numpy as np from scipy.sparse import csr_matrix A = csr_matrix([[1, 0, 0], [0, 2, 0], [0, 0, 3]]) # 属性 A.shape # (3, 3) A.nnz # 非零元素数:3 A.data # 非零值数组 # 运算 A + A # 加法 A * A # 矩阵乘法 A.multiply(A) # 逐元素乘法 A.T # 转置 # 转换 A.toarray() # 转稠密 A.todense() # 转矩阵 # 提取 A[0, 0] # 1 A.getrow(1) # 第 1 行
4. 大型稀疏矩阵
# 对角矩阵 from scipy.sparse import diags, eye D = diags([1, 2, 3], [0], shape=(3, 3)) I = eye(5) # 单位稀疏矩阵 # 随机稀疏矩阵 from scipy.sparse import random R = random(1000, 1000, density=0.01) print(R.nnz) # 约 10000 个非零 # 内存对比 print(R.nbytes) # 稀疏存储大小 print(R.toarray().nbytes) # 稠密存储大小
5. 线性方程组求解
from scipy.sparse.linalg import spsolve, eigs # 稀疏求解 Ax = b A = csr_matrix([[4, 1], [1, 3]]) b = np.array([1, 2]) x = spsolve(A, b) print(x) # [0.09... 0.63...] # 特征值(前 k 个) eigenvalues, eigenvectors = eigs(A, k=1) print(eigenvalues)
SciPy 图结构
SciPy 图结构
scipy.sparse.csgraph 提供图论算法,用于处理稀疏矩阵表示的图:最短路径、连通分量、最小生成树等。
1. 图的表示
import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import shortest_path
# 邻接矩阵(0 表示无边)
# 节点: A B C D
# 边: A-B(1) B-C(2) A-D(4) C-D(1)
adj = np.array([
[0, 1, 0, 4], # A
[1, 0, 2, 0], # B
[0, 2, 0, 1], # C
[4, 0, 1, 0] # D
])
graph = csr_matrix(adj)
2. 最短路径
from scipy.sparse.csgraph import shortest_path, dijkstra, floyd_warshall # 所有节点间最短路径 dist = shortest_path(graph, method="auto") print(dist) # [[0. 1. 3. 4.] # [1. 0. 2. 3.] # [3. 2. 0. 1.] # [4. 3. 1. 0.]] # Dijkstra 单源 dist = dijkstra(graph, indices=0) print(dist) # [0. 1. 3. 4.] # Floyd-Warshall(所有对) dist = floyd_warshall(graph) # 返回路径 dist, pred = dijkstra(graph, indices=0, return_predecessors=True)
3. 连通分量
from scipy.sparse.csgraph import connected_components
# 两个连通部分
adj2 = np.array([
[0, 1, 0, 0], # A-B 连通
[1, 0, 0, 0],
[0, 0, 0, 1], # C-D 连通
[0, 0, 1, 0]
])
n_components, labels = connected_components(
csr_matrix(adj2), directed=False)
print(n_components) # 2
print(labels) # [0 0 1 1]
4. 最小生成树
from scipy.sparse.csgraph import minimum_spanning_tree mst = minimum_spanning_tree(csr_matrix(adj)) print(mst.toarray()) # 只保留最小生成树的边 # A-B(1) B-C(2) C-D(1) # 总权重 print(mst.sum()) # 4.0
5. 其他图算法
from scipy.sparse.csgraph import (
breadth_first_order, # BFS
depth_first_order, # DFS
breadth_first_tree, # BFS 树
depth_first_tree, # DFS 树
)
# BFS 遍历顺序
order = breadth_first_order(csr_matrix(adj), 0)[0]
print(order) # [0 1 3 2]
# DFS
order = depth_first_order(csr_matrix(adj), 0)[0]
print(order)
SciPy 空间数据
SciPy 空间数据
scipy.spatial 提供空间数据结构和算法:KD 树(最近邻)、凸包、距离计算、Delaunay 三角剖分等。
1. 距离计算
from scipy.spatial import distance # 两点间距离 p1, p2 = [0, 0], [3, 4] distance.euclidean(p1, p2) # 5.0 distance.manhattan(p1, p2) # 7.0 distance.chebyshev(p1, p2) # 4.0 distance.cosine([1, 0], [0, 1]) # 1.0 # 距离矩阵 points = [[0, 0], [1, 1], [3, 4]] dist_matrix = distance.cdist(points, points) print(dist_matrix)
2. KD 树(最近邻搜索)
from scipy.spatial import KDTree
import numpy as np
# 数据点
data = np.array([
[1, 1], [2, 3], [4, 5],
[5, 2], [3, 4]
])
tree = KDTree(data)
# 查询最近邻
query = [2, 2]
dist, idx = tree.query(query)
print(f"最近点: {data[idx]}, 距离: {dist:.2f}")
# 查询 k 个最近邻
dist, idx = tree.query(query, k=3)
print("最近 3 个:", data[idx])
# 半径搜索
idx = tree.query_ball_point(query, r=2.0)
print("半径内:", data[idx])
# 批量查询
queries = [[0, 0], [5, 5]]
dist, idx = tree.query(queries)
print(idx)
3. 凸包
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
# 随机点集
points = np.random.rand(20, 2) * 10
# 计算凸包
hull = ConvexHull(points)
# 顶点
print(hull.vertices)
# 周长与面积
print(f"周长: {hull.area:.2f}")
print(f"面积: {hull.volume:.2f}")
# 可视化
plt.scatter(points[:, 0], points[:, 1])
for simplex in hull.simplices:
plt.plot(points[simplex, 0], points[simplex, 1], "r-")
plt.show()
4. Delaunay 三角剖分
from scipy.spatial import Delaunay
points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
tri = Delaunay(points)
print(tri.simplices) # 三角形顶点索引
# 判断点是否在三角网内
test = [0.3, 0.3]
in_tri = tri.find_simplex(test) >= 0
print(f"点在三角网内: {in_tri}")
5. 沃罗诺伊图
from scipy.spatial import Voronoi points = np.random.rand(10, 2) * 10 vor = Voronoi(points) # 顶点 print(vor.vertices) # 区域 print(vor.regions)
SciPy Matlab 数组
SciPy Matlab 数组
1. 读取 Matlab 文件
from scipy.io import loadmat
# 读取 .mat 文件
data = loadmat("data.mat")
print(data.keys()) # 变量列表
# 获取变量
x = data["x"]
print(type(x)) # numpy.ndarray
print(x.shape)
2. 写入 Matlab 文件
from scipy.io import savemat
import numpy as np
# 保存多个变量
data = {
"x": np.array([1, 2, 3]),
"y": np.random.rand(3, 3),
"text": "hello"
}
savemat("output.mat", data)
# 读取验证
from scipy.io import loadmat
loaded = loadmat("output.mat")
print(loaded["x"])
3. 其他格式
# scipy.io 支持
loadmat / savemat Matlab .mat
whosmat 查看 .mat 变量名
mmread / mmwrite Matrix Market 格式
# 用 whosmat 只读变量名(不加载数据)
from scipy.io import whosmat
info = whosmat("data.mat")
print(info) # [(name, shape, dtype), ...]
4. 其他文件格式处理
# 科学计算常用格式
import numpy as np
# NPZ(推荐,NumPy 原生)
np.savez("data.npz", x=np.array([1,2,3]),
y=np.array([[1,2],[3,4]]))
d = np.load("data.npz")
print(d["x"])
# CSV(pandas)
import pandas as pd
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
df.to_csv("data.csv", index=False)
# HDF5(大数据,h5py)
# pip install h5py
import h5py
with h5py.File("data.h5", "w") as f:
f.create_dataset("x", data=[1, 2, 3])
SciPy 插值
SciPy 插值
插值(interpolation)是用已知数据点估计中间未知值的方法,scipy.interpolate 提供多种插值工具。
1. 一维插值
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
# 已知数据点
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 4, 9, 16])
# 线性插值
f_linear = interp1d(x, y, kind="linear")
# 三次样条
f_cubic = interp1d(x, y, kind="cubic")
# 新点求值
x_new = 2.5
print(f"线性: {f_linear(x_new):.2f}") # 6.5
print(f"三次: {f_cubic(x_new):.2f}") # 6.56
# 插值方式
kind="linear" 线性
kind="cubic" 三次样条
kind="quadratic" 二次
kind="nearest" 最近邻
kind="zero" 零阶保持
2. 样条插值(样条)
from scipy.interpolate import CubicSpline cs = CubicSpline(x, y) # 平滑曲线 x_smooth = np.linspace(0, 4, 100) y_smooth = cs(x_smooth) # 导数 print(cs(x_new)) # 值 print(cs(x_new, 1)) # 一阶导 print(cs(x_new, 2)) # 二阶导 plt.plot(x, y, "o", label="数据") plt.plot(x_smooth, y_smooth, label="三次样条") plt.legend() plt.show()
3. 多维插值
from scipy.interpolate import griddata
# 不规则散点数据
points = np.random.rand(50, 2) * 10
values = np.sin(points[:, 0]) + np.cos(points[:, 1])
# 网格插值
grid_x, grid_y = np.mgrid[0:10:50j, 0:10:50j]
z = griddata(points, values,
(grid_x, grid_y),
method="cubic") # linear/cubic/nearest
4. 样条插值对象
from scipy.interpolate import UnivariateSpline # 带平滑的样条(可处理噪声) spl = UnivariateSpline(x, y, k=3, s=0.5) # k: 阶数, s: 平滑因子 # 拟合 print(spl(x_new))
5. 应用场景
- 数据补全(缺失值插值)
- 曲线平滑
- 图像缩放(二维插值)
- 数值模拟网格生成
Scipy 显著性检验
SciPy 显著性检验
scipy.stats 提供完整的统计检验工具,用于判断数据差异是否显著。
1. t 检验
from scipy import stats
import numpy as np
# 独立样本 t 检验(两组差异)
group_a = np.array([85, 90, 78, 92, 88])
group_b = np.array([70, 75, 72, 68, 74])
t_stat, p_value = stats.ttest_ind(group_a, group_b)
print(f"t={t_stat:.3f}, p={p_value:.4f}")
# p < 0.05 → 差异显著
if p_value < 0.05:
print("两组差异显著")
else:
print("差异不显著")
# 配对 t 检验(前后对比)
before = np.array([80, 82, 79, 85, 81])
after = np.array([90, 88, 85, 92, 89])
t_stat, p = stats.ttest_rel(before, after)
# 单样本 t 检验
t_stat, p = stats.ttest_1samp(group_a, 80)
2. 卡方检验
# 独立性检验(分类变量)
observed = np.array([
[30, 20], # 男: 喜欢/不喜欢
[25, 25] # 女: 喜欢/不喜欢
])
chi2, p, dof, expected = stats.chi2_contingency(observed)
print(f"chi2={chi2:.3f}, p={p:.4f}")
# 拟合优度
observed = [10, 20, 30]
expected = [20, 20, 20]
chi2, p = stats.chisquare(observed, expected)
3. 方差分析(ANOVA)
# 单因素方差分析(多组比较)
group1 = [85, 88, 90, 82]
group2 = [70, 75, 72, 78]
group3 = [90, 92, 95, 88]
f_stat, p = stats.f_oneway(group1, group2, group3)
print(f"F={f_stat:.3f}, p={p:.4f}")
# p < 0.05 → 至少一组显著不同
4. 非参数检验
# 数据非正态时使用 # Mann-Whitney U(两独立样本) u_stat, p = stats.mannwhitneyu(group_a, group_b) # Wilcoxon(配对) w_stat, p = stats.wilcoxon(before, after) # Kruskal-Wallis(多组) h_stat, p = stats.kruskal(group1, group2, group3) # 符号检验 p = stats.binom_test(8, 10, 0.5)
5. 正态性检验
# Shapiro-Wilk(小样本)
data = np.random.normal(0, 1, 100)
w_stat, p = stats.shapiro(data)
print(f"p={p:.4f}")
# p > 0.05 → 符合正态分布
# D'Agostino K^2
stat, p = stats.normaltest(data)
# Kolmogorov-Smirnov
stat, p = stats.kstest(data, "norm")
# QQ 图可视化
import matplotlib.pyplot as plt
stats.probplot(data, dist="norm", plot=plt)
plt.show()
6. 检验选择指南
# 两独立组,正态 → ttest_ind # 两配对组,正态 → ttest_rel # 多组,正态 → f_oneway # 非正态 → mannwhitneyu / wilcoxon / kruskal # 分类数据 → chi2_contingency # 正态性检查 → shapiro / normaltest
SciPy 总结与资源
SciPy 总结与资源
1. 知识回顾
- 常量:物理常量与单位转换
- 优化:minimize/root/curve_fit/differential_evolution
- 稀疏矩阵:csr/csc 存储与求解
- 图算法:最短路径、连通分量、最小生成树
- 空间数据:KDTree、凸包、Delaunay、距离
- 插值:interp1d、CubicSpline、griddata
- 统计:t 检验、卡方、ANOVA、非参数检验
2. 与其他库配合
# 数据科学工作流
import numpy as np
import pandas as pd
from scipy import stats, optimize
import matplotlib.pyplot as plt
# 1. pandas 读取与清洗
df = pd.read_csv("data.csv")
# 2. NumPy 数值处理
x = df["x"].values
# 3. SciPy 统计分析
t, p = stats.ttest_1samp(x, 0)
# 4. 可视化
plt.hist(x, bins=30)
plt.show()
3. 进阶方向
- 信号处理:scipy.signal(滤波、频谱)
- 图像处理:scipy.ndimage(卷积、形态学)
- 微分方程:scipy.integrate.odeint/solve_ivp
- 机器学习:scikit-learn(构建于 SciPy 之上)
4. 官方资源
官网: scipy.org 文档: docs.scipy.org 教程: docs.scipy.org/doc/scipy/tutorial GitHub: github.com/scipy/scipy 参考指南: docs.scipy.org/doc/scipy/reference
5. 实践建议
- 从 stats 和 optimize 入手,最常用
- 大矩阵用稀疏格式
- 对照 NumPy 文档区分两者职责
- 用官方教程示例动手实验
- 阅读 API 参考(参数与返回值)
SciPy 是 Python 科学计算的基石,掌握后能高效解决科研与工程中的数值问题。
第 1 / 12 节