对列进行分组,使其在每个组中的总和大致相等

时间:2017-01-13 17:02:40

标签: python pandas

将均匀分布的值排序到预定义数量的组中的最简单方法是什么?

data = {'impact':[10,30,20,10,90,60,50,40]}
df = pd.DataFrame(data,index=['a','b','c','d','e','f','g','h'])

print df

   impact
a      10
b      30
c      20
d      10
e      90
f      60
g      50
h      40

numgroups = 4

group_targetsum = round(df.impact.sum() / numgroups, -1)

print group_targetsum

80.0

在上面的例子中,我想从df创建4个组。唯一的排序标准是每组中的影响总和应大约等于group_targetsum。影响总和可以在合理范围内高于或低于group_targetsum。

最终,我想将这些群体分成他们自己的数据帧,保留索引。导致这样的事情:

print df_a

   impact
e      90

print df_b

   impact
c      20
f      60

print df_c

   impact

a      10
d      10
g      50

print df_d

   impact

b      30
h      40

结果数据框不需要完全相同,只要它们尽可能接近group_targetsum即可。

2 个答案:

答案 0 :(得分:2)

假设系列中的值非常相似,这是使用searchsorted -

的方法
In [150]: df
Out[150]: 
   impact
a      10
b      30
c      20
d      10
e      90
f      60
g      50
h      40

In [151]: a = df.values.ravel()

In [152]: shift_num = group_targetsum*np.arange(1,numgroups)

In [153]: idx = np.searchsorted(a.cumsum(), shift_num,'right')

In [154]: np.split(a, idx)
Out[154]: [array([10, 30, 20, 10]), array([90]), array([60]), array([50, 40])]

答案 1 :(得分:1)

从概念上讲,我们只想使用qcut的加权版本,但目前在熊猫中并不存在。然而,我们可以通过组合cumsumcut来完成同样的事情。 cumsum基本上为我们提供了加权,然后我们用cut对其进行切片。

(关于'csum_midpoint'的注意事项:如果没有中点调整,我们最终会根据它的开始位置(累积意义上)将事物分组,因此最终会偏向更高组中的分组。中点调整不能使事情变得完美,但它有所帮助。我相信这个答案在数学上与@Divakar相同,除了我在这里使用中点和使用'正确'。)

df['csum'] = df['impact'].cumsum()
df['csum_midpoint'] = (df.csum + df.csum.shift().fillna(0)) / 2.

df['grp'] = pd.cut( df.csum_midpoint, np.linspace(0,df['impact'].sum(),numgroups+1 ))
df.groupby( df.grp )['impact'].sum()

grp
(0, 77.5]       70
(77.5, 155]     90
(155, 232.5]    60
(232.5, 310]    90
Name: impact, dtype: int64

df

   impact  csum  csum_midpoint           grp
a      10    10            5.0     (0, 77.5]
b      30    40           25.0     (0, 77.5]
c      20    60           50.0     (0, 77.5]
d      10    70           65.0     (0, 77.5]
e      90   160          115.0   (77.5, 155]
f      60   220          190.0  (155, 232.5]
g      50   270          245.0  (232.5, 310]
h      40   310          290.0  (232.5, 310]