我有一个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数据框中抽样数据的最佳方式感兴趣,然后使用该样本。
答案 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)我在本地切换到使用分布式调度程序,这样我就可以看到发生了什么。但这并非没有问题:
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和列访问步骤之间有样本阻止了优化的发生。
为避免这种情况,您应始终在dd.read_parquet
中明确指定所需的列。
最终,很高兴看到一些高级框架提供的查询优化比Dask数据框架今天更加智能。如果你想推动这一进展,你可能会在Ibis
上提出问题