我遇到了一个问题,必须跨多个核心处理数据。设df为Pandas DataFrameGroupBy(size()
(对象。每个值表示计算的";成本;每个GroupBy都有用于核心的。我如何将df划分为不相等大小的n个仓,并且具有相同的(近似(计算成本?
import pandas as pd
import numpy as np
size = 50
rng = np.random.default_rng(2021)
df = pd.DataFrame({
"one": np.linspace(0, 10, size, dtype=np.uint8),
"two": np.linspace(0, 5, size, dtype=np.uint8),
"data": rng.integers(0, 100, size)
})
groups = df.groupby(["one", "two"]).sum()
df
one two data
0 0 0 75
1 0 0 75
2 0 0 49
3 0 0 94
4 0 0 66
...
45 9 4 12
46 9 4 97
47 9 4 12
48 9 4 32
49 10 5 45
人们通常将数据集划分为n个bin,例如下面的代码。然而,将数据集拆分为n个相等的部分是不可取的,因为核心接收到非常不平衡的工作负载,例如205对788。
n = 4
bins = np.array_split(groups, n) # undesired
[b.sum() for b in bins] #undesired
[data 788
dtype: int64, data 558
dtype: int64, data 768
dtype: int64, data 205
dtype: int64]
所需的解决方案是将数据划分为大小不等且具有近似相等的大求和值的仓。即CCD_ 2之间的差异小于先前方法CCD_。差异应尽可能小。应该如何实现的简单列表示例:
# only an example to demonstrate desired functionality
example = [[[10, 5], 45], [[2, 1], 187], [[3, 1], 249], [[6, 3], 262]], [[[9, 4], 153], [[4, 2], 248], [[1, 0], 264]], [[[8, 4], 245], [[7, 3], 326]], [[[5, 2], 189], [[0, 0], 359]]
[sum([size for (group, size) in test]) for test in t] # [743, 665, 571, 548]
是否有一种更有效的方法可以将数据集拆分为如上所述的panda或numpy中的bin?
拆分/bin GroupBy对象非常重要,以类似于np.array_split()
返回的方式访问数据。
我认为已经找到了一个很好的方法。归功于一位同事。
其思想是对组大小进行排序(按降序(,并将组放入"0"中的箱中;后向S"-图案让我举例说明。假设n = 3
(仓数(和以下数据:
groups
data
0 359
1 326
2 264
3 262
4 249
5 248
6 245
7 189
8 187
9 153
10 45
这个想法是把一组人放在一个箱子里;"从右到左";(反之亦然(;后向S"-图案bin 0中的第一个元素,bin 1中的第二个元素,等等。然后在到达最后一个bin时倒退:bin 2中的第四个元素,bin1中的五个元素等等。请参阅下面如何按照括号中的组号将元素放入bin中。这些值是组大小。
Bins: | 0 | 1 | 2 |
| 359 (0)| 326 (1)| 264 (2)|
| 248 (5)| 249 (4)| 262 (3)|
| 245 (6)| 189 (7)| 187 (8)|
| | 45(10)| 153 (9)|
仓将具有大致相同数量的值,因此具有大致相同的计算"值";成本";。垃圾箱大小为:[852, 809, 866]
,供感兴趣的人使用。我试过一个真实世界的数据集,这些垃圾箱大小相似。不能保证所有数据集的存储箱大小相似。
代码可以变得更高效,但这足以让想法出来:
n = 3
size = 50
rng = np.random.default_rng(2021)
df = pd.DataFrame({
"one": np.linspace(0, 10, size, dtype=np.uint8),
"two": np.linspace(0, 5, size, dtype=np.uint8),
"data": rng.integers(0, 100, size)
})
groups = df.groupby(["one", "two"]).sum()
groups = groups.sort_values("data", ascending=False).reset_index(drop=True)
bins = [[] for i in range(n)]
backward = False
i = 0
for group in groups.iterrows():
bins[i].append(group)
i = i + 1 if not backward else i - 1
if i == n:
backward = True
i -= 1
if i == -1 and backward:
backward = False
i += 1
[sum([size[0] for (group, size) in bin]) for bin in bins]