对dask数据帧样本的计算需要比所有数据更长的时间

时间:2018-03-09 03:03:42

标签: dask

我有一个dask数据框,由镶木地板支持。它是1.31亿行,当我在整个帧上做一些基本操作时,它们需要几分钟。

df = dd.read_parquet('data_*.pqt')
unique_locations = df.location.unique()
https = unique_locations.str.startswith('https:')
http = unique_locations.str.startswith('http:')
total_locations = len(unique_locations)
n_https = https.sum().compute()
n_http = http.sum().compute()

时间:

CPU times: user 2min 49s, sys: 23.9 s, total: 3min 13s
Wall time: 1min 53s

我天真地想,如果我采集了一些我可以带来的数据样本,并且做了:

df = dd.read_parquet('data_*.pqt')
df = df.sample(frac=0.05)
unique_locations = df.location.unique()
https = unique_locations.str.startswith('https:')
http = unique_locations.str.startswith('http:')
total_locations = len(unique_locations)
n_https = https.sum().compute()
n_http = http.sum().compute()

时间:

Unknown, I stopped it after 45minutes.

我猜测我的后续计算无法有效访问我的样本,但我不知道如何修复它。

我对从dask数据框中抽样数据的最佳方式感兴趣,然后使用该样本。

2 个答案:

答案 0 :(得分:0)

我没有明确/简单的答案,但我确实有许多事情可以共同解决我的问题。

1)我的代码效率低下,选择我需要处理的特定列使一切正常。我的新代码:

import dask.dataframe as dd
from dask.distributed import Client, progress
client = Client()  # Took me a little while to get the settings correct

def get_df(*columns):
    files = '../cache_new/sample_*.pqt'
    df = dd.read_parquet(files, columns=columns, engine='pyarrow')
    return df

# All data - Takes 31s
df_all = get_df('location')
unique_locations = df_all.location.unique()
https = unique_locations.str.startswith('https:')
http = unique_locations.str.startswith('http:')
_total_locations = unique_locations.size.persist()
_n_https = https.sum().persist()
_n_http = http.sum().persist()
progress(_total_locations, _n_https, _n_http)

# 1% sample data - Takes 21s
df_sample = get_df('location').sample(frac=0.01)
unique_locations = df_sample.location.unique()
https = unique_locations.str.startswith('https:')
http = unique_locations.str.startswith('http:')
_total_locations = unique_locations.size.persist()
_n_https = https.sum().persist()
_n_http = http.sum().persist()
progress(_total_locations, _n_https, _n_http)

事实证明这不是一个大的加速。整个计算所花费的时间主要是读取数据。如果计算非常昂贵,我想我会看到更多的加速。

2)我在本地切换到使用分布式调度程序,这样我就可以看到发生了什么。但这并非没有问题:

  1. 我遇到了由fastparquet造成的某种错误 我的流程死了,我需要使用pyarrow(这不是一个问题,不使用分布式客户端)
  2. 我必须手动设置线程数和memory_limit
  3. 3)我发现在笔记本中多次读取相同数据的错误 - https://github.com/dask/dask/issues/3268

    4)我也被pandas https://github.com/pandas-dev/pandas/issues/19941#issuecomment-371960712

    中的内存泄漏错误所困扰

    使用(3)和(4)以及在我的原始代码中我在所有列中读取效率都很低的事实,我看到了为什么我的样本从未发挥作用的一些原因,尽管我从未找到明确的答案。

答案 1 :(得分:0)

这里发生的事情是,通过添加样本,您可以停止优化。执行以下操作时:

df = dd.read_parquet('data_*.pqt')
df.x.sum()

Dask巧妙地将其重新排列为以下内容:

df = dd.read_parquet('data_*.pqt', columns=['x'])
df.x.sum()

Dask.dataframe只读取您需要的一列。这是dask.dataframe提供的为数不多的优化之一(它没有进行太多的高级优化)。

然而,当您在那里(或任何操作)抛出样本时

df = dd.read_parquet('data_*.pqt', columns=['x'])
df.sample(...).x.sum()

然后你没有得到优化,所以一切都很慢。

所以这里不是那个样本很慢,而是来自镶木地板的整个数据集很慢,而且在read_parquet和列访问步骤之间有样本阻止了优化的发生。

始终在read_parquet

中指定列

为避免这种情况,您应始终在dd.read_parquet中明确指定所需的列。

最终,很高兴看到一些高级框架提供的查询优化比Dask数据框架今天更加智能。如果你想推动这一进展,你可能会在Ibis

上提出问题