计算pandas

时间:2016-12-12 21:01:19

标签: python-3.x pandas merge combinatorics

TL;博士

我的问题在于,当使用Pandas DataFrames作为组合图的一部分时,我在计算完整外部合并的每个部分预计会有多少行。

问题(下面重复)。

  1. 理想的解决方案是不要求合并并查询panel个对象。鉴于panel上没有查询方法,是否有一个更清晰的解决方案可以解决这个问题而不会达到内存上限?
  2. 如果2的答案为否,如何在不执行合并的情况下为每个组合计算所需合并表的大小?这可能是次优的方法,但在这种情况下,对于应用程序来说它是可以接受的。
  3. Python是否适合这种语言,或者我应该查看更为统计的语言,例如R或将其写在较低级别(ccython) - 数据库是不可能的。
  4. 问题

    最近,我重新编写了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的图表

    我正在尝试构建用于解决内存问题的方法是查看为合并提供的集合,预先确定合并将需要多少内存,然后如果该组合需要太多,则将其拆分为更小的组合,分别计算每一个,然后将最终的数据帧重新组合在一起(分而治之)。

    我的问题是我在计算合并的每个部分预计会有多少行。

    问题(从上面重复)

    1. 理想的解决方案是不要求合并并查询panel个对象。鉴于panel上没有查询方法,是否有一个更清晰的解决方案可以解决这个问题而不会达到内存上限?
    2. 如果2的答案为否,如何在不执行合并的情况下为每个组合计算所需合并表的大小?这可能是次优的方法,但在这种情况下,对于应用程序来说它是可以接受的。
    3. Python是否适合这种语言,或者我应该查看更为统计的语言,例如R,还是将其写在较低级别(ccython)。
    4. 为冗长的问题道歉。如果需要或可能的话,我很乐意提供更多信息。

      有人可以说明这可能是什么原因吗?

      谢谢。

1 个答案:

答案 0 :(得分:1)

问题1。

Dask通过使用hdf5文件作为临时存储来计算合并表“内存不足”,显示了很多承诺。

通过使用多处理来创建合并,dask还提供了超过/debug/commonlibrary.dll /debug/fr/commonlibrary.dll 的性能提升。不幸的是,这并没有延伸到pandas方法,因此在查询时性能提升会在查询时丢失。

它仍然不是一个完全可行的解决方案,因为在大型复杂的合并中,dask可能仍会耗尽内存。

问题2。

使用以下方法完全可以预先计算合并的大小。

  1. 按唯一键对每个数据帧进行分组并计算大小。
  2. 为每个数据框创建一组键名。
  3. 从2创建集合的交集。
  4. 为第1组和第2组
  5. 创建设置差异
  6. 要适应存储在唯一键中的query,请选择所有NAN值。如果一个帧包含nan而另一个不包含nan,则将另一个写为1。
  7. 表示交集中的集合,将每个np.nan
  8. 的计数相乘
  9. 从设置差异中添加计数
  10. 添加groupby('...').size()
  11. 的计数

    在python中,这可以写成:

    np.nan

    问题3

    这种方法在计算时相当繁重,并且可以更好地写入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) 以获得性能提升。