Cle*_*leb 5 python dataframe pandas
我有一个这样的数据框:
df = pd.DataFrame({'keys': list('aaaabbbbccccc'), 'values': [1, 5, 6, 8, 2, 4, 7, 7, 1, 1, 1, 1, 5]})
keys values
0 a 1
1 a 5
2 a 6
3 a 8
4 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
Run Code Online (Sandbox Code Playgroud)
此外,我有一个变量max_sum = 10。
我想根据keys(ii)中的值为每行分配一个组(ii)max_sum每组不应该超过该值。
我的预期结果如下所示:
keys values group
0 a 1 1
1 a 5 1
2 a 6 2
3 a 8 3
4 b 2 4
5 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
Run Code Online (Sandbox Code Playgroud)
因此,a组(1和5)中的前两个值的总和6小于10,因此它们在同一组中。如果现在也添加6,max_sum将被超出,因此该值将归入组2。我们不能添加8到该组,否则max_sum将再次超出该组,因此我们定义了一个组3。值b和相同c。
一个可以做
df['cumsum'] = df.groupby('keys')['values'].cumsum()
keys values cumsum
0 a 1 1
1 a 5 6
2 a 6 12
3 a 8 20
4 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
Run Code Online (Sandbox Code Playgroud)
但我不知道如何从中获取组信息。
我们要基于行的累加总和对行进行分区,因此我们使用cumsum,相对于取模数max_sum,然后找到差异以找到差异为负的点(以标记下一组)。我们还需要针对每个键执行此操作,因此上述整个操作都在GroupBy.apply调用内完成。
(df.groupby('keys')['values']
.apply(lambda x: x.cumsum().mod(max_sum).diff())
.fillna(-1)
.lt(0)
.cumsum())
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
Name: values, dtype: int64
Run Code Online (Sandbox Code Playgroud)
在下面的评论中,我写道:
@Cleb似乎我的回答是错误的。对于4、4、9、2,输出应为1、1、2、3,但我的代码将分配1、1、2、2,因为cumsum会折减值。
因此,这是我解决这个极端情况的解决方案。定义一个分配组的函数:
grp = {'grp': 0} # better than `global`, at least
def func(V):
cumsum = 0
grp['grp'] += 1
grps = []
for v in V.tolist():
cumsum += v
if cumsum > max_sum:
cumsum = v
grp['grp'] += 1
grps.append(grp['grp'])
return pd.Series(grps)
Run Code Online (Sandbox Code Playgroud)
现在,致电apply:
df.groupby('keys')['values'].apply(func).values
# array([1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 7, 7, 7])
Run Code Online (Sandbox Code Playgroud)
我们可以创建两个掩码,并基于它创建一个True/False数组。
max_sum标记为TrueelseFalsekeys与当前行不同的行。我们np.where基本上有以下伪代码:
当 m1或m2 为 True 时,返回 True,否则返回 False
现在我们可以将Trueand转换False为 1 / 0,因为它们是布尔值:
True + True
2
Run Code Online (Sandbox Code Playgroud)
cumsum这就是最后一行的原因。
代码:
max_sum = 10
m1 = df.groupby('keys')['values'].cumsum().gt(max_sum) # all values which are greater than max_sum
m2 = df['keys'].ne(df['keys'].shift()) # all rows where keys change
df['group'] = np.where(m1 | m2, True, False).cumsum()
keys values group
0 a 1 1
1 a 5 1
2 a 6 2
3 a 8 3
4 b 2 4
5 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |