当列值满足特定顺序时对Pandas DataFrame进行条件判断

2 投票
2 回答
47 浏览
提问于 2025-04-13 19:30

假设我有一个这样的数据表:

   Placement  Value  Order
0   high       10      1
1   med         5      2
2   high        9      3
3   low         3      4
4   med         7      5
5   low         2      6
6   med         6      7
7   high        9      8
8   med         4      9
9   low         2      10
10  high        8      11
11  med         6      12
12  high        8      13
13  med         5      14
14  low         1      15

当我遇到“Placement”序列,比如“高 -> 低”、“低 -> 高”、“高 -> 中 -> 低”或“低 -> 中 -> 高”时,我想计算这个序列中“高”和“低”之间的差值,并把这个差值放到一个新列“Diff”的最后一行里。同时,我还想要另一个列“Measured From”,这个列的值是序列第一行的“Order”值。最后,我会删除所有没有新列值的行,这样就能得到一个像这样的数据表:

   Placement  Value  Order  Diff  Measured From
3   low         3     4      -6      3
7   high        9     8      7       6
9   low         2     10     -7      8
10  high        8     11     6       10
14  low         1     15     -7      13

我想过一种方法,就是查看每一行之前的两个“Placement”值,但我听说在使用Pandas时应该避免使用循环。有没有更有效的方法来找到这些模式并进行计算呢?

2 个回答

2

一种可能的解决办法是,创建三个布尔掩码(也就是用来过滤数据表的工具),然后根据需要移动这些掩码。接着,把不同的数据表合并在一起:

def get_frame(m, nshift):
    x = df.loc[m.shift(nshift, fill_value=False), ["Placement", "Value", "Order"]]
    x["Diff"] = x["Value"] - df.loc[m, "Value"].values
    x["Measured From"] = df.loc[m, "Order"].values
    return x


l, m, h = (
    df["Placement"].eq("low"),
    df["Placement"].eq("med"),
    df["Placement"].eq("high"),
)

m1 = l & h.shift(-1)
m2 = h & l.shift(-1)
m3 = l & m.shift(-1) & h.shift(-2)
m4 = h & m.shift(-1) & l.shift(-2)

out = pd.concat(
    [get_frame(m1, 1), get_frame(m2, 1), get_frame(m3, 2), get_frame(m4, 2)]
).sort_index()

print(out)

输出结果:

   Placement  Value  Order  Diff  Measured From
3        low      3      4    -6              3
7       high      9      8     7              6
9        low      2     10    -7              8
10      high      8     11     6             10
14       low      1     15    -7             13
2

代码

out = (df[df['Placement'].ne('med')]
       .assign(Diff=lambda x: x['Value'].diff(), 
               Measured_From=lambda x: x['Order'].shift()
              )[lambda x: x['Placement'].ne(x['Placement'].shift())]
       .dropna(subset='Measured_From'))

输出

   Placement  Value  Order  Diff  Measured_From
3        low      3      4  -6.0              3
7       high      9      8   7.0              6
9        low      2     10  -7.0              8
10      high      8     11   6.0             10
14       low      1     15  -7.0             13

撰写回答