大熊猫不可改变的数据帧

问题描述 投票:10回答:3

我对一个不可变的数据帧中的程序使用作为参考表,以READ_ONLY属性执行,它已初步构造之后(这在我的情况下是一个类def __init__()方法期间)。

我看到索引对象被冻结。

有没有一种方法,使整个数据框不变?

python pandas immutability
3个回答
5
投票

尝试代码是这样的

class Bla(object):
    def __init__(self):
        self._df = pd.DataFrame(index=[1,2,3])

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

这将让你得到的DF回来,用b.df,但你不能够分配给它。因此,在短期你在课堂上DF,其行为在“不可改变的数据框”,纯粹是因为它块改动原。返回的对象是静止然而一个可变的数据帧,所以它不会表现得像一个不可变的一个在其他方面。即您将无法使用它作为密钥字典等


3
投票

如果你忠实地想使DataFrame表现为不可变的而不是使用@Joop的copy解决方案(这我会建议),你可以建立在以下结构。

请注意,这只是一个起点。

它基本上是隐藏,将改变国家所有的东西,让自己被散列和相同的原始数据的所有实例将具有相同的哈希的代理数据对象。有可能是做下面的冷却器模块的方式,但我想它可能是教育作为一个例子。

一些警告:

  • Dependeing如何代理对象的字符串表示构造两个不同的代理对象可以得到相同的散列,howerver实现是与其他物体之间DataFrames兼容。
  • 改变原来的对象,会影响到代理对象。
  • Equalness会导致一些讨厌的无限递归如果其他物体扔了equalness问题丢回(这就是为什么list有一个特殊的情况下)。
  • 所述DataFrame代理机辅助仅仅是一个开始,问题是,任何改变的原始对象的状态不能被允许或需要的方法来通过辅助手动覆盖或由extraFilter参数实例_ReadOnly当完全掩蔽英寸见DataFrameProxy.sort
  • 该代理不能显示从代理型的。

通用只读代理

这可以在任何物体上使用。

import md5                                                                                              
import warnings                                                                                         

class _ReadOnly(object):                                                                                

    def __init__(self, obj, extraFilter=tuple()):                                                       

        self.__dict__['_obj'] = obj                                                                     
        self.__dict__['_d'] = None                                                                      
        self.__dict__['_extraFilter'] = extraFilter                                                     
        self.__dict__['_hash'] = int(md5.md5(str(obj)).hexdigest(), 16)                                 

    @staticmethod                                                                                       
    def _cloak(obj):                                                                                    
        try:                                                                                            
            hash(obj)                                                                                   
            return obj                                                                                  
        except TypeError:                                                                               
            return _ReadOnly(obj)                                                                       

    def __getitem__(self, value):                                                                       

        return _ReadOnly._cloak(self._obj[value])                                                       

    def __setitem__(self, key, value):                                                                  

        raise TypeError(                                                                                
            "{0} has a _ReadOnly proxy around it".format(type(self._obj)))                              

    def __delitem__(self, key):                                                                         

        raise TypeError(                                                                                
            "{0} has a _ReadOnly proxy around it".format(type(self._obj)))                              

    def __getattr__(self, value):                                                                       

        if value in self.__dir__():                                                                     
            return _ReadOnly._cloak(getattr(self._obj, value))                                          
        elif value in dir(self._obj):                                                                   
            raise AttributeError("{0} attribute {1} is cloaked".format(                                 
                type(self._obj), value))                                                                
        else:                                                                                           
            raise AttributeError("{0} has no {1}".format(                                               
                type(self._obj), value))                                                                

    def __setattr__(self, key, value):                                                                  

        raise TypeError(                                                                                
            "{0} has a _ReadOnly proxy around it".format(type(self._obj)))                              

    def __delattr__(self, key):                                                                         

        raise TypeError(                                                                                
            "{0} has a _ReadOnly proxy around it".format(type(self._obj)))                              

    def __dir__(self):                                                                                  

        if self._d is None:                                                                             
            self.__dict__['_d'] = [                                                                     
                i for i in dir(self._obj) if not i.startswith('set')                                    
                and i not in self._extraFilter]                                                         
        return self._d                                                                                  

    def __repr__(self):                                                                                 

        return self._obj.__repr__()                                                                     

    def __call__(self, *args, **kwargs):                                                                

        if hasattr(self._obj, "__call__"):                                                              
            return self._obj(*args, **kwargs)                                                           
        else:                                                                                           
            raise TypeError("{0} not callable".format(type(self._obj)))                                 

    def __hash__(self):                                                                                 

        return self._hash                                                                               

    def __eq__(self, other):                                                                            

        try:                                                                                            
            return hash(self) == hash(other)                                                            
        except TypeError:                                                                               
            if isinstance(other, list):                                                                 
                try:                                                                                    
                    return all(zip(self, other))                                                        
                except:                                                                                 
                    return False                                                                        
            return other == self    

数据帧代理

真的应该有更多的方法,如sort和过滤非利息收入的所有其他状态更改方法延长。

您可以用DataFrame实例或者实例作为唯一参数,或给它的参数,你就必须创建一个DataFrame

import pandas as pd

class DataFrameProxy(_ReadOnly):                                                                        

    EXTRA_FILTER = ('drop', 'drop_duplicates', 'dropna')                                                

    def __init__(self, *args, **kwargs):                                                                

        if (len(args) == 1 and                                                                          
                not len(kwargs) and                                                                     
                isinstance(args, pd.DataFrame)):                                                        

            super(DataFrameProxy, self).__init__(args[0],                                               
                DataFrameProxy.EXTRA_FILTER)                                                            

        else:                                                                                           

            super(DataFrameProxy, self).__init__(pd.DataFrame(*args, **kwargs),                         
                DataFrameProxy.EXTRA_FILTER)                                                            



    def sort(self, inplace=False, *args, **kwargs):                                                     

        if inplace:                                                                                     
            warnings.warn("Inplace sorting overridden")                                                 

        return self._obj.sort(*args, **kwargs) 

最后:

然而,尽管乐趣使这个玩意儿,何不干脆都不要改变DataFrame?如果只是暴露给你,更好的只是你要确保不改变它...


3
投票

该StaticFrame包(其中我是作者),实现了熊猫一样的界面,和许多常见的熊猫操作,而强制执行标的与NumPy阵列和不可变系列和框架集装箱不变性。

你可以使整个大熊猫据帧不可改变通过与Frame转换为StaticFrame static_frame.Frame.from_pandas(df)。然后,你可以使用它作为一个真正的只读表。

见这个方法的StaticFrame文档:https://static-frame.readthedocs.io/en/latest/api_creation.html#static_frame.Series.from_pandas

© www.soinside.com 2019 - 2024. All rights reserved.