为Streamlit st.cache_resource的不可哈希DataFrame适配通用哈希函数
针对pandas/polars DataFrame的Streamlit缓存哈希方案
以下是几个兼顾稳定性、唯一性、性能的哈希函数方案,可根据你的DataFrame规模和需求选择:
1. 利用内置校验和(推荐中小规模DataFrame)
Polars和Pandas都有内置的高效校验和计算方式,速度快且能唯一标识DataFrame内容:
Polars 实现
import polars as pl import streamlit as st @st.cache_resource(hash_funcs={pl.DataFrame: lambda df: df.checksum()}) def slow_function(df: pl.DataFrame): # 你的耗时操作 ...
- 优点:Polars的
checksum()是内部优化的矢量化计算,速度极快;内容不变则哈希值稳定,页面刷新也不会变;能唯一区分不同内容的DataFrame。 - 缺点:超大DataFrame(千万级以上行)会有一定计算耗时,但远快于遍历所有单元格。
Pandas 实现
import pandas as pd import hashlib import streamlit as st def pandas_checksum(df: pd.DataFrame): # 用hash_pandas_object生成每行的哈希,再聚合为整体哈希 row_hashes = pd.util.hash_pandas_object(df, index=False) return hashlib.sha256(row_hashes.values.tobytes()).hexdigest() @st.cache_resource(hash_funcs={pd.DataFrame: pandas_checksum}) def slow_function(df: pd.DataFrame): # 你的耗时操作 ...
- 优点:
hash_pandas_object是矢量化操作,比逐单元格哈希快很多;哈希值稳定且唯一。 - 缺点:同样,超大规模DataFrame会有一定耗时,但在绝大多数场景下足够高效。
2. 采样+元数据哈希(推荐超大DataFrame)
如果你的DataFrame规模极大(亿级行),完全计算校验和也耗时,可以结合元数据+数据采样生成哈希,在性能和唯一性之间做平衡:
import polars as pl import pandas as pd import hashlib import json import streamlit as st def large_df_hash(df, sample_size=100): combined = {} if isinstance(df, pl.DataFrame): # 记录元数据:形状、schema combined["shape"] = df.shape combined["schema"] = df.schema # 采样首尾各sample_size行 combined["head_sample"] = df.head(sample_size).to_dict(as_series=False) combined["tail_sample"] = df.tail(sample_size).to_dict(as_series=False) elif isinstance(df, pd.DataFrame): combined["shape"] = df.shape combined["dtypes"] = df.dtypes.astype(str).to_dict() combined["head_sample"] = df.head(sample_size).to_dict("records") combined["tail_sample"] = df.tail(sample_size).to_dict("records") # 序列化后哈希 serialized = json.dumps(combined, sort_keys=True, default=str).encode() return hashlib.sha256(serialized).hexdigest() @st.cache_resource(hash_funcs={pl.DataFrame: large_df_hash, pd.DataFrame: large_df_hash}) def slow_function(df): # 你的耗时操作 ...
- 优点:采样计算速度极快,几乎不受DataFrame规模影响;元数据+采样能覆盖绝大多数场景的区分需求。
- 缺点:极端情况下可能出现不同DataFrame哈希碰撞(比如不同数据但采样和元数据完全一致),但概率极低,适合对性能要求极高的场景。
3. Pickle序列化哈希(追求绝对唯一性)
如果需要绝对保证哈希的唯一性(哪怕极端场景),可以将DataFrame序列化后哈希:
import polars as pl import pandas as pd import pickle import hashlib import streamlit as st def pickle_based_hash(df): # 用最高协议序列化,减少体积提升速度 pickled_data = pickle.dumps(df, protocol=pickle.HIGHEST_PROTOCOL) return hashlib.sha256(pickled_data).hexdigest() @st.cache_resource(hash_funcs={pl.DataFrame: pickle_based_hash, pd.DataFrame: pickle_based_hash}) def slow_function(df): # 你的耗时操作 ...
- 优点:能完全唯一标识DataFrame的所有内容,无碰撞风险;哈希值稳定。
- 缺点:序列化速度比内置校验和慢,且生成的哈希值依赖pickle版本,不同环境如果pickle版本差异可能导致哈希不一致(不过Streamlit环境一般统一)。
内容的提问来源于stack exchange,提问作者Myccha
相关产品推荐
相关产品推荐

