【问题标题】:Pandas Groupby: get value from previous element of a group based on value of another columnPandas Groupby:根据另一列的值从组的前一个元素中获取值
【发布时间】:2022-01-15 16:12:20
【问题描述】:

我有一个包含 4 列的数据框。我事先按“组”和“时间戳”对这个数据框进行了排序。

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'),从组中的 PREVIOUS '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

【问题讨论】:

    标签: python python-3.x pandas pandas-groupby


    【解决方案1】:

    我们可以 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
    

    【讨论】:

    • 我使用了相同的方法;)但是您需要确保在 type3 之前永远不会有 type0 ,否则您会得到错误的ffill
    • @mozway 啊更新了~,谢谢
    • 感谢 Beny 和 @mozway 的帮助。您的两种解决方案都非常有效。我只是将第一个掩码更改为 s = df.price.where(df.type.isin(['type1','type2'])) 因为我的数据中可能还有其他类型。
    【解决方案2】:

    您可以使用一系列掩码来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
    

    【讨论】:

    • 非常感谢,mozway。这运作良好。您的 cmets 也确实有帮助!
    猜你喜欢
    • 2019-04-04
    • 1970-01-01
    • 2016-03-12
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 2020-06-08
    相关资源
    最近更新 更多