如何为包含Pandas Series可变参数的函数实现记忆化?
为参数是Pandas Series的函数实现记忆化
首先得明确:你直接用lru_cache会报错,因为Pandas Series是可变对象,默认不支持哈希,而lru_cache需要参数是可哈希类型才能作为缓存的键。下面给你几个实用的解决办法:
方案一:自定义装饰器,将Series转为可哈希类型
我们可以写一个装饰器,把传入的Series转换成元组(元组是可哈希的),再用lru_cache对转换后的参数做缓存。这样既保留了原函数的参数形式,又实现了记忆化:
from functools import lru_cache, wraps import pandas as pd def series_cache(func): @wraps(func) def wrapper(series): # 将Series转换为元组作为缓存键 cache_key = tuple(series) return cached_func(cache_key) @lru_cache(maxsize=None) def cached_func(cache_key): # 把元组转回Series,调用原函数 series = pd.Series(cache_key) return func(series) return wrapper # 使用自定义装饰器代替lru_cache @series_cache def fib(n): if n.iloc[0] == 1 or n.iloc[0] == 2: return 1 min1 = n.copy() min1.iloc[0] -= 1 min2 = n.copy() min2.iloc[0] -= 2 return fib(min1) + fib(min2) # 测试调用 print(fib(pd.Series([15, 0]))) # 输出610
这个方案的好处是不需要修改原函数的逻辑,完全兼容你原来的参数形式。
方案二:提取Series中关键的可哈希参数(简化版)
如果你的函数逻辑只依赖Series中的特定元素(比如例子里只用了第一个元素n.iloc[0]),那可以直接提取这个值作为函数参数,这样就能直接用lru_cache了:
from functools import lru_cache import pandas as pd @lru_cache(maxsize=None) def fib(n): if n == 1 or n == 2: return 1 return fib(n-1) + fib(n-2) # 调用时从Series提取关键值 print(fib(pd.Series([15, 0]).iloc[0])) # 输出610
这个方法更简洁,但只适用于函数输出仅由Series中部分元素决定的场景。
方案三:使用第三方库cachetools(灵活扩展)
如果你愿意安装第三方库,可以用cachetools的cached装饰器,配合自定义的哈希函数来处理Series:
首先安装库:
pip install cachetools
然后实现代码:
from cachetools import cached, LRUCache import pandas as pd # 自定义哈希函数:将Series转为元组 def hash_series(series): return tuple(series) @cached(cache=LRUCache(maxsize=None), key=lambda series: hash_series(series)) def fib(n): if n.iloc[0] == 1 or n.iloc[0] == 2: return 1 min1 = n.copy() min1.iloc[0] -= 1 min2 = n.copy() min2.iloc[0] -= 2 return fib(min1) + fib(min2) # 测试调用 print(fib(pd.Series([15, 0]))) # 输出610
这个方案的优势是cachetools提供了更多缓存策略(比如LFU、TTL等),适合复杂场景。
核心原理补充
为什么lru_cache不能直接用?因为Python中只有不可变对象(比如整数、字符串、元组)是可哈希的,而Series是可变容器(你可以随时修改它的元素值),所以默认无法作为缓存的键。我们的解决方案本质都是把可变的Series转换成不可哈希的类型,或者提取其中的不可变部分,让缓存系统能识别重复的参数。
内容的提问来源于stack exchange,提问作者Jorge Barrios
相关产品推荐
相关产品推荐

