Chronaxis用户手册English
本页目录

chronaxis.core.moments_numpy

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""按有限 NumPy 块维护加权中心矩或均方根,不收集历史。23由真实有效掩码选好的值和权重按相同的二进制幂缩放。块内围绕锚点求均值和4离均差,跨块用两总体均值差合并离散度。用根均方形式存储二阶量,开方与5目标倍率在可表示范围内求值,不把两个大均方相减,也不逐样本运行标量实现。6"""78from math import frexp, hypot, ldexp, sqrt9import numpy as np10from .types import QualityFlag as Q111213class NumpyMoments:14    """持有一个锚点、相对均值、根二阶量、总权重和幂指数,跨块大小固定。"""1516    def __init__(self, operation):17        """初始化归约器。参数: 操作名称。返回: 无。异常: 调用侧校验操作。"""18        self.operation = operation19        self.weight = self.anchor = self.mean = self.root = 0.20        self.exponent = None2122    def push(self, values, weights=None):23        """整列合并活动行。参数: 有限浮点一维值,权重为正数列或等权None。返回: 无。异常: 非法权重。"""24        if not len(values):25            return26        x = np.asarray(values, dtype=np.float64)27        w = None if weights is None else np.asarray(weights, dtype=np.float64)28        if w is not None and (w.shape != x.shape or np.any(w <= 0) or not np.all(np.isfinite(w))):29            raise ValueError('二阶统计需要同长正有限权重列')30        weight = float(len(x)) if w is None else float(np.sum(w))31        peak = float(np.max(np.abs(x)))32        # 用2的整数幂共同缩放,保留高基数输入的相邻浮点差距。33        e = frexp(peak)[1] if peak else None34        if self.exponent is None or e is not None and e > self.exponent:35            if self.exponent is not None:36                shift = self.exponent - e37                self.mean, self.anchor, self.root = (ldexp(v, shift) for v in (self.mean, self.anchor, self.root))38            self.exponent = e39        exponent = self.exponent or 040        scaled = np.ldexp(x, -exponent)41        if not self.weight:42            self.anchor = float(scaled[0])43        rms = self.operation.endswith('_rms')44        if rms:45            residual, mean = scaled, 0.46        else:47            # 在全局同一锚点坐标内保存小差值;窄分布可跨块保留半ULP的均值修正。48            offsets = scaled - scaled[0]49            correction = float(np.mean(offsets) if w is None else np.sum(offsets * (w / weight)))50            mean = float(scaled[0] - self.anchor) + correction51            residual = offsets - correction52        maximum = float(np.max(np.abs(residual)))53        if maximum:54            squared = np.square(residual / maximum)55            average = float(np.mean(squared) if w is None else np.sum(squared * (w / weight)))56            block_root = maximum * sqrt(min(1., average))57        else:58            block_root = 0.59        total = self.weight + weight60        left, right = self.weight / total, weight / total61        delta = mean - self.mean62        # 平方和用hypot实现,不直接平方极小的已缩放离散度。63        combined = hypot(sqrt(left) * self.root, sqrt(right) * block_root,64                         delta * sqrt(left * right) if not rms else 0.)65        # RMS 是两块 RMS 的加权平方平均,边界夹回只修正最后一个 ULP 的舍入,66        # 保证连批常数 float64 最大值也不会越出最大输入。67        self.root = min(combined, max(self.root, block_root)) if rms else combined68        self.mean += delta * right69        self.weight = total7071    def finish(self, ddof, factor):72        """完成自由度和一次目标转换。参数: 自由度、正倍率。返回: (值或None,质量)。异常: 配置错误。"""73        if self.weight <= (ddof or 0):74            return None, Q.NONE75        if self.root == 0:76            return 0., Q.NONE77        correction = sqrt(self.weight / (self.weight - ddof)) if ddof else 1.78        mantissa, exponent = frexp(self.root * correction)79        exponent += self.exponent or 080        if self.operation.endswith('_variance'):81            mantissa, exponent = mantissa * mantissa, 2 * exponent82        f, e = frexp(factor)83        try:84            value = ldexp(mantissa * f, exponent + e)85        except OverflowError:86            return None, Q.NONFINITE87        return (value, Q.NONE) if value != 0 else (None, Q.PRECISION_LOSS)88
Chronaxis 用户手册 · 离线阅读