我有一个这样的数据框:
Df = pd。 dataFrame ({'key': list ('aaaabbcccc'),'value': [1 、 5 、 6 、 8 、 2 、 4 、 7 、 5]})
键值
0 一 1
1 个 5
2 a 6
3 a 8
B 2
5 b 4
6 b 7
7 b 7
8 c 1
9 c 1
10 c 1
11 c 1
12 c 5
此外,我有一个变量max_sum = 10
。
我想根据中的值为每一行 (I) 分配一个组keys
and (ii) the max_sum
每个组不应该超过它。
我的预期结果是这样的:
键值组
0 一 1
1 个 5 个 1
2 个 6 个 2
3 个 8 个 3
4 b 2 4
B 4 4
6 b 7 5
7 b 7 6
8 c 1 7
9 c 1 7
10 c 1 7
11 c 1 7
12 c 5 7
因此,前两个值a
group (1
and 5
) sum up to 6
which is less than 10
, so they are in the same group. If we now added also 6
, max_sum
would be exceeded and therefore this value goes into group 2
. We cannot add 8
to this group as then again max_sum
would be exceeded, therefore we define a group 3
. Same then for the values b
and c
。
可以做的
Df ['cumsum'] = df.group by ('key') ['value'].cumsum ()
键值累计
0 一 1
1 个 5 个 6
2 a 6 12
3 个 8 个 20
B 2 2
5 b 4 6
6 b 7 13
7 b 7 20
8 c 1 1
9 c 1 2
10 c 1 3
11 c 1 4
12 c 5 9
但是我不知道如何从这里获取组信息。
我们可以创建两个掩码,并在此基础上创建一个True
/ False
数组。
max_sum
mark as True
else False
keys
与当前行不同。与np.where
在伪代码中,我们基本上有以下内容:
当 m1或者M2 是真的,返回 True,否则返回 False
现在我们可以翻译了True
and False
因为它们是布尔值,所以是 1/0:
真实真实
2
这就是我们要找的cumsum
在最后一行
代码:
Max_sum = 10
M1 = df.group by (“键”) [“值”].cumsum ().gt (max _ sum) # 大于 max _ sum 的所有值
M2 = df ['key'].ne (df ['key').shift () # 键改变的所有行
Df ['group'] = np.where (m1 | m2,真,假).cumsum ()
键值组
0 一 1
1 个 5 个 1
2 个 6 个 2
3 个 8 个 3
4 b 2 4
B 4 4
6 b 7 5
7 b 7 6
8 c 1 7
9 c 1 7
10 c 1 7
11 c 1 7
12 c 5 7
我们希望根据行的累积和对行进行分区,所以我们使用cumsum
, take the modulus with respect to max_sum
, then find the difference to find points where the difference is negative (to mark the next group). We also need to do this per key, so the entire operation described above is done inside a GroupBy.apply
打电话。
(Df.group by ('key') ['value']
。应用 (lambda x: x.cumsum ().mod (max _ sum).diff ())
.Fillna (-1)
.Lt (0)
。())
0 1
1 1
2 2
3 3
4 4
5 4
6 5
7 6
8 7
9 7
10 7
11 7
12 7
名称: 值,dtype: int64
在下面的评论中,我写道:
@ Cleb 我这边的回答好像是错的 4 、 9 、 2 的输出 应该是 1 、 2 、 3,但是我的代码会分配 1 、 2,因为 cumsum 折扣的价值。
所以,这是我解决这个角落案件的方法。定义分配组的函数:
至少比 “全局” 更好的 grp = {'gr': 0} #
Def func (V):
累计 = 0
【】】 = 1
Grps = []
对于 v.tolist () 中的 V:
累计 = v
如果 cumsum> max_sum:
累计 = v
【】】 = 1
Grps.append (【】】)
返回 pd 系列 (grps)
现在,打电话apply
:
Df.group by (“键”) [“值”。应用 (func)。值
# 数组 (【 1 、 2 、 3 、 4 、 5 、 6 、 7 】)
我的逻辑,先把cumsum
within each group , then we need get the pervious group's max last group number cumsum
分配到下一个组
S = (df.group by ('key') ['value'].cumsum ()/10 1)
S.group by (df ['key').last ().shift ().fillna (0).cumsum ()
出【 24 】:
0 1.0
1.0
2 2.0
3 3.0
4 4.0
5 4.0
6 5.0
7 6.0
8 7.0
9 7.0
10 7.0
11 7.0
7.0
名称: 值,dtype: float64
另一种方式
Pd.因子化 (列表 (zip (df ['key') 、 df.group by ('key') ['value'].cumsum ()//10)
Out [51]: 数组 ([1 、 2 、 3 、 4 、 5 、 6 、 7],dtype = int64)
方法 3 来自 Pir 的数据
S = df.group by ('key') ['value'].rolling (2,min _ periods = 1).sum ().gt (10)
S.loc [s.group by (级别 = 0).head (1).index [1:] = True
美国 cumsum () 1
出【 79 】:
钥匙
0 1
1 1
2 2
3 3
B 4 4
5 4
6 5
7 6
C 8 7
9 7
10 7
11 7
12 7
D 13 8
14 8
15 9
16 10
名称: 值,dtype: int
据我所知,至少没有
考虑扩展的例子
数据框 ({)
“关键”: [* “aaaabbcccddddd”,
“值”: [* map (int,'1568247711151544922252')]
})
Def gen_groups (tups,max _ sum = 10):
标签 = 0
金额 = {}
对于 key,val in tups:
如果关键不在金额中:
标签 = 1
【 Key 】 = 0 的和
和 [键] = val
如果和 [键]> max_sum:
# 这将重置求和
# 超过最大值的第一件事
和 [键] = val
标签 = 1
产量标签
Df.assign (group = [* gen_groups (zip (df ['key'),df ['value')
输出
键值组
0 一 1
1 个 5 个 1
2 个 6 个 2
3 个 8 个 3
4 b 2 4
B 4 4
6 b 7 5
7 b 7 6
8 c 1 7
9 c 1 7
10 c 1 7
11 c 1 7
12 c 5 7
“Key = = d” 的 13 d 4 8 # 第一组
因为 '4 4 <= 10',14 d 4 8 # 仍然是同一个组
因为 '4 4 9> 10',所以 15 d 9 9 # 新组
因为 '9 2> 10',所以 16 d 2 10 # 新组
因为 '2 2 <= 10',所以 17 d 2 10 # 同组
因为 '2 <= 10',所以 18 d 2 10 # 同组
因为 '2 5> 10',19 d 5 11 # 新组
因为 '5 2 <= 10',所以 20 d 2 11 # 同组
我创造每 groupIDcumsum
and use it to group again together with keys
to derive the ngroup
per keys-cumsum
Max_sum = 10
S = df.group by ('key').值.cumsum ().gt (max _ sum).cumsum ()
[Df ['key'],s].ngroup () 1
出【 461 】:
0 1
1 1
2 2
3 3
4 4
5 4
6 5
7 6
8 7
9 7
10 7
11 7
12 7
Dtype: int64