<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Simulation on TouchingFish.top</title><link>https://touchingfish.top/categories/simulation/</link><description>Recent content in Simulation on TouchingFish.top</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 28 Aug 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://touchingfish.top/categories/simulation/index.xml" rel="self" type="application/rss+xml"/><item><title>一个点的代价 / 读 Owen(2020)</title><link>https://touchingfish.top/2024/dropping-first-sobol-point/</link><pubDate>Wed, 28 Aug 2024 00:00:00 +0000</pubDate><guid>https://touchingfish.top/2024/dropping-first-sobol-point/</guid><description>&lt;p&gt;Sobol&amp;rsquo; 序列的第一个点永远是原点——$(0, 0, \dots, 0)$。&lt;/p&gt;
&lt;p&gt;很多人觉得这个点不对劲。它刚好落在单位超立方体的角落里。如果你要用 Sobol&amp;rsquo; 点做 Gaussian 分布的变换，逆正态 CDF 会把原点映射到 $-\infty$。这显然没法用。于是大家很自然地把第一个点丢掉，从第二个点开始取 $n$ 个。&lt;/p&gt;
&lt;p&gt;这个操作叫 burn-in，在 MCMC 里是标准动作。问题是——Sobol&amp;rsquo; 序列不是 Markov chain。&lt;/p&gt;
&lt;p&gt;Art B. Owen 在 2020 年写了一篇短文，标题干脆利落：&lt;em&gt;On dropping the first Sobol&amp;rsquo; point&lt;/em&gt;。结论也干脆利落：&lt;strong&gt;别丢。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;丢掉第一个点，你的 QMC 估计的均方根误差（RMSE）可能从 $O(n^{-3/2})$ 退化到 $O(n^{-1})$——在 $n$ 很大的时候，差别大约是 $\sqrt{n}$ 倍。&lt;/p&gt;
&lt;h2 id="qmc-为什么比-mc-好"&gt;QMC 为什么比 MC 好&lt;/h2&gt;
&lt;p&gt;先回顾一下基本设定。&lt;/p&gt;
&lt;p&gt;Monte Carlo（MC）的 RMSE 是 $O(n^{-1/2})$，对任何 $f \in L^2$ 都成立。这个收敛速度稳如老狗，但慢。&lt;/p&gt;
&lt;p&gt;Quasi-Monte Carlo（QMC）试图做得更好。它不随机抽样，而是用精心构造的&lt;strong&gt;低差异序列&lt;/strong&gt;（low-discrepancy sequence）来填满 $[0,1]^d$。Sobol&amp;rsquo; 序列是最常用的一种。&lt;/p&gt;
&lt;p&gt;Sobol&amp;rsquo; 序列在 base 2 下是一个 $(t,d)$-sequence。这意味着它的前 $2^m$ 个点构成一个 $(t,m,d)$-net——对于某些被称为 elementary interval 的特殊长方体，里面的点数恰好和体积成正比。&lt;/p&gt;</description></item><item><title>生物模型的参数迷局拆解</title><link>https://touchingfish.top/2024/sobol-sensitivity-analysis/</link><pubDate>Sun, 21 Jul 2024 00:00:00 +0000</pubDate><guid>https://touchingfish.top/2024/sobol-sensitivity-analysis/</guid><description>&lt;p&gt;一个生物模型有多少个参数？少则三五个，多则几十上百。&lt;/p&gt;
&lt;p&gt;捕食者怎么繁殖，猎物怎么被捕食；蛋白质怎么磷酸化，mRNA 怎么降解；感染者怎么传播疾病，康复者怎么获得免疫——每个环节都要用一个数字来描述。这些数字从哪里来？文献里翻的，实验里测的，或者干脆猜的。&lt;/p&gt;
&lt;p&gt;问题来了：哪个参数最重要？&lt;/p&gt;
&lt;p&gt;直觉上大概会说&amp;quot;都很重要啊&amp;quot;。但计算资源不是无限的，实验经费更不是。如果只有精力精确测定三个参数，你选哪三个？如果模型结果对某个参数的变化毫无反应——花一个月测的那个数字，是不是根本无所谓？&lt;/p&gt;
&lt;p&gt;这就是 Sobol&amp;rsquo; 敏感性分析要解决的问题。&lt;/p&gt;
&lt;h2 id="不只是敏感"&gt;不只是&amp;quot;敏感&amp;quot;&lt;/h2&gt;
&lt;p&gt;敏感性分析（Sensitivity Analysis, SA）这个概念不新鲜。最朴素的做法是局部敏感性分析（Local SA）：把每个参数调高 1%，看输出变化多大。听上去很合理，问题在于——你只在一个点上做了测试。换个初始值，排名可能完全颠倒。对于非线性系统，这种局部视角约等于管中窥豹。&lt;/p&gt;
&lt;p&gt;Sobol&amp;rsquo; 指数属于全局敏感性分析（Global SA）。它不问你&amp;quot;在这个点上谁敏感&amp;quot;，而是问——&lt;strong&gt;在整个参数空间里，谁在操控输出的方差？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它的做法很直接：把模型输出 $Y$ 的总方差按来源拆开。&lt;/p&gt;
$$Y = \mathcal{M}(X_1, X_2, \dots, X_m)$$&lt;p&gt;$\mathcal{M}$ 是你的模型，$X_i$ 是输入参数。Sobol&amp;rsquo; 分解告诉你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$S_i$：$X_i$ 自己贡献了多少方差（first-order index）&lt;/li&gt;
&lt;li&gt;$S_{ij}$：$X_i$ 和 $X_j$ 的交互贡献了多少（second-order index）&lt;/li&gt;
&lt;li&gt;$S_{Ti}$：$X_i$ 的总贡献——包括它自己，加上和所有其他参数的两两交互、三三交互……一直加到 $m$ 阶（total-order index）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果 $S_{Ti} \approx 0$，恭喜你，这个参数可以当成常数，模型对它几乎不敏感。如果 $S_i$ 大但 $S_{Ti} - S_i$ 小，说明这个参数是独狼，自己就很能打。如果 $S_i$ 小但 $S_{Ti}$ 大——这就很有意思了：它自己不重要，但和别人搞在一起就很关键。&lt;/p&gt;
&lt;p&gt;这种参数的微妙之处，局部方法永远抓不到。&lt;/p&gt;
&lt;h2 id="计算上的麻烦"&gt;计算上的麻烦&lt;/h2&gt;
&lt;p&gt;Sobol&amp;rsquo; 指数好看，但不好算。&lt;/p&gt;
&lt;p&gt;理论上，你可以用 Monte Carlo（MC）来估算所有方差。问题是，对于 $m$ 个参数，要算到第 $k$ 阶交互，需要的模型评估次数是指数级的。如果你的模型求解一次就要几十分钟——比如一个 stiff ODE 系统——那 MC 的时间成本会让人想关电脑。&lt;/p&gt;</description></item><item><title>从头解析 Sobol 全局敏感性分析</title><link>https://touchingfish.top/2024/sobol-global-sa-from-scratch/</link><pubDate>Mon, 15 Jan 2024 00:00:00 +0000</pubDate><guid>https://touchingfish.top/2024/sobol-global-sa-from-scratch/</guid><description>&lt;p&gt;面对一个模型时，你在做什么？&lt;/p&gt;
&lt;p&gt;调参数。翻文献。看哪个数字不确定，然后想办法让它确定一点。道理上都懂——模型是对现实的压缩，参数是对这个压缩过程的描述。一个有十个参数的模型，意味着有十个地方可能出错、十种不确定性同时存在。&lt;/p&gt;
&lt;p&gt;问题在于：当模型跑出来的结果和你预期不符时，你该怀疑哪个参数？&lt;/p&gt;
&lt;p&gt;拍脑袋是一种方法。文献里查是另一种。但直觉会骗人，文献也不一定靠谱——有些参数是&amp;quot;纸老虎&amp;quot;，看起来重要其实无关紧要；有些参数是&amp;quot;幕后玩家&amp;quot;，自己不动声色地操纵整个系统。&lt;/p&gt;
&lt;p&gt;这就是 Sobol&amp;rsquo; 敏感性分析要回答的问题——不是&amp;quot;这个参数敏感吗&amp;quot;，而是&amp;quot;在参数的整个运动范围内，谁在决定输出的命运&amp;quot;。&lt;/p&gt;
&lt;h2 id="从局部到全局"&gt;从局部到全局&lt;/h2&gt;
&lt;p&gt;最直接的想法是这样的：找一个基准点，把每个参数稍微动一动，看看输出变多少。变幅大的就是&amp;quot;敏感&amp;quot;的参数，变幅小的就是&amp;quot;不敏感&amp;quot;的。实际操作中常见做法是固定所有参数在某个基准值上，然后逐个扰动——比如每个参数调高 1%，看输出变化多少。&lt;/p&gt;
&lt;p&gt;这就是局部敏感性分析（Local Sensitivity Analysis，Local SA）。对线性模型来说，这个方法够用——导数在哪里都一样，在一点上试过就知道全局。&lt;/p&gt;
&lt;p&gt;但现实中的模型大多是非线性的。参数 A 在基准点附近可能无关紧要，换一个区域就成了主导因素；参数 B 恰恰相反。局部 SA 给你的是一张从锁孔里拍的全景照片——理论上是全景，实际上你只看到了一条缝。&lt;/p&gt;
&lt;p&gt;全局敏感性分析（Global Sensitivity Analysis，Global SA）的思路完全不同。它不再执着于&amp;quot;在这个点谁敏感&amp;quot;这个局部问题，而是把目光投向参数的整个运动范围——&lt;strong&gt;谁的波动能掀起最大的风浪？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;具体来说，假设模型为&lt;/p&gt;
$$Y = \mathcal{M}(X_1, X_2, \ldots, X_m)$$&lt;p&gt;其中 $X_i \sim F_i$ 是相互独立的随机变量，分布 $F_i$ 反映了你对第 $i$ 个参数的不确定性认知。Sobol&amp;rsquo; 方法要做的，是把 $\text{Var}(Y)$ 这个数字拆成一堆加起来等于它的分量，每个分量对应一组参数的贡献。&lt;/p&gt;
&lt;p&gt;关键在于怎么拆。&lt;/p&gt;
&lt;h2 id="anova-分解方差的乐高"&gt;ANOVA 分解：方差的乐高&lt;/h2&gt;
&lt;p&gt;Sobol&amp;rsquo; 方法的数学基础是 ANOVA（Analysis of Variance）分解，也叫 Hoeffding–Sobol 分解。这个名字听起来吓人，直觉却很友好。&lt;/p&gt;
&lt;h3 id="一个类比"&gt;一个类比&lt;/h3&gt;
&lt;p&gt;想象你在做一道菜。最终的味道（输出 $Y$）取决于盐、糖、醋、酱油……每种调料（输入 $X_i$）。你每次做菜时各调料的用量都有一点随机波动，所以每次做出来的味道也略有不同。&lt;/p&gt;
&lt;p&gt;现在你想知道：味道的变化，多大程度上是因为盐用量的波动？多大程度上是糖和醋的配合出了问题？&lt;/p&gt;
&lt;p&gt;ANOVA 分解做的事情就是：把&amp;quot;味道的总波动&amp;quot;拆成&amp;quot;盐独自贡献的部分&amp;quot;、&amp;ldquo;糖独自贡献的部分&amp;rdquo;、&amp;ldquo;盐和糖交互贡献的部分&amp;rdquo;……一直拆到所有可能的组合。&lt;/p&gt;
&lt;h3 id="数学形式"&gt;数学形式&lt;/h3&gt;
&lt;p&gt;严格来说，Hoeffding–Sobol 分解说的是：任何一个平方可积函数 $f(X_1, \ldots, X_m)$ 都可以唯一地分解为&lt;/p&gt;
$$f(X) = f_0 + \sum_{i} f_i(X_i) + \sum_{i\lt j} f_{ij}(X_i, X_j) + \cdots + f_{1\ldots m}(X_1, \ldots, X_m)$$&lt;p&gt;其中每一项满足两个条件：&lt;/p&gt;</description></item><item><title>撒豆子的人和砌砖的工匠</title><link>https://touchingfish.top/2024/mcmc-vs-qmc-basics/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://touchingfish.top/2024/mcmc-vs-qmc-basics/</guid><description>&lt;p&gt;积分是数值方法里的老问题了。&lt;/p&gt;
$$\int_{[0,1]^d} f(\boldsymbol{x}) d\boldsymbol{x} \approx \frac{1}{n}\sum_{i=1}^n f(\boldsymbol{x}_i)$$&lt;p&gt;找 $n$ 个点，算函数值，取平均——听起来简单到无聊。但稍微想一步就会碰到一个根本问题：&lt;strong&gt;点从哪里来？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个问题把世界分成两半。&lt;/p&gt;
&lt;p&gt;一个撒豆子的人，闭着眼睛往方格里扔，相信大数定律会替他摆平一切。
一个砌砖的工匠，拿着图纸往方格里填，相信结构本身就是均匀。&lt;/p&gt;
&lt;p&gt;前者叫 Monte Carlo，后者叫 Quasi-Monte Carlo。&lt;/p&gt;
&lt;h2 id="monte-carlo随机的智慧"&gt;Monte Carlo：随机的智慧&lt;/h2&gt;
&lt;p&gt;Monte Carlo 的哲学就一句话：我不知道怎么均匀地填满空间，但我知道随机撒点&amp;quot;大概率&amp;quot;会均匀。&lt;/p&gt;
&lt;p&gt;大数定律担保了这件事。弱大数定律、强大数定律、中心极限定理——这些定理说，只要你样本量够大，样本均值会收拢到期望值附近。管它怎么撒的，反正够多就行。&lt;/p&gt;
&lt;p&gt;所以 MC 的 RMSE 是 $O(n^{-1/2})$。这个收敛速度稳如老狗——不管你的函数多复杂、维度多高，永远是这个速度。&lt;/p&gt;
&lt;p&gt;但&amp;quot;稳&amp;quot;有时候是夸奖，有时候是批评。$O(n^{-1/2})$ 意味着什么？意味着你想把误差压一半，样本量要翻四倍。$n=1000$ 不够，换 $n=4000$。还不够？$n=16000$。这是一条没有尽头的高速公路，每往前开一倍，只能缩短一半的距离。&lt;/p&gt;
&lt;p&gt;说到底，MC 的均匀是逼出来的——你不知道怎么设计均匀，就只好赌概率够大时运气会好。&lt;/p&gt;
&lt;h3 id="当独立采样太贵"&gt;当独立采样太贵&lt;/h3&gt;
&lt;p&gt;标准 MC 假设样本是独立的。这有时候太奢侈了。&lt;/p&gt;
&lt;p&gt;比如你要做 Bayesian inference。后验分布 $\pi(\theta \mid x) \propto L(x \mid \theta)\pi(\theta)$ 里那个配分函数 $Z = \int L(x \mid \theta)\pi(\theta) d\theta$，在高维空间里根本算不出来。拒绝采样更是灾难——高维空间里大部分随机点都会被拒绝，效率低到让人想转行。&lt;/p&gt;
&lt;p&gt;MCMC（Markov Chain Monte Carlo）就是来解决这个问题的。&lt;/p&gt;
&lt;p&gt;思路是：不追求独立，追求&lt;strong&gt;平稳&lt;/strong&gt;。构造一个 Markov chain，让它的平稳分布刚好是你想要的分布。然后让 chain 跑起来，跑久了，样本就&amp;quot;像是&amp;quot;从目标分布来的。&lt;/p&gt;
&lt;p&gt;Metropolis-Hastings、Gibbs sampling、Hamiltonian Monte Carlo——这些名字在统计圈里如雷贯耳。它们不是去挑战大数定律，而是去利用 Markov chain 的遍历定理。&lt;/p&gt;</description></item></channel></rss>