我有几个文件,其中有一列被调用idx,我想将它用作索引。获得的数据帧大约有 13M 行。我知道我可以通过这种方式读取和分配索引(这很慢~40秒)
df = dd.read_parquet("file-*.parq")
df = df.set_index("idx")
Run Code Online (Sandbox Code Playgroud)
或以其他方式(快约 40 毫秒)
df = dd.read_parquet("file-*.parq", index = "idx")
Run Code Online (Sandbox Code Playgroud)
使用第二种方法计算长度的简单操作要快 4 倍。我不明白的是
df.known_divisions返回,True而在第二种情况下是False。我期待相反的行为。然后我df在没有 known_division 的情况下做了几个操作,我总是获得更好的性能。我正在挠头想知道这是否是故意发生的。更新
这不仅仅是计算len哪个更快。在我的计算中,我使用 groupby 创建了 4 个新数据帧,多次申请和加入,这些是时间
| |Load and reindex (s)|Load with index (s)|
|:-----------------|-------------------:|------------------:|
| load | 12.5000 | 0.0124 |
| grp, apply, join | 11.4000 | 6.2700 |
| compute() | 146.0000 | 125.0000 |
| TOTAL | 169.9000 | 131.2820 |
Run Code Online (Sandbox Code Playgroud)
当您使用第一种方法时,dask 会加载数据,并在执行您要求的任何计算之前按您选择的列的值对行进行分区(这涉及对所有磁盘上的块进行洗牌)。在计算长度的情况下,这都是浪费时间,因为了解索引划分对此没有任何帮助,但涉及该索引的进一步计算(例如,连接操作)会快得多。
在第二个版本中,您断言您选择的列是索引,但如果您没有明确要求,dask 不会对数据进行混洗。如果碰巧在 parquet 元数据中保存了统计信息,并且每个 parquet 块的最大/最小值是这样的,那么它们形成一个单调序列(即,第二个块中的所有“idx”值都大于所有第一个中的值等),那么您将像以前一样了解涉及索引的某些操作的划分和优化性能。如果不满足这些条件,则您已设置索引列,但分区是未知的 - 这对于计算长度来说完全没问题。