You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否存在适用于jagged数组掩码的coffea.processor.PackedSelection类工具?

在Coffea中处理Jagged数组的高效切割管理

针对你提到的需求——替代现有字典存储Jagged布尔数组的方式,同时支持广播和高效存储,这里有两种可行方案:

方案1:基于Awkward Array原生功能简化实现

Coffea底层依赖的Awkward Array本身对Jagged布尔数组有高效的压缩存储(类似PackedSelection的bitmap机制),且原生支持事件级与对象级切割的广播,无需额外封装即可满足需求:

import awkward as ak

# 定义对象级切割
cuts = {}
cuts['etacut'] = abs(events.cscRechitClusterEta) > 1.9
cuts['ptcut'] = events.cscRechitClusterPt > 15

# 定义事件级切割并广播到对象级
cuts['event_met_cut'] = events.met.pt > 200
# 自动将事件级扁平数组广播匹配Jagged数组的结构
cuts['broadcasted_met'] = ak.broadcast_arrays(cuts['event_met_cut'], cuts['etacut'])[0]

# 叠加所有切割
supercut = cuts['etacut'] & cuts['ptcut'] & cuts['broadcasted_met']

这种方式的优势是:

  • 无需额外编写工具类,直接利用Awkward的原生优化
  • 广播逻辑简洁,ak.broadcast_arrays自动处理Jagged与扁平数组的匹配
  • 切割逻辑清晰,和你现有字典方式的使用习惯完全兼容

方案2:自定义Jagged版PackedSelection(极致内存优化)

如果需要和PackedSelection一致的bitpacking极致内存效率,可以封装一个适配Jagged数组的工具类,模仿PackedSelection的bit压缩逻辑:

import awkward as ak
import numpy as np

class JaggedPackedSelection:
    def __init__(self):
        self._cuts = {}
        self._offsets = None  # 记录所有切割共享的Jagged结构偏移量

    def add(self, name, selection):
        # 校验输入为Jagged数组
        if not hasattr(selection, 'offsets'):
            raise ValueError("Selection must be an Awkward Jagged array")
        # 统一Jagged结构:所有切割必须匹配同一事件的对象数量分布
        if self._offsets is None:
            self._offsets = selection.offsets
        elif not np.array_equal(self._offsets, selection.offsets):
            raise ValueError("All selections must share the same Jagged structure")
        
        # 将每个事件的布尔数组打包为bit序列
        packed_cut = []
        for start, stop in zip(self._offsets[:-1], self._offsets[1:]):
            chunk = selection[start:stop].astype(np.uint8)
            packed_cut.append(np.packbits(chunk))
        self._cuts[name] = packed_cut

    def _unpack(self, name, invert=False):
        # 解包bit序列为Jagged布尔数组
        unpacked_chunks = []
        for chunk, start, stop in zip(self._cuts[name], self._offsets[:-1], self._offsets[1:]):
            n_bits = stop - start
            bits = np.unpackbits(chunk)[:n_bits].astype(bool)
            if invert:
                bits = ~bits
            unpacked_chunks.append(bits)
        return ak.unflatten(np.concatenate(unpacked_chunks), self._offsets[1:] - self._offsets[:-1])

    def require(self, **kwargs):
        # 叠加多个切割,支持正向/反向选择(如etacut=False表示反选)
        supercut = None
        for cut_name, required in kwargs.items():
            current_cut = self._unpack(cut_name, invert=not required)
            if supercut is None:
                supercut = current_cut
            else:
                supercut = supercut & current_cut
        return supercut

    def broadcast_event_cut(self, event_cut):
        # 将事件级扁平布尔数组广播到Jagged对象级
        return ak.broadcast_arrays(event_cut, self._unpack(next(iter(self._cuts.keys()))))[0]

使用示例:

jps = JaggedPackedSelection()
# 添加对象级切割
jps.add('etacut', abs(events.cscRechitClusterEta) > 1.9)
jps.add('ptcut', events.cscRechitClusterPt > 15)

# 叠加切割
supercut = jps.require(etacut=True, ptcut=True)
# 结合事件级切割
event_cut = events.met.pt > 200
broadcasted_cut = jps.broadcast_event_cut(event_cut)
final_cut = supercut & broadcasted_cut

这个类通过bitpacking进一步压缩了布尔数组的内存占用,同时保留了Jagged数组的结构和广播能力。

内容的提问来源于stack exchange,提问作者aaportel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:39:20