python - 在复杂的 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 的值:
- 如果
A=B
那么D=-1
- 如果
A=C
那么D=+1
- if
A
不等于B
orC
, thenA
应该与之前不同的值进行比较, ifA
大于其不同的之前的值 thenD=+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
这是我尝试过的:
- 使用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
- 使用
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
解决方案
我找到了使用两次行迭代的解决方案,第一个在 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)
至少我得到了你预期的结果。让我知道这种方法是否有效。
推荐阅读
- google-apps-script - 更快地将多个谷歌表格合并到一张表格中
- php - PHP内置webserver破坏外来字符
- c# - 为什么与 MiniProfiler 一起使用时,Dapper QueryAsync 会出现歧义?
- algorithm - 如何回答这个递归问题,它和循环之间有很大区别吗
- java - 如何使用 Bazel 在 Android 中实现 Fabric Crashlytics?
- amazon-web-services - 从服务器上的容器访问 AWS S3 存储桶
- javascript - Object.assign 的奇怪行为
- google-street-view - 如何在街景中创建路径?
- typescript - Vue中使用Typescript和类组件装饰器时如何将数组传递给props
- sql-server - 日志传送大型数据库