Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 熊猫平行分组消耗大量内存_Python_Pandas_Group By - Fatal编程技术网

Python 熊猫平行分组消耗大量内存

Python 熊猫平行分组消耗大量内存,python,pandas,group-by,Python,Pandas,Group By,我有一个中等大小的文件(~300MB),其中包含一个个人列表(~300k)和他们执行的操作。我正在尝试使用groupBy和所描述的apply的并行版本为每个人应用一个操作。看起来像这样 import pandas import multiprocessing from joblib import Parallel, delayed df = pandas.read_csv(src) patients_table_raw = apply_parallel(df.groupby('ID'), f)

我有一个中等大小的文件(~300MB),其中包含一个个人列表(~300k)和他们执行的操作。我正在尝试使用
groupBy
和所描述的
apply
的并行版本为每个人应用一个操作。看起来像这样

import pandas
import multiprocessing
from joblib import Parallel, delayed

df = pandas.read_csv(src)
patients_table_raw = apply_parallel(df.groupby('ID'), f)

def applyParallel(dfGrouped, func):
    retLst = Parallel(n_jobs=multiprocessing.cpu_count())(delayed(func)(group) for name, group in dfGrouped)
    return pd.concat(retLst)
但不幸的是,这会占用大量的空间。我认为这与以下事实有关:

list_groups = list(df.groupby('ID'))
消耗数GB内存!如何处理?我最初的想法是在小的“堆栈”中迭代groupBy,不消耗太多内存(但我没有找到一种不将其转换为列表的方法)

更详细的背景 我有以下方式的简单CSV数据集:

|-------------------------|
| ID | Timestamp | Action |
|-------------------------|
|1   | 0         | A      |
|1   | 10        | B      |
|1   | 20        | C      |
|2   | 0         | B      |
|2   | 15        | C      |
         ...
我基本上要做的是创建一个不同的表,其中包含对个体及其ID的操作序列/时间戳的描述。这将帮助我找回个人

|------------------|
| ID | Description |
|------------------|
|1   | 0A10B20C    |
|2   | 0B15C       |
         ...
为了做到这一点,并遵循python的方式,我的想法基本上是加载pandas数据帧中的第一个表groupBy the ID,并在分组中应用一个函数,该函数返回每个组(每个ID)所需的表的一行。然而,我的数据集中有很多个人(大约100万),groupBy操作非常昂贵(没有明确的垃圾收集,正如我在自己的回答中提到的)。此外,并行化groupBy意味着大量的内存使用,因为显然有些东西会被复制


因此,更详细的问题是:如何使用groupBy(从而使数据处理速度比实现自己的循环更快),而不产生如此巨大的内存开销?

一些评论,然后我找到了解决方案:

  • 我试过
    dask
    ,但没什么不同。我猜这是因为文件不够大,无法使用辅助内存

  • 如果在应用于组的函数中执行垃圾收集,内存性能将显著提高。我已经通过一个简单的
    gc.collect()
    做到了这一点,它每10000美元交互一次。比如:

    x['ID'].head(1).values[0] % 10000 == 0:
        gc.collect()
    
  • 垃圾收集实际上使我的并行版本运行。但是
    返回pd.concat(retLst)
    是另一个巨大的瓶颈,消耗了大量内存

我的最终解决方案是以外部方式平行化该解决方案:

  • 我创建了一个函数,它将执行groupBy和apply,用于ID在[X,Y]范围内的个人

  • 我只是创建一个池并并行运行它们。根据文件的范围,每个进程用不同的名称保存一个文件

    f = functools.partial(make_patient_tables2, src="in", dest="out")
    range_of = [(0, 10000), (10000, 20000), (20000, 30000)]
    with Pool(cpu_count()) as p:
        ret_list = p.map(f, range_of)
    
  • 最后但并非最不重要的一点是,我连接了所有生成的文件

请注意,这仍然有点内存密集,因为我们必须复制表的读取(这是在make_patient_表2中完成的,但无论如何都会发生,因为多处理不共享资源。因此,更好的解决方案将解决共享资源的问题,但垃圾收集器+不使用concat+复制原始数据2-3次就够了

当然不漂亮。希望它能对其他人有所帮助。

试试这个(没有并行化):


还有一种选择!使用Apache Spark.:Dhahahaha,应该是一次性的,所以我不想太花哨!但这是合理的方法!谢谢你真的需要在这么大的文件上进行并行化吗?只需串行工作就容易多了。如果你确实需要它,请查看
dask
。我同意@chrisb-我认为你不需要并行化理顺你的计算——通常使用Pandas会比较慢。你能用一个样本数据集、你将要实现的目标的简短描述和所需的数据集发布一个问题吗?在这种情况下,社区可能会找到一个最佳的解决方案solution@ManoelRibeiro,我添加了一个答案-你能用你的真实数据检查一下吗?嘿!我已经试过了,而且效率很高。奇怪的是,在您的方法中没有出现垃圾收集问题。但是,这种方法不是完全通用的(实际上在真正的数据集中,您有一点更复杂的描述和表),因此您有点“需要”应用,因为仅仅求和并不能解决它。我想知道应用泛型函数是否会造成我遇到的所有问题。@ManoelRibeiro,
通常效率很低,所以我们希望尽可能避免它
In [87]: df
Out[87]:
   ID  Timestamp Action
0   1          0      A
1   1         10      B
2   1         20      C
3   2          0      B
4   2         15      C

In [88]: df.set_index('ID').astype(str).sum(axis=1).groupby(level=0).sum().to_frame('Description').reset_index()
Out[88]:
   ID Description
0   1    0A10B20C
1   2       0B15C