有条理地通过Pandas分组的值

jpp*_*jpp 7 python performance dataframe pandas pandas-groupby

我正在寻找一种更有效和可维护的方法来有条件地按组抵消价值.最容易展示一个例子.

值始终为非负值Offset == False且始终为负值Offset == True.我要做的是通过Label"折叠"正值(地板为0)和负值.

Note Label+ Offsetcombined总是唯一的.由于Offset是布尔值,因此每个Label最多只能有2行.

例1

df = pd.DataFrame({'Label': ['L1', 'L2', 'L3', 'L3'],
                   'Offset': [False, False, False, True],
                   'Value': [100, 100, 50, -100]})

# input
#   Label Offset  Value
# 0    L1  False    100
# 1    L2  False    100
# 2    L3  False     50
# 3    L3   True   -100
Run Code Online (Sandbox Code Playgroud)

期望的输出:

  Label Offset  Value
0    L1  False    100
1    L2  False    100
2    L3  False      0
3    L3   True    -50
Run Code Online (Sandbox Code Playgroud)

例2

df = pd.DataFrame({'Label': ['L1', 'L2', 'L3', 'L3'],
                   'Offset': [False, False, False, True],
                   'Value': [100, 100, 100, -50]})

# input
#   Label Offset  Value
# 0    L1  False    100
# 1    L2  False    100
# 2    L3  False    100
# 3    L3   True    -50
Run Code Online (Sandbox Code Playgroud)

期望的输出:

  Label Offset  Value
0    L1  False    100
1    L2  False    100
2    L3  False     50
3    L3   True      0
Run Code Online (Sandbox Code Playgroud)

当前效率低下的解决方

我目前的解决方案是手动循环,速度慢且难以维护:

for label in df['Label'].unique():
    mask = df['Label'] == label
    if len(df.loc[mask]) == 2:
        val_false = df.loc[~df['Offset'] & mask, 'Value'].iloc[0]
        val_true = df.loc[df['Offset'] & mask, 'Value'].iloc[0]
        if val_false > abs(val_true):
            df.loc[~df['Offset'] & mask, 'Value'] += val_true
            df.loc[df['Offset'] & mask, 'Value'] = 0
        else:
            df.loc[~df['Offset'] & mask, 'Value'] = 0
            df.loc[df['Offset'] & mask, 'Value'] += val_false
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个矢量化或至少部分矢量化的解决方案,以提高性能并摆脱这种混乱.

DSM*_*DSM 6

也许:

label_sums = df.Value.groupby(df.Label).transform(sum)
df["new_sum"] = label_sums.where(np.sign(label_sums) == np.sign(df.Value), 0)
Run Code Online (Sandbox Code Playgroud)

这给了我

In [42]: df
Out[42]: 
  Label  Offset  Value  new_sum
0    L1   False    100      100
1    L2   False    100      100
2    L3   False     50        0
3    L3    True   -100      -50
4    L4   False    100      100
5    L5   False    100      100
6    L6   False    100       50
7    L6    True    -50        0
Run Code Online (Sandbox Code Playgroud)