Pandas Groupby:根据另一列的值从组的前一个元素中获取值

Pandas Groupby: get value from previous element of a group based on value of another column

我有一个包含 4 列的数据框。我事先按 'group' 和 'timestamp' 对这个数据框进行了排序。

df = pd.DataFrame(
{
    "type": ['type0', 'type1', 'type2', 'type3', 'type1', 'type3', 'type0', 'type1', 'type3', 'type3'],
    "group": [1, 1, 1, 1, 1, 1, 2, 2, 2, 2],
    "timestamp": ["20220105 07:52:46", "20220105 07:53:11", "20220105 07:53:55", "20220105 07:59:12", "20220105 08:24:13", "20220105 08:48:19", "20220105 11:01:30", "20220105 11:15:16", "20220105 12:13:36", "20220105 12:19:44"],
    "price": [0, 1.5, 2.5, 3, 3.2, 3.1, 0.5, 3, 3.25, pd.NA]
})

>> df
    type  group          timestamp price
0  type0      1  20220105 07:52:46     0
1  type1      1  20220105 07:53:11   1.5
2  type2      1  20220105 07:53:55   2.5
3  type3      1  20220105 07:59:12     3
4  type1      1  20220105 08:24:13   3.2
5  type3      1  20220105 08:48:19   3.1
6  type0      2  20220105 11:01:30   0.5
7  type1      2  20220105 11:15:16     3
8  type3      2  20220105 12:13:36  3.25
9  type3      2  20220105 12:19:44  <NA>

按列 'group' 分组后,我想按照以下逻辑创建一个 'new_price' 列:
对于组中的每个 'type3' 行(即 df['type'] = 'type3'),从组中的前一个 'type1' 或 'type2' 行获取价格团体。 对于 type0/type1/type2 行,保持与输入数据框中相同的价格。

我的解决方案:

当我们没有 2 个连续的 'type3' 行时,我的下面的解决方案有效。 但是当有 2 个连续的 'type3' 行时,我得到的第二行 'type3' 的价格是错误的。 我想要前一个 'type1' 的价格或组中的 'type2' 行,但我使用我的解决方案从第一个 'type3' 行获得价格。

df = df.sort_values(by=["group", "timestamp"])
required_types_mask = df['type'].isin(['type1', 'type2', 'type3'])
temp_series = df.loc[:, 'price'].where(required_types_mask).groupby(df['group']).shift(1)
type_3_mask = df['type'].eq('type3')
df.loc[:, 'new_price'] = df.loc[:, 'price'].mask(type_3_mask, temp_series)

我的结果:

    type  group          timestamp price new_price
0  type0      1  20220105 07:52:46     0         0
1  type1      1  20220105 07:53:11   1.5       1.5
2  type2      1  20220105 07:53:55   2.5       2.5
3  type3      1  20220105 07:59:12     3       2.5
4  type1      1  20220105 08:24:13   3.2       3.2
5  type3      1  20220105 08:48:19   3.1       3.2
6  type0      2  20220105 11:01:30   0.5       0.5
7  type1      2  20220105 11:15:16     3         3
8  type3      2  20220105 12:13:36  3.25         3
9  type3      2  20220105 12:19:44  <NA>       3.25 <- Incorrect price

预期结果:

    type  group          timestamp price new_price
0  type0      1  20220105 07:52:46     0         0
1  type1      1  20220105 07:53:11   1.5       1.5
2  type2      1  20220105 07:53:55   2.5       2.5
3  type3      1  20220105 07:59:12     3       2.5
4  type1      1  20220105 08:24:13   3.2       3.2
5  type3      1  20220105 08:48:19   3.1       3.2
6  type0      2  20220105 11:01:30   0.5       0.5
7  type1      2  20220105 11:15:16     3         3
8  type3      2  20220105 12:13:36  3.25         3
9  type3      2  20220105 12:19:44  <NA>         3 <- Correct price

我们可以 mask type3 的价格然后 ffill

s = df.price.mask(df.type.isin(['type0','type3']))
df['new'] = np.where(df.type.eq('type3'),s.groupby(df['group']).ffill(),df['price'])
df
    type  group          timestamp price  new
0  type0      1  20220105 07:52:46     0    0
1  type1      1  20220105 07:53:11   1.5  1.5
2  type2      1  20220105 07:53:55   2.5  2.5
3  type3      1  20220105 07:59:12     3  2.5
4  type1      1  20220105 08:24:13   3.2  3.2
5  type3      1  20220105 08:48:19   3.1  3.2
6  type0      2  20220105 11:01:30   0.5  0.5
7  type1      2  20220105 11:15:16     3    3
8  type3      2  20220105 12:13:36  3.25    3
9  type3      2  20220105 12:19:44  <NA>    3

您可以使用一系列掩码来ffill

首先掩码 'type3' 和 'type0'(后者避免将其用作 ffill 的来源)。然后恢复'type0'.

的值

每个组都完成。

df['new_price'] = (
 df.groupby('group')
   .apply(lambda d: d['price']
            .mask(d['type'].isin(['type3', 'type0'])) # type0/3 to NaN
            .ffill()                                  # fill with previous type1/2
            .mask(d['type'].eq('type0'), d['price'])  # restore type0
         )
   .values
 )

输出:

    type  group          timestamp price new_price
0  type0      1  20220105 07:52:46     0         0
1  type1      1  20220105 07:53:11   1.5       1.5
2  type2      1  20220105 07:53:55   2.5       2.5
3  type3      1  20220105 07:59:12     3       2.5
4  type1      1  20220105 08:24:13   3.2       3.2
5  type3      1  20220105 08:48:19   3.1       3.2
6  type0      2  20220105 11:01:30   0.5       0.5
7  type1      2  20220105 11:15:16     3       3.0
8  type3      2  20220105 12:13:36  3.25       3.0
9  type3      2  20220105 12:19:44  <NA>       3.0