我正在尝试从一堆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])
似乎熊猫不喜欢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}}。相反,默认ndarray
为dtype=
,生成的object
被强制为Index
。
int64
上一个例子只是一个启动者。我想要构建的真实>>> 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
而没有任何副本,我真的希望从您的体验中受益。