跳转至

Zarr — 云原生分块压缩数组存储格式


一句话说明

Zarr 把大型 NumPy 数组切成小块,分别压缩存储(本地/S3/GCS均可),让 TB 级数据也能高效并行读写,是云时代的 HDF5 替代方案。


安装与配置

# pip 安装(当前默认安装 v3.x,要求 Python >=3.12)
pip install zarr                   # 核心库(v3.2+)

# 云存储支持
pip install zarr s3fs              # AWS S3 支持
pip install zarr gcsfs             # Google Cloud Storage 支持

# 验证
python -c "import zarr; print(zarr.__version__)"

核心用法

创建和写入数组

import zarr
import numpy as np
from zarr.codecs import BloscCodec       # v3 压缩编解码器

# 创建根组(直接传路径,Zarr 自动管理存储)
root = zarr.open_group("my_data.zarr", mode="w")  # 写模式创建

# 创建数组(指定形状和分块大小)
z = root.create_array(
    name    = "temperature",              # 数据集名称
    shape   = (1000, 1000),               # 总形状:1000x1000
    chunks  = (100, 100),                 # 每块 100x100
    dtype   = "float32",                  # 数据类型
    codecs  = [BloscCodec(               # 压缩方式(v3 用 codecs 参数)
        cname="lz4",                      # LZ4 压缩器(速度快)
        clevel=5,                         # 压缩级别 1-9
    )],
)

# 写入数据
z[:] = np.random.rand(1000, 1000).astype("float32")
print(z.info)                             # 打印数组信息

读取数组

# 打开已有存储(只读模式)
root = zarr.open_group("my_data.zarr", mode="r")

z = root["temperature"]       # 取出数据集

# 切片读取(只读需要的块,不全量加载)
subset = z[100:200, 100:200]   # 读取子区域
print(subset.shape)            # (100, 100)
print(type(subset))            # numpy.ndarray

分组管理

# 层级结构(类似文件夹)
root = zarr.open_group("experiment.zarr", mode="w")

# 创建子组
raw  = root.create_group("raw")          # 原始数据组
proc = root.create_group("processed")    # 处理后数据组

raw.create_array("reads", shape=(500, 150), dtype="int16")
proc.create_array("counts", shape=(500, 20000), dtype="float32")

# 添加元数据
root.attrs["experiment_id"] = "EXP-001"  # 全局属性
root.attrs["date"]          = "2025-05-01"

实战案例

单细胞数据大矩阵存储

import zarr
import numpy as np

# 存储 10x Genomics 风格的计数矩阵(细胞 x 基因)
n_cells, n_genes = 50000, 30000          # 5万细胞,3万基因

root = zarr.open_group("scRNA.zarr", mode="w")

# 稀疏矩阵用分块存储
counts = root.create_array(
    "X",
    shape  = (n_cells, n_genes),
    chunks = (1000, 1000),               # 每块 1000x1000
    dtype  = "float32",
    fill_value = 0,                      # 空位填 0(稀疏友好)
)

# 批量写入(避免内存溢出)
batch = 1000                             # 每次写1000行
for i in range(0, n_cells, batch):
    end = min(i + batch, n_cells)
    counts[i:end, :] = np.random.poisson(0.5, (end-i, n_genes)).astype("float32")

print(f"数组形状:{counts.shape}")
print(f"分块大小:{counts.chunks}")

常见报错与解决

报错原因解决
ImportError: cannot import DirectoryStore使用了 Zarr v2 API改用 zarr.open_group(path)zarr.storage.LocalStore(path)
AttributeError: module 'zarr' has no attribute 'Blosc'v3 移除了 zarr.Blosc改用 from zarr.codecs import BloscCodec
ContainsGroupError组已存在mode="a"(追加)或 mode="w"(覆盖)
PermissionError文件只读打开时用 mode="a"(追加)或 mode="w"(覆盖)
写入慢块太小频繁 I/O增大 chunks 参数,推荐每块 1-10 MB

速查表

操作代码
创建/打开组zarr.open_group("dir.zarr", mode="w")
创建数组root.create_array("name", shape=(...))
指定压缩codecs=[BloscCodec(cname="lz4")]
写数据z[0:100] = data
读数据z[0:100]
查看信息z.info
添加属性z.attrs["key"] = "val"
只读打开zarr.open_group("dir.zarr", mode="r")