我有80万行x 8.7万列的实木复合地板文件。我将其加载到一个dask数据框中:
import dask.dataframe as dd
dask_train_df = dd.read_parquet('train.parquet')
dask_train_df.info()
这将产生:
<class 'dask.dataframe.core.DataFrame'>
Columns: 8712 entries, 0 to 8711
dtypes: int8(8712)
当我尝试执行dask_train_df.head()
或dask_train_df.loc[2:4].compute()
之类的简单操作时,即使有17 GB以上的RAM,也会出现内存错误。
但是,如果我这样做:
import pandas as pd
train = pd.read_parquet('../input/train.parquet')
train.info()
产量:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 800000 entries, 0 to 799999
Columns: 8712 entries, 0 to 8711
dtypes: int8(8712)
memory usage: 6.5 GB
我可以运行train.head()
和train.loc[2:4]
没问题,因为一切都已经在内存中了。
1)所以我的问题是,为什么这些简单的操作为什么会使用Dask Dataframe消耗内存,但是当我使用Pandas Dataframe将所有内容加载到内存时却能正常工作?
我注意到npartitions=1
,并且在文档read_parquet
中看到“将Parquet数据目录读入Dask.dataframe,每个分区一个文件”。就我而言,这似乎使我失去了拥有多个分区的所有并行化功能,但是Dask Dataframe的内存使用量不应该由单个Pandas Dataframe的内存量来限制吗?
2)还有一个附带的问题:如果我想通过在Dask Dataframe中对其进行分区来并行化单个镶木地板文件,我该怎么做?我在dd.read_parquet
签名中看不到blocksize参数。我也尝试过使用repartition函数,但是我相信沿行和拼花文件中的分区,我想沿列进行分区吗?
答案 0 :(得分:0)
首先,我想评论一下8712列相当多,您会发现解析架构/元数据可能会花费大量时间,不必担心数据加载。
fastparquet加载数据时,首先分配足够大小的数据帧,然后遍历列/块(具有适当的开销,在这种情况下显然很小),然后将值分配给分配的数据帧。
通过Dask运行计算(任何计算)时,在许多情况下,输入变量和其他中间对象的内存中可能存在任务内副本。这通常不是问题,因为应将整个数据集分为许多部分,并且小中间体的内存开销是能够处理大于内存的数据集的代价。我不确定您在何时获得副本,可能值得研究和预防。
在您的情况下,整个数据集是一个分区。这将导致单个加载任务在一个线程中运行。您将不会获得任何并行性,并且任何中间内部副本都将应用于整个数据集。通过选择列,您可以仅加载部分数据,从而制造分区并以这种方式实现并行性。但是,处理镶木地板数据的典型方法是利用“行组”分区(即沿索引)和多个文件,因此避免该问题的真正方法是使用已经适当分区的数据。
请注意,由于您可以直接使用fastparquet / pandas加载数据,因此也可以使用to_parquet
方法或fastparquet的write函数来保存分区版本。