可以memmap pandas系列。数据框呢?

浏览:54日期:2024-03-06
如何解决可以memmap pandas系列。数据框呢??

好…经过大量挖掘,这是怎么回事。PandasDataFrame使用BlockManager该类在内部组织数据。与文档相反,DataFrame不是系列的集合,而是类似dtyped矩阵的集合。Blockmanger将所有float列组合在一起,将所有int列组合在一起,等等…,并且它们的内存(据我所知)保持在一起。

如果提供单个ndarray矩阵(单个类型),则无需复制内存即可做到这一点。请注意,BlockManager(理论上)还支持在其构造中不复制混合类型数据,因为可能不必将此输入复制到相同类型的块中。但是,如果单个矩阵是数据参数,则DataFrame构造函数不会仅进行复制。

简而言之,如果您将混合类型或多个数组作为构造函数的输入,或者为dict提供单个数组,则您在Pandas中不走运,DataFrame的默认BlockManager将复制您的数据。

无论如何,解决此问题的一种方法是强制BlockManager不要按类型合并,而是将每列保留为单独的“块”。所以,有了猴子修补魔法…

from pandas.core.internals import BlockManagerclass BlockManagerunconsolidated(BlockManager): def __init__(self, *args, **kwargs):BlockManager.__init__(self, *args, **kwargs)self._is_consolidated = Falseself._kNown_consolidated = False def _consolidate_inplace(self): pass def _consolidate(self): return self.blocksdef df_from_arrays(arrays, columns, index): from pandas.core.internals import make_block def gen():_len = Nonep = 0for a in arrays: if _len is None:_len = len(a)assert len(index) == _len assert _len == len(a) yield make_block(values=a.reshape((1,_len)), placement=(p,)) p+=1 blocks = tuple(gen()) mgr = BlockManagerunconsolidated(blocks=blocks, axes=[columns, index]) return pd.DataFrame(mgr, copy=False)

如果指定copy = False,则DataFrame或Blockmanger最好具有consolidate = False(或假设有此行为)。

去测试:

def assert_readonly(iloc): try: iloc[0] = 999 # Should be non-editable raise Exception('MUST BE READ ONLY (1)') except ValueError as e: assert 'read-only' in e.message # Original ndarray n = 1000 _arr = np.arange(0,1000, dtype=float) # Convert it to a memmap mm = np.memmap(filename, mode=’w+’, shape=_arr.shape, dtype=_arr.dtype) mm[:] = _arr[:] del _arr mm.flush() mm.flags[’WRITEABLE’] = False # Make immutable!df = df_from_arrays( [mm, mm, mm], columns=[’a’, ’b’, ’c’], index=range(len(mm)))assert_read_only(df['a'].iloc)assert_read_only(df['b'].iloc)assert_read_only(df['c'].iloc)

对于我来说,将BlockManager类似类型的数据保存在一起是否真的有实际的好处-在Pandas中的大多数操作都是按行标签或逐列进行操作-这是DataFrame由于结构的异构通常仅通过其索引关联的列。尽管可行的是,他们在每个“块”中保留一个索引,但是如果索引在块中保留偏移量,则可以从中受益(如果是这种情况,那么他们应该按进行分组sizeof(dtype),我认为情况并非如此)。呵呵…

关于提供非复制构造函数的PR进行了一些讨论,但被放弃了。

看来有逐步淘汰BlockManager的明智计划,因此您的工作量很多。

另请参阅引擎盖下的熊猫,这对我很有帮助。

解决方法

似乎我可以通过创建mmap’d ndarray并使用它来初始化python系列的memmap底层数据。

def assert_readonly(iloc): try: iloc[0] = 999 # Should be non-editable raise Exception('MUST BE READ ONLY (1)') except ValueError as e: assert 'read-only' in e.message# Original ndarrayn = 1000_arr = np.arange(0,1000,dtype=float)# Convert it to a memmapmm = np.memmap(filename,mode=’w+’,shape=_arr.shape,dtype=_arr.dtype)mm[:] = _arr[:]del _arrmm.flush()mm.flags[’WRITEABLE’] = False # Make immutable!# Wrap as a seriess = pd.Series(mm,name='a')assert_readonly(s.iloc)

成功!似乎它s由只读的内存映射ndarray支持。我可以对DataFrame做同样的事情吗?以下失败

df = pd.DataFrame(s,copy=False,columns=[’a’])assert_readonly(df['a']) # Fails

以下成功,但仅适用于一列:

df = pd.DataFrame(mm.reshape(len(mm,1)),columns=[’a’],copy=False)assert_readonly(df['a']) # Succeeds

…这样我 就可以 不复制而制作DF。但是,这仅适用于一列,我想要很多。我发现了用于组合1列DF的方法:pd.concat(.. copy =False),pd.merge(copy = False),…产生副本。

我有成千上万的大列作为数据文件,一次只需要几列。我希望能够将它们的mmap表示形式放置在上面的DataFrame中。可能吗?

Pandas文档使我们很难猜测这里到底发生了什么-尽管它确实说一个DataFrame“可以认为是Series对象的类似dict的容器”。。我开始不再是这种情况了。

我宁愿不需要HD5来解决这个问题。

相关文章: