跳转至

Awkward Array — 处理不规则嵌套数组的高性能库


一句话说明

Awkward Array 让你像操作 NumPy 一样操作"锯齿形"嵌套数据(每行长度不同的粒子事件、JSON等),底层用 C++ 实现,速度极快。


安装与配置

# pip 安装
pip install awkward             # 当前主流版本 2.x

# conda 安装
conda install -c conda-forge awkward

# 验证
python -c "import awkward as ak; print(ak.__version__)"

核心用法

创建不规则数组

import awkward as ak            # 导入

# 创建锯齿形数组(每个子列表长度不同)
arr = ak.Array([
    [1, 2, 3],       # 第一行 3 个元素
    [4, 5],          # 第二行 2 个元素
    [6, 7, 8, 9],    # 第三行 4 个元素
])
print(arr.type)      # var * int64(var 表示可变长度)
print(arr[0])        # [1, 2, 3]
print(arr[:, 0])     # [1, 4, 6] 取每行第一个

嵌套结构(Record)

# 结构化数组(类似 pandas,但支持嵌套)
events = ak.Array([
    {"x": 1.0, "y": 2.0, "hits": [10, 20, 30]},   # 第一个事件
    {"x": 3.0, "y": 4.0, "hits": [40, 50]},         # 第二个事件
])

print(events["x"])         # [1.0, 3.0](取字段)
print(events["hits"])      # [[10,20,30],[40,50]]
print(events["hits", :2])  # 每行取前2个

向量化操作

import numpy as np

arr = ak.Array([[1, 2], [3, 4, 5], [6]])

# 广播运算(和 NumPy 一样的语法)
doubled = arr * 2              # [[2,4],[6,8,10],[12]]
summed  = ak.sum(arr, axis=1)  # 每行求和:[3, 12, 6]
flat    = ak.flatten(arr)      # 展平:[1,2,3,4,5,6]

实战案例

处理粒子物理数据

import awkward as ak
import numpy as np

# 模拟粒子碰撞事件(每次碰撞粒子数不同)
events = ak.Array({
    "pt":  [[30.0, 50.0], [20.0], [45.0, 60.0, 15.0]],  # 横向动量
    "eta": [[-1.2, 0.8],  [2.1],  [0.3, -0.5, 1.9]],    # 赝快度
})

# 筛选高能粒子(pt > 25)
mask   = events["pt"] > 25          # 布尔掩码(不规则)
hi_pt  = events["pt"][mask]         # 过滤
print(hi_pt)                        # [[30,50],[],[45,60]]

# 统计每个事件粒子数
n_particles = ak.num(events["pt"])  # [2, 1, 3]
print(n_particles)

从 Parquet/JSON 读取

# 读 Parquet(保留嵌套结构)
arr = ak.from_parquet("nested_data.parquet")

# 从 JSON 读取
import json
data = [{"a": [1,2]}, {"a": [3]}]
arr  = ak.from_iter(data)           # 从迭代器创建

常见报错与解决

报错原因解决
ValueError: cannot convert尝试把不规则数组转成规则ak.to_numpy() 前先 ak.pad_none()
IndexError: axis out of rangeaxis 参数超出层级检查嵌套深度,用 arr.ndim 查看
TypeError: ... is not an Awkward type混用 numpy 操作改用 ak.* 对应函数

速查表

操作代码
创建ak.Array([[1,2],[3]])
取字段arr["field"]
每行长度ak.num(arr)
每行求和ak.sum(arr, axis=1)
展平ak.flatten(arr)
布尔过滤arr[arr > 0]
补齐空值ak.pad_none(arr, 5)
转 numpyak.to_numpy(arr)