具有自定义索引的分区Dask Dataframe

时间:2019-01-22 11:43:26

标签: python partitioning dask data-partitioning

我有一个与此类似的巨大的Dask数据框

|Ind| C1 | C2 |....| Cn |
|-----------------------|
| 1 |val1| AE |....|time|
|-----------------------|
| 2 |val2| FB |....|time|
|-----------------------|
|...|....| .. |....| ...|
|-----------------------|
|n-1|valx| ZK |....|time|
| n |valn| QK |....|time|

我想根据C2列的唯一值对其重新分区,然后将函数映射到每个分区。

首先,我将C2设置为索引:

df = dd.readcsv(...)

df = df.set_index(df.C2)

现在,我想对新索引的数据帧重新分区,然后将函数映射到每个分区。我当前的方法如下:

unique_c2 = df.index.unique().compute()

df = df.repartition(division=list(unique_c2))

# list(unique_c2) looks like this: ['AE', 'FB', ..., 'ZK', 'QK']

df.map_partitions(lambda x: my_func(x), meta=df)

我想要的分区应如下所示:

|Ind | C1 | C2 |....| Cn |
|------------------------|
| AE |val1| AE |....|time|
|------------------------|
| AE |val2| AE |....|time|
|------------------------|
|....|....| .. |....| ...|
|------------------------|
| AE |valn| AE |....|time|

...

|Ind | C1 | C2 |....| Cn |
|------------------------|
| ZK |val1| ZK |....|time|
|------------------------|
| ZK |val2| ZK |....|time|
|------------------------|
|....|....| .. |....| ...|
|------------------------|
| ZK |valn| ZK |....|time|

|Ind | C1 | C2 |....| Cn |
|------------------------|
| QK |val1| QK |....|time|
|------------------------|
| QK |val2| QK |....|time|
|------------------------|
|....|....| .. |....| ...|
|------------------------|
| QK |valn| QK |....|time|

但是重新分区函数“合并”了我的最后两个索引,所以我的最后一个分区看起来像这样:

|Ind | C1 | C2 |....| Cn |
|------------------------|
| ZK |val1| ZK |....|time|
|------------------------|
| ZK |val2| ZK |....|time|
|------------------------|
|....|....| .. |....| ...|
|------------------------|
| QK |valn| QK |....|time|
|------------------------|
|....|....| .. |....| ...|
|------------------------|
| QK |valn| QK |....|time|

为什么会发生这种情况,或者您对我的问题有更好的解决方案?我知道有一个dask.groupby(...).apply(...)。但是我的映射函数有副作用,并且apply(...)总是按设计对每个dask分区执行两次。

1 个答案:

答案 0 :(得分:2)

由于分区的设计方式,分区的数量始终为(分区的数量+ 1)。来自docs

分区包括每个分区索引的最小值, 最后一个分区的索引的最大值。

由于设置了divisions=list(unique_c2),因此与唯一的c2值的划分数目相同,因此要进行划分。因此,分区数将比您想要的少一分。

您可以通过将代码更改为以下内容来解决此问题:

    unique_c2_list = list(df.index.unique().compute())

    df = df.repartition(divisions=sorted(unique_c2_list + [unique_c2_list[-1]]))

这会将最后一个唯一的c2值添加到除法列表的末尾。对于最后的划分,c2的最小值和最大值将相同,因此这将产生所需数量的分区,并防止最后两个分区合并。