
前几天有个做可靠性仿真的朋友找我说他代码里算出某个点的密度值是 3.7然后直接把 3.7 当成概率写进了报告被审的人问了一句概率怎么会大于 1他当场就卡住了。这事特别典型——概率分布和概率密度名字只差两个字数学上还是一对互推的孪生兄弟但它们的含义、量纲、取值范围完全不是一回事。把这两个概念混着用轻则报告被挑毛病重则整个模型的结论都站不住。这篇就把 F(x) 和 f(x) 从头到尾捋一遍顺带把 MATLAB 里怎么算、怎么画、怎么反过来验证讲透。内容偏基础但越是基础的东西越容易在用了好几年之后突然发现自己理解偏了。适合正在啃概率论的学生、做仿真建模和数据分析的工程师以及需要写统计代码但数学课已经还给老师的人。看完至少能搞清楚三件事密度为什么能大于 1、分布函数为什么强调右连续、以及怎么用几条 MATLAB 命令把这两个函数的关系验证给自己看。1. 先把最容易被搞反的事说清楚f(x)不是概率1.1 密度大于1完全合法这不是bug很多人第一次看到某点密度值超过 1 就本能觉得错了这是因为把密度当成了概率。用物理里的线密度类比最直观一根铁丝线密度是 2 克每厘米这个 2 本身不是质量只是说每厘米大约贡献 2 克。要得到质量你得乘长度。取 0.3 厘米长质量 0.6 克取 1 厘米质量 2 克。密度值本身跟总质量是不是 1没有半毛钱关系。概率密度一模一样。拿最简单的均匀分布举例X 在 (0, 0.5) 上均匀分布那它的密度在区间内恒等于 2。为啥是 2因为总面积必须等于 1而底边长只有 0.5高就得是 1 / 0.5 2。所以密度值 2 不但正常而且是必须的。你要是看到密度小于 1 反而要警惕比如 X 在 (0, 10) 上均匀分布密度是 0.1看着小但它乘上区间长度 10 之后还是 1。判断密度对不对永远看积分不看单点值。1.2 真正承载概率的是区间积分连续型随机变量里单点概率恒等于零。这句话反直觉但它是数学定义直接推出来的P(X a) 等于从 a 到 a 的积分积分区间长度为零结果就是零。所以对连续分布问取到某一个精确值的概率是多少答案永远是 0虽然这件事真实发生时你会觉得我明明抽到了它。别纠结连续情况下抽到某个精确值本来就不是一个良定义的事件。真正有意义的是区间概率P(a X ≤ b) ∫ from a to b of f(x) dx由于单点概率为零开闭区间算出来是一样的写成 P(a X b) 也行左边从负无穷积到 x得到的那个函数就是分布函数 F(x)所以密度和概率的关系是密度乘区间长度严格说是积分才得到概率。想算概率永远离不开一个区间哪怕这个区间很窄。1.3 量纲不同这是区分两者最硬的指标还有个特别干净的区别方式看量纲。概率是无量纲的永远在 0 到 1 之间。而密度的量纲是 1 除以随机变量的量纲随机变量 X 的含义f(x) 的量纲举例说明时间秒1/秒指数分布的 λe^(-λx)λ 单位是 1/秒长度米1/米均匀分布 U(0, 3) 的密度是 1/3 每米金额元1/元收入的密度值单位是每元纯数值、无单位无量纲标准化后的变量密度也可能超过 1看这张表就明白密度值的大小跟你用什么单位去度量 X 直接相关。同一份物理数据时间用秒算密度是 0.001换成毫秒算密度就是 1数字差一千倍但积分出来的概率完全一致。所以下次有人问密度值 5 是不是错了先问一句你的 X 是什么单位。2. 概率分布F(x)的完整画像三条性质与右连续2.1 单调不减、两端极限、右连续各管什么分布函数的定义很朴素F(x) P(X ≤ x)。就一句话但对所有类型的随机变量都适用离散、连续、混合通吃这是它比密度函数更底层的地方。定义完之后有三条性质性质不是拿来背的每一条都有实际用途。第一条F(x) 单调不减。这很好理解x 越大X 小于等于 x这个事件包含的样本点越多概率自然不会变小。F 可以是平的但绝不能往下走。实际写代码时如果你算出来的经验分布函数出现了下降那一定是数据排序或者累加逻辑出问题了。第二条F(-∞) 0F(∞) 1。极端情况下的归一化保证概率总和是 1。这条性质经常被拿来当模型是否自洽的检验标准比如你拟合了一个分布尾部行为不对F 在很大 x 处还明显小于 1说明模型漏了太多概率质量。第三条F(x) 右连续也就是 F(x 0) F(x)。这条最容易被忽略也最容易在细节上翻车下面单独说。2.2 右连续为什么不是左连续右连续的意思是在某点 x₀ 处从右边趋近时函数值等于该点的函数值从左趋近时不一定。为什么偏偏是右而不是左根源就在定义里用的是 X ≤ x 而不是 X x。举个具体例子假设 X 只能取 0 和 1P(X0)0.3P(X1)0.7。那分布函数长这样x 0 时F(x) 00 ≤ x 1 时F(x) 0.3x ≥ 1 时F(x) 1看 x0 这个点。F(0) 0.3。从左边趋近 0F 趋近 0从右边趋近 0F 趋近 0.3。所以 F(0) 取的是右侧的值跳跃发生在这点上函数值跟着跳上去这就是右连续。如果当初定义用 X x那就会变成左连续怎么定都行但一旦定了就得自洽。这件小事在实际建模中有影响处理离散和连续混合的数据时断点处的概率质量到底归左边还是右边会直接影响你写累加代码时的边界判断。2.3 离散、连续、混合三种情况下的F(x)长什么样把三种情况放一起对比一眼就能看出分布函数这个统一框架的价值类型F(x) 的形态数学表达举例离散型阶梯函数一段一段往上升F(x) Σ P(X xᵢ)对所有 xᵢ ≤ x 求和掷骰子、伯努利、泊松连续型光滑连续曲线处处无跳变F(x) ∫ f(t) dt从 -∞ 到 x正态、指数、均匀混合型既有光滑段又有突然的跳跃离散部分累加 连续部分积分保险理赔大量零赔付 少量连续赔付混合型是最容易出错的保险精算、排队论里特别常见。比如一个保单赔付为 0 的概率是 0.95剩下 0.05 的概率下赔付金额连续分布。这种分布既不能只当离散处理也不能只当连续处理密度函数这个工具在这里就不够用了——因为密度无法描述那 0.95 的跳跃。这种时候只能用 F(x)或者离散概率质量 连续密度的组合描述。这也是为什么我总说F(x) 是比 f(x) 更基础的工具遇到搞不定的分布退回到 F 往往能找到出路。3. f(x)与F(x)之间的两条通道求导与积分3.1 从F到f连续点直接求导断点处随便定连续型的情况下两者靠微积分基本定理连起来在 F(x) 可导的点上f(x) F(x)。反过来说在 F 不可导的点上比如分段拼接的断点密度值可以任意指定因为你随便改一个点的函数值不影响任何积分结果也就不影响任何概率。这一点让很多强迫症同学难受明明是个固定的量怎么就随便定了。我一般这么解释密度函数在测度意义下是唯一的单点的值不影响它作为一个密度的身份。就像一个人改了名字还是同一个人。不过在实际画图和写代码时断点处的密度最好取成和左右两边一致的值否则图会裂开一条缝。比如密度在 (0, 1) 上是 2x在 (1, 2) 上是 0函数在 x1 处本身连续那就把 f(1) 定成 2图像看着舒服。这只是画图习惯跟数学无关。3.2 从f到F上限积分与分段常数确定反方向就是积分F(x) ∫ from -∞ to x of f(t) dt连续段好办直接积。麻烦的是分段定义的密度。拿指数分布举例f(x) λe^(-λx)只在 x 0 上有定义x ≤ 0 时是 0。那么x ≤ 0 时从 -∞ 积到 x积的全是 0所以 F(x) 0x 0 时F(x) ∫ from 0 to x of λe^(-λt) dt 1 - e^(-λx)注意下界的切换因为 x ≤ 0 部分密度是 0实际有效积分从 0 开始而不是从 -∞ 老老实实积过来那部分贡献是零。这个把有效区间找出来的步骤是手推分段分布时最容易漏的一步。每换一个分段都要重新确认积分下界和上面已经累积的概率。3.3 完整走一遍从密度推分布再推概率给个具体的小题目把链条串起来。设密度 f(x) 3x²/8x 在 (0, 2) 之间其他为 0。先验证它是不是合法密度积分 from 0 to 2 of 3x²/8 dx (3/8)·(x³/3) 从 0 到 2 (1/8)·8 1。合法。推分布函数x ≤ 0 时F(x) 00 x 2 时F(x) ∫ from 0 to x of 3t²/8 dt x³/8x ≥ 2 时F(x) 1。检查连续性在 x2 处 F(2) 8/8 1和右段接上没问题。再用它算个概率P(1 X 1.5)。方法一是积分密度∫ from 1 to 1.5 of 3x²/8 dx (1.5³ - 1³)/8 (3.375 - 1)/8 0.2969。方法二是分布函数相减F(1.5) - F(1) 1.5³/8 - 1³/8 0.2969。两个方法必须一致这也是写代码时最常用的自检手段——同一件事用两条路径算对不上就说明哪一步错了。从F求f也不难对 x³/8 求导得 3x²/8回来了。这套积过去、导回来的往返是确认自己对两个函数理解到位最有效的方式建议每个初学的人都拿两三个分布手动跑一遍。4. MATLAB实操把分布画出来、算出来、验出来4.1 三条命令画出pdf与cdf并排图光看公式容易虚画出来立刻有感觉。以正态分布为例均值 2、标准差 1.5mu 2; sigma 1.5; x linspace(mu - 4*sigma, mu 4*sigma, 1000); f normpdf(x, mu, sigma); % 概率密度 F normcdf(x, mu, sigma); % 概率分布 subplot(1,2,1); plot(x, f, LineWidth, 1.5); xlabel(x); ylabel(f(x)); title(概率密度); grid on; subplot(1,2,2); plot(x, F, LineWidth, 1.5); xlabel(x); ylabel(F(x)); title(概率分布); grid on;新版 MATLAB 更推荐用分布对象好处是参数集中管理函数调用不用每次重复填 mu 和 sigmapd makedist(Normal, mu, 2, sigma, 1.5); f pdf(pd, x); F cdf(pd, x);两种写法结果一样。用对象的好处是切换分布家族时改动最小比如把Normal换成Exponential、Weibull一行就能切换做分布拟合对比的时候特别省事。4.2 用icdf反查分位数与区间概率已知概率反查 x 值用icdf老写法是norminvp [0.025, 0.5, 0.975]; q icdf(pd, p); % 返回对应分位数 disp(q);这会给出 95% 区间的两个端点中间那个是中位数。做置信区间、做分位数映射、做逆变换采样全靠它。反过来已知区间求概率用cdf相减prob cdf(pd, 3.5) - cdf(pd, 1.2); % P(1.2 X 3.5)这里有个坑要提醒算尾部概率不要用 1 减去cdf。比如 P(X 8)别写1 - cdf(pd, 8)。因为cdf(pd, 8)可能已经非常接近 1浮点数相减会损失有效数字结果可能变成 0 或者精度极差的数。正确的做法是用 upper 参数直接算上尾p_tail cdf(pd, 8, upper); % 直接算 P(X 8)精度更好这个建议在算极端风险、尾部损失估计时特别重要我见过有人因为这个问题把极低概率算成了 0导致整个风险模型失效。4.3 蒙特卡洛采样反过来验证理论F(x)最后一个验证环节也是最让人踏实的用采样去逼近理论。rng(42); % 固定种子结果可复现 X random(pd, 1e5, 1); % 抽 10 万个样本 figure; histogram(X, Normalization, pdf); % 归一化成密度和理论f对比 hold on; plot(x, f, r, LineWidth, 2); legend(经验密度, 理论密度); figure; ecdf(X); % 经验分布函数 hold on; plot(x, F, r, LineWidth, 2); legend(经验分布, 理论分布);Normalization,pdf这个参数是关键不加的话直方图纵轴是频数根本没法跟密度曲线放一起看。跑完这个图你会看到柱状图和红线基本吻合采样量越大越贴合。这一步的意义不只是验证函数没调错更重要的是建立直觉——你会亲眼看到密度曲线下面的面积如何累积成分布函数。顺便说样本量别太少。1e4 个样本以下经验分布抖得厉害柱子和曲线对不上容易误判。想知道要多少样本可以试着重跑几次看波动什么时候小到自己能接受。4.4 数值积分与数值求导的精度边界有了密度想反推分布或者有了分布想反推密度很多时候没解析解只能数值搞。MATLAB 里% 从密度数值积分得到分布 F_num cumtrapz(x, f); % 梯形法累积积分 % 从分布数值微分得到密度 f_num gradient(F, x); % 中心差分 % 更精确的自适应积分 F_point integral((t) pdf(pd, t), -inf, 1.5);cumtrapz用的是梯形法简单快但精度受网格密度影响网格太粗时结果偏小。gradient求导对噪声极其敏感如果你的 F 是经验分布或者带噪声的数据直接求导会得到一条锯齿状的鬼东西。这时候要么先平滑要么别求导直接老老实实用分布函数。integral支持-inf到某值的自适应积分精度高但每次调用都要重新算一遍做大批量计算会慢。我的习惯是验证逻辑用integral批量生产用cumtrapz前提是网格够密。两种方法差值超过千分之一就得回头检查网格或者被积函数。5. 随机变量变换Yg(X)之后密度怎么走5.1 单调变换的雅可比因子实际建模中很少直接用原始变量经常要做变换。已知 X 的密度求 Y g(X) 的密度公式是f_Y(y) f_X(g⁻¹(y)) · |d(g⁻¹(y))/dy|后面那个导数绝对值叫雅可比因子很多人第一次见会漏掉它或者忘了取绝对值。举个人人都懂的经典例子X 服从 U(0, 1)做变换 Y -ln(X)这个变换在 (0,1) 上严格单调递减。反函数是 X e⁻ʸ导数 dX/dY -e⁻ʸ绝对值是 e⁻ʸ。X 的密度在 (0,1) 上恒为 1所以 f_Y(y) 1 · e⁻ʸ e⁻ʸy 0。这就是参数为 1 的指数分布。这个变换叫逆变换采样是生成非均匀随机数最常用的方法之一——先在 (0,1) 上抽均匀数再代入目标分布的分位数函数就能得到目标分布的样本。5.2 非单调变换要分区间求和单调的时候公式简单非单调就麻烦了。典型例子 Y X²X 服从标准正态。因为平方把负半轴和正半轴折叠到一起同一个 y 值对应两个 x 值√y 和 -√y。这时候不能只代一个要把两支的贡献加起来f_Y(y) f_X(√y)·|1/(2√y)| f_X(-√y)·|1/(2√y)|y 0对标准正态来说 f_X(√y) f_X(-√y)所以化简后是 2·φ(√y)/(2√y) φ(√y)/√y。这恰好是自由度为 1 的卡方分布的密度。这个练习非常值得手动推一遍因为它会强行逼你养成看到非单调变换先数支数的习惯。判断变换单调不单调最省事的办法是画个图或者求导看导数符号。导数变号就说明有多支。5.3 在MATLAB里用符号或数值对照验证手推完担心出错可以让 MATLAB 帮忙验syms X Y real g X^2; gInv solve(Y g, X); % 解出两支 disp(gInv);符号工具箱能帮你解反函数但对复杂变换经常卡住或者给出带条件的分支不太可靠。更稳的验证方式还是走数值路线对原始变量 X 大量采样变换后得到 Y 的样本画直方图再和自己推导出的理论密度对比。两条路对上了才算放心。数值验证这招对几乎所有变换都好使不依赖解析能力只需要你会采样和画图。6. 踩过的几个坑与排查思路6.1 断点处的密度取值不影响结果但会毁掉图前面说过断点处密度随便定但画图时如果你不处理两条分段曲线的端点会各走各的画出个断裂的缺口。排查思路很简单算完密度后在断点处检查左右极限取个一致的值补上。如果密度本身在断点不连续左边趋近 2右边趋近 0那就是真跳变图上也该跳别硬接。分辨假断裂和真跳变靠的就是左右极限是否相等。6.2 尾部概率精度看着对实际错这个坑前面提过但值得再强调。1 - cdf(x)在尾部会损失精度因为两个接近 1 的数相减有效位被吃掉了。更隐蔽的是反过来算极小的cdf值也类似。排查办法拿cdf(x, upper)和1 - cdf(x)在不同 x 处比较如果你发现两者在小概率区域差距越来越大就说明精度问题来了。凡是涉及极小概率、极端分位数、风险度量一律用 upper 或者直接算对数概率。6.3 混合分布被当成连续分布处理这个错误在保险、医疗、电商这些大量零值加少量正值的数据里特别常见。数据里一半以上是 0你直接当连续分布拟合结果密度在 0 附近会被拉得极其夸张整个模型都是错的。正确做法是拆成两部分先建一个伯努利模型判断是不是零再对非零部分拟合连续分布。判断数据是不是混合型最快的办法是画直方图看到 0 处有一根特别高的柱子远超其他基本就能确定。这个判断步骤一定别省画图三秒钟的事能救你几天白干。6.4 采样量不足导致经验分布抖动用ecdf或直方图验证理论分布时样本量不够会看到明显抖动尤其是尾部。这时候别急着怀疑理论先把样本量翻十倍再看。判断是采样问题还是模型问题有个小技巧重跑几次不同种子如果每次抖的位置都不一样那就是采样噪声如果某个位置稳定偏离理论曲线那就可能是模型本身不对。这个区分方法我用过很多次比盲目加大样本量更有效。让我最后说个我自己常用的自检习惯。任何一个分布模型拿到手先问三个问题密度积分是不是 1、分布函数在正负无穷的极限是不是 1 和 0、断点处右连续有没有被破坏。这三个问题用代码跑一遍也就几行但能拦下最常见的一批错误。很多看似复杂的模型 bug最后追根溯源都是这三个基本性质里某一条被违反了。基础性质之所以叫基础是因为它们真的会兜住你的疏漏。