Dask dataframe:“set_index”可以将单个索引放入多个分区吗?

Dah*_*ahn 6 python indexing dataframe dask

根据经验,每当您set_index使用 Dask 数据帧时,Dask 总是会将具有相同索引的行放入单个分区中,即使这会导致分区严重不平衡。

这是一个演示:

import pandas as pd
import dask.dataframe as dd

users = [1]*1000 + [2]*1000 + [3]*1000

df = pd.DataFrame({'user': users})
ddf = dd.from_pandas(df, npartitions=1000)

ddf = ddf.set_index('user')

counts = ddf.map_partitions(lambda x: len(x)).compute()
counts.loc[counts > 0]
# 500    1000
# 999    2000
# dtype: int64
Run Code Online (Sandbox Code Playgroud)

然而,我在任何地方都找不到这种行为的保证。

我曾尝试自己筛选代码,但放弃了。我相信这些相互关联的函数之一可能包含答案:

当您时set_index,单个索引是否永远不能位于两个不同的分区中?如果不是,那么该财产在什么条件下成立?


赏金:我将向来自信誉良好的来源的答案授予赏金。例如,引用实现来表明该属性必须成立。

Gab*_*eph 2

单个索引是否永远不能位于两个不同的分区中?

不,这当然是允许的。达斯克甚至打算让这种情况发生。然而,由于中的一个错误set_index,所有数据最终仍将位于一个分区中。

一个极端的例子(除了一个之外,每一行都是相同的值):

In [1]: import dask.dataframe as dd
In [2]: import pandas as pd
In [3]: df = pd.DataFrame({"A": [0] + [1] * 20})
In [4]: ddf = dd.from_pandas(df, npartitions=10)
In [5]: s = ddf.set_index("A")
In [6]: s.divisions
Out[6]: (0, 0, 0, 0, 0, 0, 0, 1)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,Dask 打算将0s 分割到多个分区之间。然而,当真正发生洗牌时,所有0s 仍然最终位于一个分区中:

In [7]: import dask
In [8]: dask.compute(s.to_delayed())  # easy way to see the partitions separately
Out[8]: 
([Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [],
  Empty DataFrame
  Columns: []
  Index: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],)
Run Code Online (Sandbox Code Playgroud)

这是因为决定一行属于哪个输出分区的代码不考虑 中的重复项divisions。作为divisions一个系列,它使用searchsortedwith side="right",这就是为什么所有数据总是在最后一个分区中结束的原因。

问题解决后我会更新这个答案。