需要在行级别对 pandas 数据框进行评估
Need to do eval on pandas dataframe at row level
我有一个场景,我的 pandas 数据框有一个存储为字符串的条件,我需要执行它并将结果存储为不同的列。下面的示例将帮助您更好地理解;
现有数据框:
ID Val Cond
1 5 >10
1 15 >10
预期的数据帧:
ID Val Cond Result
1 5 >10 False
1 15 >10 True
如您所见,我需要连接 Val 和 Cond 并在行级别执行 eval。
如果您的条件是由基本操作(<、<=、==、!=、>、>=)构成的,那么我们可以使用 getattr
更有效地完成此操作。我们使用.str.extract
来解析条件,将比较和值分开。使用我们的字典,我们将比较映射到 Series 属性,然后我们可以在一个简单的 groupby 中分别调用每个唯一比较。
import pandas as pd
print(df)
ID Val Cond
0 1 5 >10
1 1 15 >10
2 1 20 ==20
3 1 25 <=25
4 1 26 <=25
# All operations we might have.
d = {'>': 'gt', '<': 'lt', '>=': 'ge', '<=': 'le', '==': 'eq', '!=': 'ne'}
# Create a DataFrame with the LHS value, comparator, RHS value
tmp = pd.concat([df['Val'],
df['Cond'].str.extract('(.*?)(\d+)').rename(columns={0: 'cond', 1: 'comp'})],
axis=1)
tmp[['Val', 'comp']] = tmp[['Val', 'comp']].apply(pd.to_numeric)
# Val cond comp
#0 5 > 10
#1 15 > 10
#2 20 == 20
#3 25 <= 25
#4 26 <= 25
#5 10 != 10
# Aligns on row Index
df['Result'] = pd.concat([getattr(gp['Val'], d[idx])(gp['comp'])
for idx, gp in tmp.groupby('cond')])
# ID Val Cond Result
#0 1 5 >10 False
#1 1 15 >10 True
#2 1 20 ==20 True
#3 1 25 <=25 True
#4 1 26 <=25 False
#5 1 10 !=10 False
简单但低效且危险的方法是在每一行上eval
,创建一个包含您的条件的字符串。 eval
很危险,因为它可以评估任何代码,所以只有在您真正信任并了解数据时才使用。
df['Result'] = df.apply(lambda x: eval(str(x.Val) + x.Cond), axis=1)
# ID Val Cond Result
#0 1 5 >10 False
#1 1 15 >10 True
#2 1 20 ==20 True
#3 1 25 <=25 True
#4 1 26 <=25 False
#5 1 10 !=10 False
您也可以这样做:
df["Result"] = [eval(x + y) for x, y in zip(df["Val"].astype(str), df["Cond"]]
通过连接字符串 df["Val"] 和 df["Cond"] 创建“Result”列,然后对其应用 eval。
我有一个场景,我的 pandas 数据框有一个存储为字符串的条件,我需要执行它并将结果存储为不同的列。下面的示例将帮助您更好地理解;
现有数据框:
ID Val Cond
1 5 >10
1 15 >10
预期的数据帧:
ID Val Cond Result
1 5 >10 False
1 15 >10 True
如您所见,我需要连接 Val 和 Cond 并在行级别执行 eval。
如果您的条件是由基本操作(<、<=、==、!=、>、>=)构成的,那么我们可以使用 getattr
更有效地完成此操作。我们使用.str.extract
来解析条件,将比较和值分开。使用我们的字典,我们将比较映射到 Series 属性,然后我们可以在一个简单的 groupby 中分别调用每个唯一比较。
import pandas as pd
print(df)
ID Val Cond
0 1 5 >10
1 1 15 >10
2 1 20 ==20
3 1 25 <=25
4 1 26 <=25
# All operations we might have.
d = {'>': 'gt', '<': 'lt', '>=': 'ge', '<=': 'le', '==': 'eq', '!=': 'ne'}
# Create a DataFrame with the LHS value, comparator, RHS value
tmp = pd.concat([df['Val'],
df['Cond'].str.extract('(.*?)(\d+)').rename(columns={0: 'cond', 1: 'comp'})],
axis=1)
tmp[['Val', 'comp']] = tmp[['Val', 'comp']].apply(pd.to_numeric)
# Val cond comp
#0 5 > 10
#1 15 > 10
#2 20 == 20
#3 25 <= 25
#4 26 <= 25
#5 10 != 10
# Aligns on row Index
df['Result'] = pd.concat([getattr(gp['Val'], d[idx])(gp['comp'])
for idx, gp in tmp.groupby('cond')])
# ID Val Cond Result
#0 1 5 >10 False
#1 1 15 >10 True
#2 1 20 ==20 True
#3 1 25 <=25 True
#4 1 26 <=25 False
#5 1 10 !=10 False
简单但低效且危险的方法是在每一行上eval
,创建一个包含您的条件的字符串。 eval
很危险,因为它可以评估任何代码,所以只有在您真正信任并了解数据时才使用。
df['Result'] = df.apply(lambda x: eval(str(x.Val) + x.Cond), axis=1)
# ID Val Cond Result
#0 1 5 >10 False
#1 1 15 >10 True
#2 1 20 ==20 True
#3 1 25 <=25 True
#4 1 26 <=25 False
#5 1 10 !=10 False
您也可以这样做:
df["Result"] = [eval(x + y) for x, y in zip(df["Val"].astype(str), df["Cond"]]
通过连接字符串 df["Val"] 和 df["Cond"] 创建“Result”列,然后对其应用 eval。