可以memmap pandas系列。数据框呢?
Can memmap pandas series. What about a dataframe?
看来我可以通过创建一个 mmap'd ndarray 并使用它来初始化系列来 memmap 一个 python 系列的基础数据。
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!
# Wrap as a series
s = 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 "Can be thought of as a dict-like container for Series objects."。我开始意识到这不再是这种情况了。
我宁愿不需要 HD5 来解决这个问题。
如果您更改 DataFrame 构造函数以添加参数 copy=False,您将获得所需的行为。
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html
编辑:另外,您想使用底层的 ndarray(而不是 pandas 系列)。
好的...经过大量挖掘后,这就是发生的事情。
Pandas' DataFrame
使用 BlockManager
class 在内部组织数据。与文档相反,DataFrame
不是系列的集合,而是 类似 dtyped 矩阵 的集合。 BlockManger
将所有 float 列组合在一起,将所有 int 列组合在一起,等等......,并且它们的内存(据我所知)保持在一起。
仅当提供单个 ndarray
矩阵(单一类型)时,才可以在不复制内存的情况下做到这一点。请注意,BlockManager
(理论上)在其构造中也支持不复制混合类型数据,因为可能没有必要将此输入复制到相同类型的分块中。但是,DataFrame
构造函数仅在单个矩阵是数据参数时才进行复制。
简而言之,如果您将混合类型或多个数组作为构造函数的输入,或者提供一个包含单个数组的字典,那么您在 Pandas 和 DataFrame
中就不走运了的默认 BlockManager
将复制您的数据。
无论如何,解决此问题的一种方法是强制 BlockManager
不按类型合并,而是将每一列保持为单独的 'block'。所以,有了猴子修补魔法......
from pandas.core.internals import BlockManager
class BlockManagerUnconsolidated(BlockManager):
def __init__(self, *args, **kwargs):
BlockManager.__init__(self, *args, **kwargs)
self._is_consolidated = False
self._known_consolidated = False
def _consolidate_inplace(self): pass
def _consolidate(self): return self.blocks
def df_from_arrays(arrays, columns, index):
from pandas.core.internals import make_block
def gen():
_len = None
p = 0
for 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
得出的,它是一种异构列的结构,通常只与其索引相关联。尽管他们每个 'block' 保留一个索引是可行的,但如果索引在块中保持偏移量则可以获得好处(如果是这种情况,那么他们应该按 sizeof(dtype)
分组,我认为这不是案子)。
呵呵...
有一些关于 provide a non-copying constructor 的 PR 的讨论被放弃了。
看来是有道理的plans to phase out BlockManager
,所以你的里程有很多不同。
又见Pandas under the hood,对我帮助很大
看来我可以通过创建一个 mmap'd ndarray 并使用它来初始化系列来 memmap 一个 python 系列的基础数据。
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!
# Wrap as a series
s = 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 "Can be thought of as a dict-like container for Series objects."。我开始意识到这不再是这种情况了。
我宁愿不需要 HD5 来解决这个问题。
如果您更改 DataFrame 构造函数以添加参数 copy=False,您将获得所需的行为。 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html
编辑:另外,您想使用底层的 ndarray(而不是 pandas 系列)。
好的...经过大量挖掘后,这就是发生的事情。
Pandas' DataFrame
使用 BlockManager
class 在内部组织数据。与文档相反,DataFrame
不是系列的集合,而是 类似 dtyped 矩阵 的集合。 BlockManger
将所有 float 列组合在一起,将所有 int 列组合在一起,等等......,并且它们的内存(据我所知)保持在一起。
仅当提供单个 ndarray
矩阵(单一类型)时,才可以在不复制内存的情况下做到这一点。请注意,BlockManager
(理论上)在其构造中也支持不复制混合类型数据,因为可能没有必要将此输入复制到相同类型的分块中。但是,DataFrame
构造函数仅在单个矩阵是数据参数时才进行复制。
简而言之,如果您将混合类型或多个数组作为构造函数的输入,或者提供一个包含单个数组的字典,那么您在 Pandas 和 DataFrame
中就不走运了的默认 BlockManager
将复制您的数据。
无论如何,解决此问题的一种方法是强制 BlockManager
不按类型合并,而是将每一列保持为单独的 'block'。所以,有了猴子修补魔法......
from pandas.core.internals import BlockManager
class BlockManagerUnconsolidated(BlockManager):
def __init__(self, *args, **kwargs):
BlockManager.__init__(self, *args, **kwargs)
self._is_consolidated = False
self._known_consolidated = False
def _consolidate_inplace(self): pass
def _consolidate(self): return self.blocks
def df_from_arrays(arrays, columns, index):
from pandas.core.internals import make_block
def gen():
_len = None
p = 0
for 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
得出的,它是一种异构列的结构,通常只与其索引相关联。尽管他们每个 'block' 保留一个索引是可行的,但如果索引在块中保持偏移量则可以获得好处(如果是这种情况,那么他们应该按 sizeof(dtype)
分组,我认为这不是案子)。
呵呵...
有一些关于 provide a non-copying constructor 的 PR 的讨论被放弃了。
看来是有道理的plans to phase out BlockManager
,所以你的里程有很多不同。
又见Pandas under the hood,对我帮助很大