如何在Jupyter Notebook中实现状态依赖式缓存?
问题描述
我在Jupyter Notebook里有个计算成本极高的大型中间DataFrame,想跨会话缓存它,但要是生成这个DataFrame的上游变量(比如过滤后的新数据)变了,得自动重新计算才行。有没有办法把缓存变量和任意数量的"状态"变量绑定,检测到状态变化就重新计算目标变量,没变化就直接从缓存加载?
已参考的相关方案及存在的问题
- 使用
%store魔法命令:能实现跨会话缓存,但必须手动触发重新计算,没法自动感知上游变量的变化。 - 使用
dill保存整个会话:可以保存会话内容,但体积太大,我只想存计算成本高的中间值,不想把整个会话都保存下来。
期望的使用示例
假设Notebook中的单元格用# ---- #分隔
# 初始化工作:加载并清洗数据集 df = load_dataset() df = clean_dataset() # 生成后续会用到的中间变量 s1, s2, s3 = compute_intermediate_variables() # ---- # # 高计算成本单元格 def compute(df, s1, s2, s3): # 定义耗时的计算逻辑 return some_func(df, s1, s2, s3) # 希望在这里使用缓存操作,自动根据df、s1、s2、s3的变化决定是重新计算还是加载缓存
可行解决方案
方案1:用joblib实现带依赖校验的缓存
joblib能高效序列化大型NumPy数组和DataFrame,还可以通过计算输入参数的哈希值判断是否需要重新计算。
步骤:
- 安装joblib:
pip install joblib - 编写缓存逻辑,通过哈希值校验输入变量是否变化:
from joblib import Memory import hashlib import pandas as pd import pickle # 创建缓存存储目录 memory = Memory(location='./cached_data', verbose=0) def get_var_hash(var): """生成变量的唯一哈希值,用于检测变量是否变化""" if isinstance(var, pd.DataFrame): # 针对DataFrame生成哈希,包含数据、列顺序和类型信息 return hashlib.sha256(pd.util.hash_pandas_object(var, index=True).values).hexdigest() else: # 其他类型变量序列化后生成哈希 return hashlib.sha256(pickle.dumps(var)).hexdigest() @memory.cache(ignore=['df_hash', 's1_hash', 's2_hash', 's3_hash']) def cached_compute(df_hash, s1_hash, s2_hash, s3_hash, df, s1, s2, s3): return some_func(df, s1, s2, s3) # 生成依赖变量的哈希值,传入缓存函数 df_hash = get_var_hash(df) s1_hash = get_var_hash(s1) s2_hash = get_var_hash(s2) s3_hash = get_var_hash(s3) # 获取结果:依赖变量不变则加载缓存,变了则重新计算 result_df = cached_compute(df_hash, s1_hash, s2_hash, s3_hash, df, s1, s2, s3)
方案2:使用jupyter-cache专用工具
jupyter-cache是专为Jupyter Notebook设计的缓存工具,支持基于单元格输入输出的缓存,还能自定义依赖项。
步骤:
- 安装工具:
pip install jupyter-cache - 在Notebook中加载扩展:
%load_ext jupyter_cache
- 用
%%cache魔法命令标记需要缓存的单元格,并指定依赖变量:
%%cache high_cost_compute --deps df s1 s2 s3 def compute(df, s1, s2, s3): return some_func(df, s1, s2, s3) result_df = compute(df, s1, s2, s3)
这个魔法命令会自动跟踪指定的依赖变量,只要df、s1、s2、s3中有一个变化,就会重新执行单元格;否则直接加载缓存好的result_df。
内容的提问来源于stack exchange,提问作者Joshua Shew
相关产品推荐
相关产品推荐

