为计算列缓存哈希一个pandas框架

4jb9z9bj  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(100)

我正在使用composition方法创建一个包含pandas框架的类,如下所示。我正在通过对基列进行一些操作来创建derived属性。

import numpy as np
import pandas as pd

class myclass:
    def __init__(self, *args, **kwargs):
        self.df = pd.DataFrame(*args, **kwargs)
    @property
    def derived(self):
        return self.df.sum(axis=1)

myobj = myclass(np.random.randint(100, size=(100,6)))
d = mc.derived

字符串
derived的计算是一个昂贵的步骤,因此我想缓存这个函数。我想使用functools.lru_cache同样。但是,它需要原始对象被哈希。我试图为这个对象创建一个__hash__函数,详细说明在这个答案https://stackoverflow.com/a/47800021/3679377中。
现在我遇到了一个新的问题,哈希函数是一个昂贵的步骤!.有什么方法可以解决这个问题?或者我已经走到了死胡同?
有没有更好的方法来检查一个嵌套框架是否被修改过,如果没有,就继续返回相同的哈希值?

4urapxun

4urapxun1#

如果散列不起作用,你可以尝试利用类的内部状态。

缓存一个方法

使用类属性作为缓存:在第一次调用方法时,将结果存储到该属性中,并在后续调用时检索它。

import pandas as pd

class MyClass:
    def __init__(self, *args, **kwargs):
        self._df = pd.DataFrame(*args, **kwargs)
        self._cached_value = None

    @property
    def df(self):
        return self._df

    @df.setter
    def df(self, value):
        self._cached_value = None
        self._df = value

    @property
    def derived(self):
        if self._cached_value is None:
            self._cached_value = self._df.sum(axis=1)
        return self._cached_value

cl = MyClass()
cl.derived  # compute
cl.derived  # return cached value

cl.df = my_new_df_value  # cache is emptied
cl.derived  # compute

字符串

缓存多个方法

然后你可以将这个原则扩展到几种方法,使用dict来存储每个操作的结果。你可以使用方法名称作为这个dict的键(感谢模块inspect,参见this response的示例)。

import pandas as pd
import inspect

class MyClass:
    def __init__(self, *args, **kwargs):
        self.df = pd.DataFrame(*args, **kwargs)
        self._cached_values = {}

    @property
    def derived(self):
        method_name = self._get_method_name()
        if method_name not in self._cached_values:
            self._cached_value[method_name] = self.df.sum(axis=1)
        return self._cached_value[method_name]

    @property
    def derived_bis(self):
        method_name = self._get_method_name()
        if method_name not in self._cached_values:
            self._cached_value[method_name] = your_expensive_op
        return self._cached_value[method_name]

    def _get_method_name(self):
        return inspect.stack()[1][3]  # returns the name of this method's caller

cl = MyClass()
cl.derived  # compute  --> self._cached_value = {'derived': your_result}
cl.derived  # return cached value

cl.derived_bis # compute  --> self._cached_value = {'derived': your_result, 'derived_bis': your_other_result}
cl.derived_bis # return cached value


您可以因式分解这两个属性的主体以遵守DRY原则,但一定要相应地修改_get_method_name

lxkprmvk

lxkprmvk2#

如果你知道哪些方法可能会更新你的df,你可以在你的自定义类中覆盖它们,并保留一个标志。我不会在这里详细介绍,但这里是基本原则:

import numpy as np
import pandas as pd

class myclass:
    def __init__(self, *args, **kwargs):
        self.df = pd.DataFrame(*args, **kwargs)
        self.derived_is_calculated = False
        
    @property
    def derived(self):
        if not self.derived_is_calculated:
            d = self.df.sum(axis=1)
            self.derived_is_calculated = True
            return d

    def update(self, other, **kwargs):
        """ Implements the normal update method, and sets a flag to track if df has changed """
        old_df = self.df.copy()  # Make a copy for comparison
        pd.DataFrame.update(self.df, other, **kwargs) # Call the base'update' method
        if not self.df.equals(old_df): # Compare before and after update
            self.derived_is_calculated = False
        
random_array = np.random.randint(100, size=(2,10))
myobj = myclass(random_array)

print(myobj.derived) # Prints the summed df
print(myobj.derived) # Prints None

myobj.update([1,2,3])
print(myobj.derived) # Prints the new summed df

字符串
可能有一个更深层次的DataFrame或pandas方法,它会在DataFrame内容的每次更改时调用,我会继续寻找。
但是你可以设置一个你的程序将使用的方法列表,并制作一个装饰器来做我在update中所做的事情,并在列出的每个方法上调用它。

nmpmafwu

nmpmafwu3#

这个问题是Google搜索如何散列DataFrame的结果之一。
对于示例代码中的用例,缓存结果是最好的方法,正如efont的回答中所指出的。
要回答有关如何对DataFrame进行散列并解决“散列函数是一个代价高昂的步骤”这一事实的字面问题,请参见RokoMijic的this answer

hashlib.sha1(pd.util.hash_pandas_object(df).values).hexdigest()

字符串
Herepd.util.hash_pandas_object()的参考。

相关问题