我的问题在于,当使用Pandas DataFrames作为组合图的一部分时,我在计算完整外部合并的每个部分预计会有多少行。
panel
个对象。鉴于panel
上没有查询方法,是否有一个更清晰的解决方案可以解决这个问题而不会达到内存上限?R
或将其写在较低级别(c
,cython
) - 数据库是不可能的。 最近,我重新编写了py-upset graphing library,以便在计算跨DataFrame的组合时更有效。我不是在寻找对此代码的评论,它在大多数情况下运行良好,我对这种方法感到满意。我现在正在寻找的是一个非常具体的问题的答案;在处理大型数据集时发现。
我重写的方法是在完整外连接上制定所有提供的数据帧的内存中合并,如480 - 502 of pyupset.resources
行所示
for index, key in enumerate(keys):
frame = self._frames[key]
frame.columns = [
'{0}_{1}'.format(column, key)
if column not in self._unique_keys
else
column
for column in self._frames[key].columns
]
if index == 0:
self._merge = frame
else:
suffixes = (
'_{0}'.format(keys[index-1]),
'_{0}'.format(keys[index]),
)
self._merge = self._merge.merge(
frame,
on=self._unique_keys,
how='outer',
copy=False,
suffixes=suffixes
)
对于使用连接的中小型数据帧,效果非常好。事实上,最近的性能测试表明,它可以在不到一分钟的时间内处理包含10,000行的5或6个数据集,这对于我需要的应用程序结构来说已经足够了。
问题现在从基于时间变为基于记忆。
鉴于可能有数千条记录的数据集,即使在大型服务器上,该库也会很快耗尽内存。
为了正确看待这个问题,我的这个应用程序的测试机器是一个8核VMWare盒子,其中128GiB RAM运行Centos7。
考虑到以下数据集大小,在添加第5个数据帧时,内存使用量呈指数级增长。这是非常令人期待的,但强调了我面临的问题的核心。
Rows | Dataframe
------------------------
13963 | dataframe_one
48346 | dataframe_two
52356 | dataframe_three
337292 | dataframe_four
49936 | dataframe_five
24542 | dataframe_six
258093 | dataframe_seven
16337 | dataframe_eight
这些不是" 小"数据帧的行数虽然每列的列数限制为一个唯一键+4个非唯一列。 pandas
中每列的大小为
column | type | unique
--------------------------
X | object | Y
id | int64 | N
A | float64 | N
B | float64 | N
C | float64 | N
当内存被吃掉时,此合并可能会导致问题。偶尔它会因MemoryError中止(很好,我可以捕获并处理它们),有时内核接管并在系统变得不稳定之前简单地杀死应用程序,偶尔,系统会挂起并变得无响应/不稳定直到最终内核杀死应用程序并释放内存。
示例输出(内存大小近似值):
[INFO] Creating merge table
[INFO] Merging table dataframe_one
[INFO] Data index length = 13963 # approx memory <500MiB
[INFO] Merging table dataframe_two
[INFO] Data index length = 98165 # approx memory <1.8GiB
[INFO] Merging table dataframe_three
[INFO] Data index length = 1296665 # approx memory <3.0GiB
[INFO] Merging table dataframe_four
[INFO] Data index length = 244776542 # approx memory ~13GiB
[INFO] Merging table dataframe_five
Killed # > 128GiB
生成合并表后,会以集合组合查询,以生成类似于https://github.com/mproffitt/py-upset/blob/feature/ISSUE-7-Severe-Performance-Degradation/tests/generated/extra_additional_pickle.png的图表
我正在尝试构建用于解决内存问题的方法是查看为合并提供的集合,预先确定合并将需要多少内存,然后如果该组合需要太多,则将其拆分为更小的组合,分别计算每一个,然后将最终的数据帧重新组合在一起(分而治之)。
我的问题是我在计算合并的每个部分预计会有多少行。
panel
个对象。鉴于panel
上没有查询方法,是否有一个更清晰的解决方案可以解决这个问题而不会达到内存上限?R
,还是将其写在较低级别(c
,cython
)。为冗长的问题道歉。如果需要或可能的话,我很乐意提供更多信息。
有人可以说明这可能是什么原因吗?
谢谢。
答案 0 :(得分:1)
Dask通过使用hdf5文件作为临时存储来计算合并表“内存不足”,显示了很多承诺。
通过使用多处理来创建合并,dask还提供了超过/debug/commonlibrary.dll
/debug/fr/commonlibrary.dll
的性能提升。不幸的是,这并没有延伸到pandas
方法,因此在查询时性能提升会在查询时丢失。
它仍然不是一个完全可行的解决方案,因为在大型复杂的合并中,dask可能仍会耗尽内存。
使用以下方法完全可以预先计算合并的大小。
query
,请选择所有NAN值。如果一个帧包含nan而另一个不包含nan,则将另一个写为1。np.nan
groupby('...').size()
值在python中,这可以写成:
np.nan
这种方法在计算时相当繁重,并且可以更好地写入def merge_size(left_frame, right_frame, group_by):
left_groups = left_frame.groupby(group_by).size()
right_groups = right_frame.groupby(group_by).size()
left_keys = set(left_groups.index)
right_keys = set(right_groups.index)
intersection = right_keys & left_keys
left_sub_right = left_keys - intersection
right_sub_left = right_keys - intersection
left_nan = len(left_frame.query('{0} != {0}'.format(group_by)))
right_nan = len(right_frame.query('{0} != {0}'.format(group_by)))
left_nan = 1 if left_nan == 0 and right_nan != 0 else left_nan
right_nan = 1 if right_nan == 0 and left_nan != 0 else right_nan
sizes = [(left_groups[group_name] * right_groups[group_name]) for group_name in intersection]
sizes += [left_groups[group_name] for group_name in left_sub_right]
sizes += [right_groups[group_name] for group_name in right_sub_left]
sizes += [left_nan * right_nan]
return sum(sizes)
以获得性能提升。