首页 > 解决方案 > 在复杂的 if 条件下比较大型 Pandas DataFrame 中不同的前一行值

问题描述

我有一个超过 100 万行的数据框,我想比较大型 Pandas DataFrame 中不同的先前行值以了解复杂的 if 条件。

例如,我有以下数据框:

import pandas as pd
import numpy as np
df = pd.DataFrame([[3, 2, 3], [2, 2, 3], [2, 1, 3], [4, 3, 5]], columns=['A', 'B', 'C'])
print(df)

    A   B   C
0   3   2   3
1   2   2   3
2   2   1   3
3   4   3   5

现在,我需要添加一个新列,并根据以下条件为其分配 1 或 -1 的值:

  1. 如果A=B那么D=-1
  2. 如果A=C那么D=+1
  3. ifA不等于Bor C, thenA应该与之前不同的值进行比较, ifA大于其不同的之前的值 then D=+1, ifA小于其不同的之前的值 thenD=-1

结果应如下所示:

    A   B   C   D
0   3   2   3   1
1   2   2   3  -1
2   2   1   3  -1
3   4   3   5   1

这是我尝试过的:

  1. 使用for-loop(它可以工作,但需要很长时间才能完成超过 100 万行的数据帧的任务):
def my_func(df):
    for i in range(0, len(df)):
        n = 1
        if (df.loc[i, 'A'] == df.loc[i, 'C']):
            df.loc[i, 'D'] = 1
        elif (df.loc[i, 'A'] == df.loc[i, 'B']):
            df.loc[i, 'D'] = -1
        elif ((df.loc[i, 'A'] != df.loc[i, 'C']) & 
                (df.loc[i, 'A'] != df.loc[i, 'B'])):
            if (df.loc[i, 'A'] > df.loc[i-n, 'A']):
                df.loc[i, 'D'] = 1
            elif (df.loc[i, 'A'] < df.loc[i-n, 'A']):
                df.loc[i, 'D'] = -1
            else:
                while (df.loc[i, 'A'] == df.loc[i-n, 'A']):
                    n += 1
                    if (df.loc[i, 'A'] == df.loc[i-n, 'A']):
                        continue
                    elif (df.loc[i, 'A'] > df.loc[i-n, 'A']):
                        df.loc[i, 'D'] = 1
                        break
                    elif (df.loc[i, 'A'] < df.loc[i-n, 'A']):
                        df.loc[i, 'D'] = -1
                        break
my_func(df)
print(df)

    A   B   C   D
0   3   2   3   1
1   2   2   3  -1
2   2   1   3  -1
3   4   3   5   1
  1. 使用np.select(结果不是我想要的):
conditions = [
    (df.A == df.B),
    (df.A == df.C),
    ((df.A != df.B) | (df.A != df.C)) & (df.A > df.A.shift()),
    ((df.A != df.B) | (df.A != df.C)) & (df.A < df.A.shift())
]
choices = [-1, 1, 1, -1]
df['D'] = np.select(conditions, choices, default=np.nan)
print(df)

    A   B   C   D
0   3   2   3   1
1   2   2   3  -1
2   2   1   3  NaN
3   4   3   5   1

标签: pythonpandasnumpy

解决方案


我找到了使用两次行迭代的解决方案,第一个在 A != B 和 A != C 的情况下创建辅助列,第二个用于使用条件计算 D。

import pandas as pd
import numpy as np
df = pd.DataFrame([[3, 2, 3], [2, 2, 3], [2, 1, 3], [4, 3, 5]], columns=['A', 'B', 'C'])

def get_last_different(s):
    current = s.iloc[-1]
    filtered = s.loc[s != current]
    if filtered.empty:
        return np.nan
    else:
        return filtered.iloc[-1]
    return last

def compute_D(row):
    d = 0
    if row["A"] == row["B"]:
        d -= 1
    if row["A"] == row["C"]:
        d += 1
    if (row["A"] != row["B"]) and (row["A"] != row["C"]):
        if row["A"] > row["aux"]:
            d += 1
        if row["A"] < row["aux"]:
            d -= 1
    return d

df["aux"] = df.expanding(min_periods=1)["A"].apply(get_last_different)
df["D"] = df.apply(foo, axis=1)

至少我得到了你预期的结果。让我知道这种方法是否有效。


推荐阅读