Vega Statistics API 完全指南:概率分布建模、回归拟合与统计计算
2026/9/23 12:28:18 网站建设 项目流程
  • 数据可视化

【免费下载链接】vega

A visualization grammar.

项目地址:https://gitcode.com/gh_mirrors/ve/vega
点击查看免费下载

Vega 内置了一套完整的**统计(statistics)**函数库,用于对概率分布建模、执行回归拟合以及完成分箱、置信区间等统计计算。这些方法既被绑定在顶层vega对象上(在表达式、信号与变换中直接可用),也可以借助独立的 vega-statistics 包以纯 JavaScript 方式单独使用。读完本文,你将掌握随机数生成与控制、正态/对数正态/均匀/整数/混合/KDE 六类分布对象的构造与采样、七种回归模型的拟合与预测,以及带宽估计、直方图分箱、自助置信区间、点图分箱与分位数计算等实用例程,并能结合源码理解其底层实现。

本文以官方文档 docs/docs/api/statistics.md 为主体,辅以 packages/vega-statistics 的真实源码与测试进行印证。

一、模块定位:从vega顶层对象到独立包

在 Vega 的模块化架构中,统计能力集中在packages/vega-statistics子包中,由 packages/vega-statistics/index.js 统一导出。该包的完整导出清单如下(与文档 API 一一对应):

  • 随机数:randomsetRandomrandomLCG
  • 分布方法:sampleNormalcumulativeNormaldensityNormalquantileNormalsampleLogNormalcumulativeLogNormaldensityLogNormalquantileLogNormalsampleUniformcumulativeUniformdensityUniformquantileUniform
  • 分布对象:randomNormalrandomLogNormalrandomUniformrandomIntegerrandomMixturerandomKDE
  • 回归:regressionConstantregressionLinearregressionLogregressionExpregressionPowregressionQuadregressionPolyregressionLoesssampleCurve
  • 统计例程:bandwidthNRDbinbootstrapCIdotbinquantilesquartiles

在完整 Vega 环境中,这些方法绑定到顶层vega对象,这意味着你可以在 Vega 的表达式、signal 或 transform 参数中直接调用vega.sampleNormal()vega.bin()等。需要独立使用(例如在 Node.js 或浏览器端做纯统计计算)时,则直接安装并导入vega-statistics包即可。

二、随机数生成:默认、替换与可复现种子

所有需要随机数的 Vega 例程(分布采样、bootstrapCI 自助抽样等)都应统一经由下列 API 获取随机数,从而保证可被全局替换与复现。

vega.random()

vega.random()返回 [0, 1) 区间上的均匀伪随机数。默认实现就是 JavaScript 内置的Math.random,这一点在 packages/vega-statistics/src/random.js 中一目了然:

export var random = Math.random; export function setRandom(r) { random = r; }

vega.setRandom(randfunc)

vega.setRandom(randfunc)用传入的函数替换全局随机数生成器,之后所有random()调用都会走新函数。典型用途有二:

  1. 引入替代随机源;
  2. 注入确定性(seeded)生成器,保证测试与输出稳定可复现。

vega.randomLCG(seed)

vega.randomLCG(seed)返回一个以给定seed初始化的新随机数生成器,其返回的函数无参调用、产生 [0, 1) 区间随机值,实现为经典的线性同余生成器(LCG)。源码见 packages/vega-statistics/src/lcg.js,使用的是 glibc 的经典参数:

export default function(seed) { return function() { seed = (1103515245 * seed + 12345) % 2147483647; return seed / 2147483647; }; }

组合使用示例——先构造种子生成器,再注入全局:

// 生成确定性的均匀随机数序列 const rng = vega.randomLCG(42); vega.setRandom(rng); vega.random(); // 稳定输出,每次运行结果一致

这一组合在 packages/vega-statistics/test 下的各分布测试中被广泛采用,用于保证测试可复现。

三、分布方法:无状态采样与计算函数

分布方法是一组无状态的纯函数,直接接受分布参数并返回计算结果,适合在表达式或变换参数中即取即用。

3.1 正态(高斯)分布

对应源码 packages/vega-statistics/src/normal.js。默认mean=0stdev=1,支持四个函数:

函数签名说明
vega.sampleNormal([mean, stdev])从正态分布采样一个值
vega.cumulativeNormal(value[, mean, stdev])给定输入值处的累积分布函数(CDF)值
vega.densityNormal(value[, mean, stdev])给定输入值处的概率密度函数(PDF)值
vega.quantileNormal(probability[, mean, stdev])给定概率的分位数(CDF 的逆)

源码实现的几个工程要点:

  • 采样使用Box-Muller 变换(normal.js),并通过缓存第二个高斯样本(nextSample)避免浪费每次变换产生的一个随机数;
  • CDF采用 West (2009) 的有理多项式近似(normal.js),对 |z|>37 直接返回 0 以规避数值溢出;
  • 分位数基于反误差函数erfinv实现(normal.js),该近似移植自 Apache Commons Math 的 Mike Giles 实现,对越界概率返回NaN

3.2 对数正态分布

对应源码 packages/vega-statistics/src/lognormal.js。注意这里的mean/stdev对数尺度的参数,默认01。四个函数均基于正态实现推导:采样直接对正态样本取指数(Math.exp(mean + sampleNormal() * stdev)),CDF 等价于cumulativeNormal(Math.log(value), ...),分位数等价于Math.exp(quantileNormal(...)),PDF 则在value <= 0时返回 0。

函数签名
vega.sampleLogNormal([mean, stdev])
vega.cumulativeLogNormal(value[, mean, stdev])
vega.densityLogNormal(value[, mean, stdev])
vega.quantileLogNormal(probability[, mean, stdev])

3.3 连续均匀分布

对应源码 packages/vega-statistics/src/uniform.js,定义在区间[min, max)上,默认min=0max=1参数约定:只传一个参数时,它被解释为max(此时min取 0)。

函数签名
vega.sampleUniform([min, max])
vega.cumulativeUniform(value[, min, max])
vega.densityUniform(value[, min, max])
vega.quantileUniform(probability[, min, max])

源码中 PDF 在区间外返回 0、区间内返回常数1/(max-min);CDF 在value < min时为 0、value > max时为 1、区间内线性插值;分位数对越界概率返回NaN(uniform.js)。

四、分布对象:参数化随机变量的统一接口

分布对象把一组分布参数封装成"随机变量",统一暴露四个方法(见 statistics.md):

  • dist.sample():从该分布抽取一个随机值;
  • dist.pdf(value):计算给定输入值处的概率密度函数值;
  • dist.cdf(value):计算给定输入值处的累积分布函数值;
  • dist.icdf(probability):计算给定概率的逆累积分布函数值。

构造后的对象还支持 getter/setter 形式的参数读写。以正态为例(normal.js),mean()stdev()无参调用返回当前值,带参调用设置新值并返回dist自身以支持链式调用。

4.1 randomNormal / randomLogNormal / randomUniform

  • vega.randomNormal([mean, stdev]):正态分布对象,可用mean/stdevgetter/setter;
  • vega.randomLogNormal([mean, stdev]):对数正态分布对象,可用mean/stdevgetter/setter(对数尺度);
  • vega.randomUniform([min, max]):连续均匀分布对象,可用min/maxgetter/setter,单参数时解释为max

4.2 randomInteger:离散均匀分布

vega.randomInteger([min,] max)创建整数域[min, max)上的离散均匀分布对象(源码 packages/vega-statistics/src/integer.js)。只传一个参数时解释为maxmin默认 0;同样提供min/maxgetter/setter。实现上sample()a + Math.floor(d * random())pdf仅在x为整数且位于[a, b)时返回1/d(integer.js)。

4.3 randomMixture:混合分布

vega.randomMixture(distributions[, weights])创建若干分布对象的(加权)混合(源码 packages/vega-statistics/src/mixture.js):

  • distributions必须是分布对象数组;
  • 可选weights数组提供各分布的数值权重,会被自动归一化为总和为 1;未指定的权重默认为 1(归一化前);
  • 不支持icdf:调用会直接抛错'Mixture icdf not supported.'(mixture.js);
  • 提供distributionsweightsgetter/setter。

从源码看,sample()先按归一化权重累加概率随机选中一个子分布,再调用其sample()pdf/cdf则是各子分布结果的加权求和(mixture.js)。

4.4 randomKDE:核密度估计

vega.randomKDE(values[, bandwidth])基于数值数组values构造**核密度估计(KDE)**分布对象(源码 packages/vega-statistics/src/kde.js):

  • 使用高斯核估计平滑的连续概率分布;
  • 可选bandwidth决定高斯核宽度;若为 0 或未指定,将基于输入数据自动估计默认带宽(调用estimateBandwidth,即下文bandwidthNRD);
  • 不支持icdf:调用同样抛错'KDE icdf not supported.'(kde.js);
  • 提供databandwidthgetter/setter。

实现上sample()先均匀抽取一个支撑点,再叠加一个缩放后的高斯噪声(support[~~(random()*n)] + bandwidth * kernel.sample());pdf/cdf是对所有支撑点核函数的平均(kde.js)。

4.5 综合示例与变换中的使用

// 正态分布对象 const dist = vega.randomNormal(100, 15); dist.mean(); // 100 dist.sample(); // 一次采样 dist.cdf(115); // 小于 115 的概率 dist.icdf(0.5); // 中位数 ≈ 100 dist.stdev(20); // 修改标准差 // 混合分布:70% 正态 + 30% 均匀 const mix = vega.randomMixture([ vega.randomNormal(0, 1), vega.randomUniform(0, 10) ], [0.7, 0.3]); mix.sample();

分布对象在 Vega 变换层被直接消费:vega-transforms的 packages/vega-transforms/src/util/Distributions.js 将kdemixturenormallognormaluniform五种函数名映射到vega-statistics的构造器,据此把 Vega 规范中的distributions参数对象解析为分布对象实例(含from数据字段抽取与混合分布递归解析)。

五、回归:二维拟合、预测与决定系数

文档把回归单独列为一节:用二维回归方法根据一个变量预测另一个变量。除regressionConstant外,所有回归方法签名统一为vega.regressionXxx(data, x, y[, ...]),其中data是输入数据数组,x/y是取值访问器函数。返回对象包含三部分:

  • coef:拟合系数数组;
  • predict:对输入x值返回回归预测值的函数;
  • rSquared:R² 决定系数,表示模型解释的y总方差比例(计算见 packages/vega-statistics/src/regression/r-squared.js:1 - SSE/SST)。
方法函数形式coef
regressionLineary = a + b*x[a, b]
regressionLogy = a + b*log(x)[a, b]
regressionExpy = a + e^(b*x)[a, b]
regressionPowy = a * x^b[a, b]
regressionQuady = a + b*x + c*x²[a, b, c]
regressionPolyy = a + b*x + ... + k*x^order[a, b, c, d, ...](长度 order+1)

源码佐证:

  • 线性回归基于普通最小二乘(OLS):通过在线累加均值与矩,调用 packages/vega-statistics/src/regression/ols.js 求解斜率与截距(linear.js);
  • 多项式回归对 order 0/1/2 分别复用constant/linear/quad的高效实现,更高阶则构建法方程矩阵并用高斯消元求解(poly.js),且对系数做了去中心化还原(uncenter);
  • 对数/指数/幂回归通过变量代换(对xy取对数)转化为线性问题后复用 OLS。

regressionLoess:局部加权回归

vega.regressionLoess(data, x, y, bandwidth)使用loess(局部估计散点平滑)拟合非参数光滑趋势线(源码 packages/vega-statistics/src/regression/loess.js):

  • bandwidth表示滑动窗口大小,取值[0, 1],是包含的总数据点数量的比例;源码中邻域大小为Math.max(2, ~~(bandwidth * n))(loess.js);
  • 对每个点,在最近邻滑动窗口内做加权线性回归,权重由tricube 核(1 - |t|³)³给出;
  • 执行最多 2 次鲁棒迭代(maxiters = 2),基于残差中位数重新加权,抑制离群点影响;
  • 返回平滑后的[x, y]点数组(重复 x 值取平均)。该实现改编自 science.js。

sampleCurve:自适应曲线采样

vega.sampleCurve(f, extent[, minSteps, maxSteps])从插值函数f在域extent上生成样本点并返回[x, y]数组(源码 packages/vega-statistics/src/sampleCurve.js)。其要点:

  • 自适应细分:在曲率更高处动态加密采样点,当当前样本与拟细分点的夹角差低于四分之一度(实现为0.5 * π / 180弧度,见 sampleCurve.js)时停止细分;
  • minSteps(默认 25):初始均匀分布的最小样本数;
  • maxSteps(默认 200):自适应采样停止的最大分辨率,相对于大小为maxSteps的均匀网格定义;
  • minStepsmaxSteps相同,则不做自适应,只返回初始均匀样本。
const pts = vega.sampleCurve(x => Math.sin(x), [0, Math.PI * 2]); // 返回 [x, y] 数组,弯折处更密集

六、统计例程:分箱、置信区间与分位数

bandwidthNRD:正态参考带宽

vega.bandwidthNRD(array[, accessor])为高斯核密度估计估计带宽,假设正态参考分布(源码 packages/vega-statistics/src/bandwidth.js)。公式源自 Scott (1992):

1.06 × min(标准差, 四分位距 / 1.34) × n^(-1/5)

其中n为样本量;当四分位距或标准差为零时有特殊处理。可选的accessor先从对象数组提取数值,等价于先执行array.map(accessor)

bin:直方图分箱方案

vega.bin(options)确定定量分箱方案(例如构建直方图)。它会在给定数值基(base)上搜索可能的步长空间,并施加最大箱数等约束,最终返回描述分箱方案的{start, stop, step}对象。支持的选项如下(完整继承自官方文档):

选项说明默认值
extent(必填)[min, max]两元素数组,表示分箱值域
base自动分箱使用的数值基10
maxbins允许的最大箱数(常因按"整齐"圆整值切分域而更少)20
span生成箱边界的值跨度,默认extent[1]-extent[0];允许在自定义跨度(如放大区域)上自动确定步长,同时保留整体extent由 extent 决定
step精确步长;提供后maxbinsspansteps均被忽略
steps允许的步长数组;提供后maxbins被忽略
minstep最小允许步长(对整数值尤其有用)0
divide允许的细分比例因子数组[5, 2]
nice是否将 start/stop 相对步长圆整为整齐值true

官方文档给出的三个经典示例(在 statistics.md 中亦有收录):

vega.bin({extent:[0, 1], maxbins:10}); // {start:0, stop:1, step:0.1} vega.bin({extent:[0, 1], maxbins:5}); // {start:0, stop:10, step:2} vega.bin({extent:[5, 10], maxbins:5}); // {start:5, stop:10, step:1}

源码实现(packages/vega-statistics/src/bin.js)的决策顺序是:显式step→ 限定steps数组 → 基于 span 与 base 自动推导(计算对数级别、按maxbins约束放大、再按divide细分收缩),最后按nice圆整边界并处理浮点精度。其行为由 packages/vega-statistics/test/bin-test.js 系统验证。

bootstrapCI:自助法置信区间

vega.bootstrapCI(array, samples, alpha[, accessor])基于自助法(bootstrap)重采样计算置信区间(源码 packages/vega-statistics/src/bootstrapCI.js):

  • samples为重采样迭代次数,alpha为目标显著水平;例如alpha=0.05对应 95% 置信区间;
  • 每次迭代从原样本有放回地均匀抽取n个值并求均值,samples个均值排序后取alpha/21-alpha/2分位作为区间两端;
  • 忽略nullundefinedNaN值(由 packages/vega-statistics/src/numbers.js 的生成器负责过滤与数值化);
  • 空数组返回[undefined, undefined]

dotbin:点图分箱

vega.dotbin(sortedArray, step[, smooth, accessor])计算**点图(dot plot)**分箱位置,返回与输入sortedArray索引一一对应的箱位置数组(源码 packages/vega-statistics/src/dotbin.js):

  • 实现 Wilkinson (1999) 的 "dot density" 算法;step决定箱宽,距锚点step范围内的点共享同一箱位置;
  • 可选smooth布尔值:为真时对箱位置做平滑以降低方差(将相邻堆叠内的点按step/4阈值交换,见 dotbin.js);
  • 注意:调用前应移除所有nullundefinedNaN值;输入需为已排序数组。

quantiles 与 quartiles:分位数与四分位边界

  • vega.quantiles(array, p[, accessor]):给定概率阈值数组p(范围 [0, 1]),返回长度与p相同的 p-分位数数组(源码 packages/vega-statistics/src/quantiles.js)。实现将数值转为Float64Array排序后调用 d3-array 的quantileSorted,并刻意不依赖类型数组排序的返回值,以避免 Safari 的未定义排序结果问题;
  • vega.quartiles(array[, accessor]):返回 3 元素数组[第一四分位, 中位数, 第三四分位](源码 packages/vega-statistics/src/quartiles.js),即quantiles(array, [0.25, 0.50, 0.75], accessor)的快捷封装。

两者同样忽略nullundefinedNaN值,并支持可选accessor提取字段。

七、在 Vega 中的实际应用与进一步阅读

变换层消费

vega-statistics的能力被多个数据变换直接复用(见 packages/vega-transforms/src 中对vega-statistics的引用):

  • Bin.js:调用vega.bin生成分箱方案;
  • Density.js:调用randomKDE生成核密度估计分布并采样;
  • DotBin.js:调用dotbin计算点图位置;
  • KDE.js:基于randomKDE输出平滑密度;
  • Quantile.js:调用quantiles计算分位数;
  • Sample.js:使用分布对象做随机采样。

对应这些变换的 Vega 规范文档见 docs/docs/transforms 目录(如 density.md、bin.md、quantile.md 等),其中distribution参数即通过上文提到的 Distributions.js 解析器映射到本文的分布对象构造器。

表达式层消费

vega-functions的表达式代码生成器 packages/vega-functions/src/codegen.js 将cumulativeNormaldensityNormalquantileNormalsampleNormalsampleLogNormalsampleUniformdensityUniformquantileUniformcumulativeLogNormaldensityLogNormalquantileLogNormalrandom等统计函数注入表达式运行时,因此在 Vega 的 signal 表达式或 transform 参数中可以直接书写cumulativeNormal(datum.x, 0, 1)这类调用。

独立使用与测试

独立使用时直接导入vega-statistics包即可:

import {sampleNormal, bin, regressionLinear} from 'vega-statistics';

每个 API 都有对应的单元测试可作行为参考,例如 packages/vega-statistics/test/normal-test.js、bin-test.js、regression-test.js、kde-test.js、bootstrapCI-test.js 等,覆盖默认参数、边界条件与数值精度。

小结

Vega 的 Statistics API 以 packages/vega-statistics 为内核,为概率分布建模、随机数控制、回归拟合与统计计算提供了统一而完备的编程接口:random/setRandom/randomLCG提供可复现的随机数基础;sample*/cumulative*/density*/quantile*系列提供无状态的分布计算;六类分布对象以sample/pdf/cdf/icdf统一接口封装随机变量(混合与 KDE 不支持icdf);七种回归方法与自适应曲线采样覆盖参数与非参数拟合;binbootstrapCIdotbinbandwidthNRDquantilesquartiles则支撑直方图、置信区间、点图与箱线图等常见可视化统计需求。这些能力既通过顶层vega对象在规范中直接可用,也可脱离 Vega 独立集成到任意 JavaScript 项目中。

  • 数据可视化

【免费下载链接】vega

A visualization grammar.

项目地址:https://gitcode.com/gh_mirrors/ve/vega
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询