Resources
1Install
npx skillscat add xngg1021/academic-research-kernel/math-computation Install via the SkillsCat registry.
数理计算 Skill
本技能为各类科学计算任务的统一入口,涵盖符号推导(sympy)、数值分析(numpy 与 scipy)、高精度计算(mpmath)、统计建模(statsmodels 与 scikit-learn)、数据处理(pandas)、图论分析(networkx)、张量求导(torch)、科学可视化(matplotlib)、生存分析(lifelines)、金融波动率建模(arch)以及心理测量分析(pingouin)。相关依赖库按需安装;因 terminal 与 execute_code 的解释器环境可能不一致,执行前须通过 sys.executable 核查实际运行环境与包依赖。
跨学科计算采用“领域自动路由”机制:先判定应用领域(涵盖金融、社科、生物医学、物理工程以及数理统计),再将计算需求映射至具体算法与函数库,领域配方详见 references/domain-recipes-*.md。各学科通用的数学基础方法(如数值优化、统计推断、蒙特卡洛模拟、微分方程求解以及时间序列分析)构成底层共享能力,便于跨领域复用。
不做:机器学习训练调参(按任务查找专用训练工具;huggingface-hub/llama-cpp 是可选的模型管理/推理相关技能)、数学动画视频(去 manim-video skill)、硬件跑分(使用另行安装并核实的专用工具)。
When to Use
- 代数方程求解、微积分与极限计算、表达式化简、因式分解、矩阵运算与特征值分析、LaTeX 公式生成 → sympy
- 数值积分与重积分、数值优化与线性规划、线性方程组求解、快速傅里叶变换、常微分方程初值与边值问题、数值插值与特殊函数计算 → scipy/numpy
- 任意精度高精度计算(几十位小数)→ mpmath
- 描述统计分析、假设检验(t 检验、卡方检验、方差分析)、回归分析(OLS、WLS、稳健回归)、功效分析与时间序列平稳性检验 → statsmodels + scipy.stats
- 表格数据读取与写入、数据分组透视与清洗 → pandas
- 复杂网络与图论分析(最短路径、图连通性、网络中心性、最大流计算)→ networkx
- 梯度/自动微分、张量运算 → torch
- 科学图表绘制(函数曲线图、散点图、直方图、三维曲面图、拟合线图、热力图)→ matplotlib
Don't use for: 纯算术四则运算(直接算)、需要联网查数据(用 web_search)、要发给用户的图片需先存文件再说明路径。
Prerequisites
Python 3.11+;数值配方要求 NumPy、SciPy >=1.9(含 MILP)。其余按任务检查 pandas、sympy、mpmath、statsmodels、scikit-learn >=0.24(含旋转)、matplotlib、networkx、torch、lifelines、arch、pingouin。Excel .xlsx 读取另需 openpyxl,.xls 另需 xlrd。
不假定 Hermes 预装这些库。用所选解释器执行 python -c "import sys; print(sys.executable)";安装时用该解释器的 -m pip install <package>,或 uv pip install --python <venv-python> <package>。占位符须换成已确认的解释器,不把作者本机版本当成锁定环境。离线计算本身不需 API key;首次安装依赖可能需联网。
执行方式
使用会话实际暴露的 terminal 运行 Python 脚本;execute_code 可编排工具调用或在其解释器有依赖时直接计算。不要假定两个环境共享包。打印中间量、单位和结果;检查退出码与 stderr。
出图必须无头运行:先 import matplotlib; matplotlib.use('Agg') 再 import pyplot,最后 fig.savefig(path) 存文件,不要 plt.show()(无 GUI 会卡住/报错)。中文标签需先设字体(见 Pitfalls)。
科学计算执行层(Scientific Computation Engine)
默认在 CPU 上用 NumPy/SciPy 计算;不要默认"上 GPU 更快"。本机与本仓库有一层实测证据:../../scripts/scfabric/ 与 ../../docs/scientific-compute-fabric.md。核心规则:
- dtype 语义先于设备可用性。float64 工作负载不得为"上 GPU"降成 float32;MPS 不支持 float64,double 计算留在 CPU。
- 大规模可并行的浮点统计(蒙特卡洛、bootstrap 重抽样、大 FFT)才有加速器价值;小任务与标量重算一律 CPU。
- 要声称某个后端更快,必须跑 paired benchmark 加数值等价检查并出 ComputeReceipt(
../../scripts/scfabric/admission.py);没有 receipt 的加速断言不算证据。 - 复现记录里写清楚 backend、dtype、线程数与实测 dispatch,不要只写"GPU"。
领域自动路由(全领域计算中枢)
每次计算先输出一行路由说明再执行:
【路由】领域:金融 | 任务:组合优化 | 工具:scipy.optimize.minimize(约束) | 配方:references/domain-recipes-finance.md
第一步:领域识别(按用户需求关键词)
| 领域 | 触发词 | 配方文件 |
|---|---|---|
| 金融 | 收益率、期权、组合、VaR、波动率、GARCH、夏普、定价、因子回归 | domain-recipes-finance.md |
| 社会科学 | 问卷、量表、信度、效度、效应量、中介、调节、面板、抽样 | domain-recipes-social-science.md |
| 生物医学 | 生存、删失、Kaplan-Meier、Cox、发病率、剂量 | domain-recipes-social-science.md(生存分析节) |
| 物理/工程 | 微分方程、场、扩散、谱、滤波、信号、振动、电路 | domain-recipes-physics-engineering.md |
| 纯数/统计 | 无领域词(默认) | 本 SKILL.md 速查 + advanced-recipes.md |
第二步:任务类型 → 工具映射(最大公约数因子)
| 任务类型 | 工具 |
|---|---|
| 回归/假设检验 | statsmodels + scipy.stats |
| 分类/聚类/降维/因子分析 | scikit-learn |
| 优化(无约束/约束/线性规划/全局) | scipy.optimize(minimize / linprog / differential_evolution) |
| 随机模拟/蒙特卡洛 | numpy default_rng |
| 时间序列(ARIMA/波动率) | statsmodels / arch |
| 生存分析 | lifelines |
| 心理测量(信度/效应量/事后检验) | pingouin |
| 符号/高精度 | sympy / mpmath |
| ODE/PDE | scipy.integrate / 有限差分手写 |
| 图/网络 | networkx |
| 自动微分 | torch |
第三步:执行与路由规则
按映射工具找速查(本 SKILL.md)或配方(references)。路由规则:领域词命中即走对应配方;多领域词按金融 > 社科 > 生物医学 > 物理工程的优先级;用户明确领域时以用户为准;拿不准时路由行标"存疑"并说明假设。
各库核心 API 速查
符号计算 sympy
# fragment: API reference; supply the named input variables and required imports.
import sympy as sp
x, y = sp.symbols('x y')
sp.diff(x**3 + sp.sin(x), x) # 求导
sp.integrate(sp.exp(-x**2), x) # 不定积分(符号)
sp.limit(sp.sin(x)/x, x, 0) # 极限
sp.solve(x**2 - 5*x + 6, x) # 解方程
sp.solve([x+y-3, x-y-1], [x, y]) # 解方程组
sp.solveset(sp.sin(x) - 0.5, x) # 解集形式(含周期解)
sp.simplify((x**2-1)/(x-1)) # 化简
sp.factor(x**3 - 1) # 因式分解
sp.Matrix([[1,2],[3,4]]).eigenvals() # 特征值
sp.series(sp.exp(x), x, 0, 5) # 泰勒展开
sp.latex(sp.Integral(sp.exp(x), x)) # 输出 LaTeX 字符串
sp.sqrt(2).evalf(30) # 任意精度求数值(30位)
sp.nsolve(sp.cos(x)-x, x, 0.7) # 数值求根(无解析解时)
f = sp.lambdify(x, x**2 + 1, 'numpy') # 符号表达式 → numpy 函数(向量化求值/绘图)要点:结果想转浮点用 float(expr) 或 expr.evalf();solve 解不出就用 nsolve(多初值扫描防漏根),要向量化数值就用 lambdify。
数值计算 scipy/numpy
# fragment: API reference; supply the named input variables and required imports.
import numpy as np
from scipy import integrate, optimize, linalg, fft, interpolate
from scipy.integrate import solve_ivp, solve_bvp
integrate.quad(lambda x: x**2, 0, 1)[0] # 数值定积分
integrate.dblquad(f, 0, 1, 0, 1)[0] # 二重积分
optimize.minimize(lambda x: (x-3)**2, x0=0) # 无约束最小化
optimize.minimize(f, x0, constraints=cons) # 约束优化(cons 用 LinearConstraint/NonlinearConstraint)
optimize.curve_fit(f, xdata, ydata, p0) # 非线性曲线拟合
optimize.linprog(c, A_ub, b_ub) # 线性规划(标准形式,无需额外库)
np.linalg.solve(A, b) # 线性方程组(良态矩阵)
np.linalg.lstsq(A, b, rcond=None) # 最小二乘;检查秩与奇异值,病态时仍可能不稳定
np.linalg.cond(A) # 条件数;结合精度/缩放判断,lstsq 不会消除病态
linalg.eigh(A) # 对称矩阵特征值/特征向量
fft.fft(signal) # 快速傅里叶变换
solve_ivp(f, [t0, t1], y0) # ODE 初值问题
solve_bvp(f, bc, x, y) # ODE 边值问题(配方见 references)
interpolate.CubicSpline(x, y) # 插值
np.gradient(f, x) # 数值微分(有限差分)
rng = np.random.default_rng(42) # 随机数(新 API,见 Pitfalls 8)
rng.normal(0, 1, size=1000) # 抽样优化先检查 result.success、约束残差和目标值;失败时检查缩放、导数与初值。Nelder-Mead 是无梯度局部方法,不保证最稳或全局最优,也不支持通用约束。拟合同时检查警告与协方差有限性。
高精度 mpmath
# fragment: API reference; supply the named input variables and required imports.
from mpmath import mp
mp.dps = 50 # 50 位精度
mp.pi, mp.e # 高精度常数
mp.nsum(lambda n: 1/n**2, [1, mp.inf]) # 高精度级数求和
mp.quad(lambda x: mp.exp(-x**2), [-mp.inf, mp.inf])统计 statsmodels + scipy.stats
# fragment: API reference; supply the named input variables and required imports.
import statsmodels.api as sm
from scipy import stats
import numpy as np
stats.describe(data) # 描述统计
stats.ttest_ind(a, b, equal_var=False) # Welch 独立样本 t 检验,不假定等方差
stats.ttest_rel(a, b) # 配对 t 检验
stats.chi2_contingency(table) # 卡方独立性
stats.f_oneway(g1, g2, g3) # 单因素 ANOVA
stats.norm.fit(data) # 正态分布参数拟合
stats.pearsonr(x, y) # 皮尔逊相关
stats.shapiro(data) # 正态性检验
X = sm.add_constant(x) # 加截距项
sm.OLS(y, X).fit().summary() # 线性回归(看 p 值/R²)
sm.WLS(y, X, weights=w).fit() # 权重为误差方差的倒数,须有依据
sm.RLM(y, X).fit().summary() # 稳健回归(有离群点时)
sm.Logit(y_bin, X).fit().summary() # 逻辑回归
sm.tsa.stattools.adfuller(series) # 时间序列平稳性检验
sm.stats.TTestIndPower().solve_power(effect_size, nobs1=None, alpha=0.05, power=0.8) # 功效分析(求所需样本量)summary() 输出长,先打印关键量(系数、p 值、R²)再决定要不要全文。残差检验用 sm.stats.diagnostic.het_breuschpagan(异方差)与 statsmodels.stats.stattools.durbin_watson(自相关)。
自动微分 torch
# fragment: API reference; supply the named input variables and required imports.
import torch
x = torch.tensor(2.0, requires_grad=True)
y = x**3 + torch.sin(x)
y.backward() # dy/dx
print(x.grad) # 12 + cos(2)只做梯度/张量运算用 CPU 版足够;不需要 GPU,也不需要任何模型权重。
数据 pandas
import pandas as pd
# smoke-test: true
# fixture: 教学临时 CSV;真实任务改为用户 path。
import tempfile
from pathlib import Path
_tmp = tempfile.TemporaryDirectory()
path = Path(_tmp.name) / 'table.csv'
pd.DataFrame({'col': ['g', 'g'], 'v': [1., 3.], 'a': ['a', 'a'], 'b': ['b', 'b']}).to_csv(path, index=False)
from pathlib import Path
path = Path(path).expanduser()
if path.suffix.lower() == '.csv':
df = pd.read_csv(path)
elif path.suffix.lower() in {'.xlsx', '.xls'}:
df = pd.read_excel(path)
else:
raise ValueError(f'Unsupported table format: {path.suffix}')
df.groupby('col')['v'].agg(['mean','std','count'])
df.pivot_table(values='v', index='a', columns='b')
df.describe() # 快速概览
assert df['v'].sum() == 4.
_tmp.cleanup()pandas 3.0 的 copy-on-write 与字符串 dtype 变化见 Pitfalls 9。
图论 networkx
# fragment: API reference; supply the named input variables and required imports.
import networkx as nx
G = nx.Graph(); G.add_edges_from([(1,2),(2,3),(1,3)])
nx.shortest_path(G, 1, 3) # 最短路
nx.connected_components(G) # 连通分量
nx.pagerank(G) # PageRank 中心性
nx.maximum_flow(DiG, s, t) # 最大流(有向图)绘图 matplotlib(无头)
# smoke-test: true
import matplotlib
matplotlib.use('Agg') # 必须最先,无 GUI 后端
import matplotlib.pyplot as plt
import numpy as np
# 中文标签需先核实已安装字体(见 Pitfalls),不假定系统自带中文字体。
plt.rcParams['axes.unicode_minus'] = False
x = np.linspace(-5, 5, 200)
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].plot(x, np.sin(x), label='sin')
axes[1].scatter(x, x + np.random.default_rng(42).normal(0, 0.5, 200), s=6, alpha=0.6)
axes[0].legend(); axes[1].set_title('Scatter')
from pathlib import Path
import os
path = Path(os.environ.get('PLOT_DIR', '~/plots')).expanduser() / 'plot.png'
path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(path, dpi=120, bbox_inches='tight')
assert path.is_file() and path.stat().st_size > 0
plt.close(fig)
print(f'saved: {path.resolve()}')3D 用 fig = plt.figure(); ax = fig.add_subplot(111, projection='3d')。热力图用 plt.imshow + plt.colorbar()。
Procedure
- 明确问题是符号还是数值:能解析解(求导/精确积分/方程有闭式解)走 sympy;否则走 scipy 数值。
- 写
execute_code脚本,一次算完中间量和最终答案,print出来;需要图就savefig到稳定目录(~/plots/或tempfile.gettempdir(),路径保证 UTF-8 可用)。 - 结果核对:符号解代入验算(sympy 的
expr.subs(x, 值)或数值回代);数值解检查量纲/数量级是否合理;统计结果检查 p 值与效应量的自洽性。 - 把最终答案(数字/公式/图路径)用纯文本回给用户;公式用 LaTeX 字符串或
expr.pretty()的文本形式,不贴整段代码。
进阶配方(线性规划、边值问题、功效分析、蒙特卡洛、torch 梯度、3D 曲面)见 references/advanced-recipes.md。领域配方:金融见 references/domain-recipes-finance.md,社科与生物医学见 references/domain-recipes-social-science.md,物理工程见 references/domain-recipes-physics-engineering.md。
Pitfalls
- matplotlib 无头:CLI 环境没有 GUI,
plt.show()会卡住或报错。必须matplotlib.use('Agg')+savefig。这个错误最常见。 - 中文乱码:默认字体不含中文,标签会变方块。先
plt.rcParams['font.sans-serif']=['Microsoft YaHei'](Windows 已内置);Linux/macOS 用['SimHei']或系统可用字体,查字体用matplotlib.font_manager.fontManager.ttflist。 - sympy 结果转数值:
solve返回符号对象,直接打印是x = -sqrt(5)+1之类,用户可能要数值——用float(expr)或expr.evalf()。nsolve需要初值,多解时用多个初值扫描,防漏根。 - scipy 优化/拟合不收敛:检查尺度、初值、导数及算法是否支持所需约束;失败结果不能当作有效解。
- 符号积分积不出:sympy 积不出不代表无解,立刻转
integrate.quad数值积分,不要卡在符号路径。 summary()太啰嗦:statsmodels 的 summary 输出几十行,直接回给用户会被淹没,先提取系数表/关键统计量。- 包名陷阱:scikit-learn 的 import 名是
sklearn(不是scikit-learn);opencv 是cv2;检查是否安装用importlib.util.find_spec('sklearn'),别拿 pip 包名做find_spec。 - 随机数必须用新 API:numpy 2.x 里
np.random.seed()是全局旧 API,同一会话多个任务会互相污染。用rng = np.random.default_rng(seed)后调rng.normal(...)等方法。numpy 2.x 还移除了np.NaN/np.float_等旧别名,一律写np.nan/float。 - pandas 版本注意:统一用
loc一步赋值,避免链式赋值;3.x 默认 copy-on-write,字符串 dtype 也有变化。升级依赖后重跑自检。 - 环境变化:遇到 ModuleNotFoundError 先确认当前解释器和任务所需依赖,不推断用户机器曾安装哪些包。
Verification
# smoke-test: true
import sympy as sp, numpy as np, tempfile, os
from scipy.integrate import quad
import statsmodels.api as sm
import matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
import pandas as pd, networkx as nx
try:
import torch
except ImportError:
torch = None
import lifelines, arch, pingouin
x = sp.symbols('x')
assert str(sp.diff(x**3, x)) == '3*x**2' # 符号求导
assert abs(quad(lambda t: t**2, 0, 1)[0] - 1/3) < 1e-9 # 数值积分
assert np.allclose(sm.OLS([1., 3., 5., 7.], sm.add_constant([0., 1., 2., 3.])).fit().params, [1., 2.]) # 统计回归
rng = np.random.default_rng(0) # numpy 新 API
assert abs(rng.normal(0, 1, 100).mean()) < 0.5
assert pd.DataFrame({'a': [1, 2]}).a.sum() == 3 # pandas
G = nx.Graph(); G.add_edge(1, 2) # networkx
assert nx.shortest_path_length(G, 1, 2) == 1
if torch is not None:
t = torch.tensor(2.0, requires_grad=True) # torch 自动微分
(t**2).backward()
assert abs(t.grad.item() - 4.0) < 1e-6
p = os.path.join(tempfile.gettempdir(), '_v.png')
fig, ax = plt.subplots(); ax.plot([0, 1], [0, 1]); fig.savefig(p); os.remove(p) # 出图
plt.close(fig)
print('math-computation Verification passed (basic invariants; not every recipe)')