熊猫用groupby和mask减去列

时间:2019-12-23 11:08:27

标签: pandas group-by

对于一个“ SN”以下的组,我想为每个组减去三个绩效指标。一组边界是序列号SN和掩码中的顺序布尔True值。 (因此,一个SN下可以存在多个True序列)。

我想要的第一个指标是Csub,它在列“ C”中的每个组的第一个值和最后一个值之间减去。其次,Bmean是“ B”列中每个组的平均值。

例如:

In:

df = pd.DataFrame({"SN" : ["66", "66", "66", "77", "77", "77", "77", "77"], "B" : [-2, -1, -2, 3, 1, -1, 1, 1], "C" : [1, 2, 3, 15, 11, 2, 1, 2],
"mask" : [False, False, False, True, True, False, True, True] })

   SN  B   C  mask
0  66 -2   1  False
1  66 -1   2  False
2  66 -2   3  False
3  77  3  15  True
4  77  1  11  True
5  77 -1   2  False
6  77  1   1  True
7  77  1   2  True

Out:

   SN  B   C  mask     Csub Bmean CdivB
0  66 -2   1  False    Nan   Nan  Nan
1  66 -1   2  False    Nan   Nan  Nan
2  66 -2   3  False    Nan   Nan  Nan
3  77  3  15  True     -4    13  -0.3
4  77  1  11  True     -4    13  -0.3
5  77 -1   2  False    Nan   Nan  Nan
6  77  1   1  True     1     1    1 
7  77  1   2  True     1     1    1 

我煮出了类似的东西,但是它是根据遮罩的T / F值分组的。它应该按SN和顺序的True值而不是ALL True值分组。此外,我无法弄清楚如何对此进行减法运算。

# Extracting performance values
perf = (df.assign(
    Bmean = df['B'], CdivB = df['C']/df['B']
).groupby(['SN','mask'])
    .agg(dict(Bmean ='mean', CdivB = 'mean'))
    .reset_index(drop=False)
)

1 个答案:

答案 0 :(得分:0)

它不漂亮,但是您可以尝试以下方法。

首先,准备一个“ group_key”列,以便对“ mask”中的连续True值进行分组:

# Select the rows where 'mask' is True preceded by False.
first_true = df.loc[
    (df['mask'] == True)
    & (df['mask'].shift(fill_value=False) == False) 
]

# Add the column.
df['group_key'] = pd.Series()

# Each row in first_true gets assigned a different 'group_key' value.
df.loc[first_true.index, 'group_key'] = range(len(first_true))

# Forward fill 'group_key' on mask.
df.loc[df['mask'], 'group_key'] = df.loc[df['mask'], 'group_key'].ffill()

然后我们可以按'SN'和'group_key'进行分组,并计算和分配指标值。

# Group by 'SN' and 'group_key'.
gdf = df.groupby(by=['SN', 'group_key'], as_index=False)

# Compute indicator values
indicators = pd.DataFrame(gdf.nth(0)) # pd.DataFrame used here to avoid a SettingwithCopyWarning.
indicators['Csub'] = gdf.nth(0)['C'].array - gdf.nth(-1)['C'].array
indicators['Bmean'] = gdf.mean()['B'].array

# Write values to original dataframe
df = df.join(indicators.reindex(columns=['Csub', 'Bmean']))

# Forward fill the indicator values
df.loc[df['mask'], ['Csub', 'Bmean']] = df.loc[df['mask'], ['Csub', 'Bmean']].ffill()

# Drop 'group_key' column
df = df.drop(columns=['group_key'])

我排除了“ CdivB”,因为我不明白它的价值。