Chronaxis用户手册English
本页目录

chronaxis.core.windows_numpy

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""独立用NumPy扩展、分组和裁剪事件窗口,再恢复片段模型。23输入已排序Event tuple、WindowSpec和实际观测Interval,输出Segment tuple。4时间端点为(N,) int64纳秒列,先检查扩展溢出,再执行UFUNC;按真实活动间隔5或请求窗口重叠建立组边界,reduceat归约每组范围,数组裁剪并计算覆盖。6输出循环只打包模型/元数据,不逐事件执行参考数值;不调用参考窗口算法。7输入和数组完整物化,不读旧链、不写文件、不承诺整个AnalysisRunner的预算。8"""910# 真正数组端点、掩码与分组归约,禁止object/vectorize替代。11import numpy as np12from ..timebase.conversion import INT64_MIN, INT64_MAX, TimeOverflowError13from .models import Interval14# 只共享已校验协议与ID/诊断包装。15from .windows import require_windows, make_segment, require_resolved_windows161718def build_segments_numpy(events, spec, observation, *, bounds=None, compact=False):19    """以数组计算请求与实际范围,输出保留原事件关联的片段。2021    参数: events已排序真实事件;spec为WindowSpec;observation为真实Interval。22    返回: Segment或compact的CompactSegment tuple;bounds为已解析的实际边界。旧覆盖保持独立float64比值。23    异常: 配置/模型错误传播;端点或跨度溢出明确拒绝;分配失败不吞。24    流程: 扩展前校验int64上下界,批量建立连接掩码/组索引、归约、裁剪及覆盖。25        恢复Interval时校验请求跨度,再做安全整数差;不改变原事件。26    """27    # 共享的门槛没有窗口数值或归约。28    require_windows(events, spec, observation)29    require_resolved_windows(events,bounds,compact)30    if not events:31        return ()32    # 每个时间列为(N,)纳秒,point的结束锚点等于真实触发时刻。33    onsets = np.array([event.start_ns for event in events], dtype=np.int64)34    endings = np.array([event.start_ns if event.end_ns is None else event.end_ns for event in events], dtype=np.int64)35    extension = spec.exit_delay_ns if spec.merge == 'exit_delay' else spec.post_ns36    if bounds is None:37        if np.any(onsets < np.int64(INT64_MIN + spec.pre_ns)) or np.any(endings > np.int64(INT64_MAX - extension)):38            raise TimeOverflowError('窗口请求扩展超出int64纳秒')39        starts = np.subtract(onsets, np.int64(spec.pre_ns))40        ends = np.add(endings, np.int64(extension))41        left_clip=right_clip=np.zeros(len(events),dtype=bool)42    else:43        starts=np.array([item[0] for item in bounds],dtype=np.int64)44        ends=np.array([item[1] for item in bounds],dtype=np.int64)45        left_clip=np.array([item[2] for item in bounds],dtype=bool)46        right_clip=np.array([item[3] for item in bounds],dtype=bool)47    # 连接掩码(N-1,);single比较真实onset与前活动退出deadline,不使用pre。48    if spec.merge == 'exit_delay':49        connected = (onsets[1:] <= ends[:-1]) | right_clip[:-1]50    elif spec.merge == 'overlap':51        prior=np.maximum.accumulate(ends)[:-1]52        connected = (starts[1:] < prior) | ((starts[1:] == prior) & (np.maximum.accumulate(right_clip)[:-1] | left_clip[1:]))53    elif spec.merge == 'overlap_and_adjacent':54        connected = starts[1:] <= np.maximum.accumulate(ends)[:-1]55    else:56        connected = np.zeros(len(events)-1, dtype=bool)57    # 组首索引和结束索引只依赖本次真实事件,未重新排序旧输入。58    first = np.concatenate((np.array([0], dtype=np.int64), np.flatnonzero(~connected)+1))59    stop = np.concatenate((first[1:], np.array([len(events)], dtype=np.int64)))60    group_starts = np.minimum.reduceat(starts, first)61    group_ends = np.maximum.reduceat(ends, first)62    # 模型恢复先验证合并请求跨度,之后整数求差才保证不wrap。63    requests = tuple(Interval(int(start), int(end)) for start, end in zip(group_starts, group_ends))64    left = np.maximum(group_starts, np.int64(observation.start_ns))65    right = np.minimum(group_ends, np.int64(observation.end_ns))66    observed = right >= left67    actuals = tuple(Interval(int(start), int(end)) if flag else None for start, end, flag in zip(left, right, observed))68    if compact:69        coverages=[None]*len(first)70    else:71        requested_duration = np.subtract(group_ends, group_starts)72        actual_duration = np.zeros(len(first), dtype=np.int64)73        np.subtract(right, left, out=actual_duration, where=observed)74        coverages = np.divide(actual_duration.astype(np.float64), requested_duration.astype(np.float64))75    clipped=np.logical_or.reduceat(left_clip|right_clip,first)76    # 输出循环只关联父事件和包装typed模型,全部边界/分组/覆盖已在数组完成。77    return tuple(make_segment(spec, requests[index], actuals[index], None if compact else float(coverages[index]), events[int(start):int(end)],compact=compact,clipped=bool(clipped[index]))78                 for index, (start, end) in enumerate(zip(first, stop)))79
Chronaxis 用户手册 · 离线阅读