Pandas零拷贝MultiIndex / FrozenNDArray创建

时间:2017-12-02 10:38:44

标签: pandas numpy

我正在尝试从一堆numpy DataFrame创建一个pandas ndarray而不复制任何东西。总体目标是在共享内存的多个进程之间共享一个巨大的DataFrame

有关我的环境的一些信息:

  • pandas 0.18.0
  • numpy 1.10.4
  • python 3.5

我用来检索ndarray s的基础数据指针的函数:

def ndarray_data_ptr(a):
    return hex(a.__array_interface__['data'][0])

问题1

似乎熊猫不喜欢int16索引。它会默默地将它们转换为int64并制作副本,即使我特别要求零拷贝。

>>> import pandas as pd
>>> import numpy as np

>>> data = np.array([1.23, 4.56, 7.89], dtype=np.dtype(np.float64))
>>> index = np.array([1, 2, 3], dtype=np.dtype(np.int16))

>>> df = pd.DataFrame(
...     data=val,
...     index=pd.Index(idx, copy=False),
...     copy=False)

>>> print('data', ndarray_data_ptr(data))
data 0x2322790

>>> print('index', ndarray_data_ptr(index))
index 0x228d680

>>> print('df data', ndarray_data_ptr(df.values))
df data 0x2322790

>>> print('df index', ndarray_data_ptr(df.index.values))
df index 0x218a100

我设法在创建dtype 时明确提供所需的pd.Index来克服此问题。它似乎现在按预期工作,即使大熊猫的行为不是很明显。我原本期望构造函数的dtype=的默认值为None,并重新使用提供的dtype的{​​{1}}。相反,默认ndarraydtype=,生成的object被强制为Index

int64

问题2

上一个例子只是一个启动者。我想要构建的真实>>> df = pd.DataFrame( ... data=data, ... index=pd.Index(index, copy=False, dtype=index.dtype), ... copy=False) >>> print('data', ndarray_data_ptr(data)) data 0x2403780 >>> print('index', ndarray_data_ptr(index)) index 0x1abe930 >>> print('df data', ndarray_data_ptr(df.values)) df data 0x2403780 >>> print('df index', ndarray_data_ptr(df.index.values)) df index 0x1abe930 实际上使用DataFrame

MultiIndex

索引级别已正确重复使用而没有复制,而索引标签已被复制。实际上,我注意到标签不是>>> data = np.array([1.23, 4.56, 7.89], dtype=np.dtype(np.float64)) >>> index_levels = [ >>> np.array([1, 2, 3], dtype=np.dtype(np.int16)), >>> np.array([4, 5, 6], dtype=np.dtype(np.int16)), >>> ] >>> index_labels = [ >>> np.array([0, 1, 2], dtype=np.dtype(np.int16)), >>> np.array([0, 1, 2], dtype=np.dtype(np.int16)), >>> ] >>> df = pd.DataFrame( >>> data=data, >>> index=pd.MultiIndex( >>> levels=[ >>> pd.Index(index_levels[0], dtype=index_levels[0].dtype, copy=False), >>> pd.Index(index_levels[1], dtype=index_levels[1].dtype, copy=False), >>> ], >>> labels=[ >>> pd.core.base.FrozenNDArray(index_labels[0], dtype=index_labels[0].dtype, copy=False), >>> pd.core.base.FrozenNDArray(index_labels[1], dtype=index_labels[1].dtype, copy=False), >>> ], >>> copy=False, >>> ), >>> copy=False) >>> print('index level 0', ndarray_data_ptr(index_levels[0])) index level 0 0x24adf70 >>> print('index level 1', ndarray_data_ptr(index_levels[1])) index level 1 0x24a7d90 >>> print('index label 0', ndarray_data_ptr(index_labels[0])) index label 0 0x1400b10 >>> print('index label 1', ndarray_data_ptr(index_labels[1])) index label 1 0x25d34f0 >>> print('df index level 0', ndarray_data_ptr(df.index.levels[0].values)) df index level 0 0x24adf70 >>> print('df index level 1', ndarray_data_ptr(df.index.levels[1].values)) df index level 1 0x24a7d90 >>> print('df index label 0', ndarray_data_ptr(df.index.labels[0])) df index label 0 0x24c0ad0 >>> print('df index label 1', ndarray_data_ptr(df.index.labels[1])) df index label 1 0x24c0ad0 ,而是pandas使用pd.Index实例,所以我试图用问题1 中使用的相同技术欺骗它们,但这显然是还不够。

构建pd.core.base.FrozenNDArray时,即使dtype的{​​{1}}也被强制转移到FrozenNDArray

int8

MultiIndex的情况下,我花了很多时间弄清楚如何防止这种>>> df.index.levels[0] Int64Index([1, 2, 3], dtype='int16') >>> df.index.levels[1] Int64Index([4, 5, 6], dtype='int16') >>> df.index.labels[0] FrozenNDArray([0, 1, 2], dtype='int8') >>> df.index.labels[1] FrozenNDArray([0, 1, 2], dtype='int8') 强制,但我仍然无法弄清楚如何。

在我的实际问题中,整体dtype约为40GB,索引标签约占300MB。我想防止这种不必要的每进程内存开销。

如果有人设法从共享内存中构建pandas MultiIndex,或者只创建DataFrame而没有任何副本,我真的希望从您的体验中受益。

0 个答案:

没有答案