你可以做你想做的事,但你可以做某事并不意味着这是一个好主意。任何需要的解决方案eval()
都可能比它需要的更复杂,并且如果您无法完全控制输入的数据,则会带来巨大的风险。
话虽如此,此脚本显示了一种天真的方法,没有表格中的花哨表达式,以及您建议的方法 - 我强烈建议您不要使用它并找出更好的方法来实现您的需求:
from io import StringIO
import re
import datatable as dt
csv1 = """A,B
1,2
3,4
5,6"""
csv2 = """NAME,EXPR
A_GREATER_THAN_B, A>B
A_GREATER_THAN_10, A>10
B_GREATER_THAN_5, B>5"""
def naive():
# naive approach
d = dt.fread(StringIO(csv1))
d['A_GREATER_THAN_B'] = d[:, dt.f.A > dt.f.B]
d['A_GREATER_THAN_10'] = d[:, dt.f.A > 10]
d['B_GREATER_THAN_5'] = d[:, dt.f.B > 5]
print(d)
def update_with_expressions(d, expressions):
for n in range(expressions.nrows):
col = expressions[n, :][0, 'NAME']
expr = re.sub('([A-Za-z]+)', r'dt.f.\1', expressions[n, :][0, 'EXPR'])
# here's hoping that expression is trustworthy...
d[col] = d[:, eval(expr)]
def fancy():
# fancy, risky approach
d = dt.fread(StringIO(csv1))
update_with_expressions(d, dt.fread(StringIO(csv2)))
print(d)
if __name__ == '__main__':
naive()
fancy()
结果(表明您从任何一种方法都得到相同的结果):
| A B A_GREATER_THAN_B A_GREATER_THAN_10 B_GREATER_THAN_5
| int32 int32 bool8 bool8 bool8
-- + ----- ----- ---------------- ----------------- ----------------
0 | 1 2 0 0 0
1 | 3 4 0 0 0
2 | 5 6 0 0 1
[3 rows x 5 columns]
| A B A_GREATER_THAN_B A_GREATER_THAN_10 B_GREATER_THAN_5
| int32 int32 bool8 bool8 bool8
-- + ----- ----- ---------------- ----------------- ----------------
0 | 1 2 0 0 0
1 | 3 4 0 0 0
2 | 5 6 0 0 1
[3 rows x 5 columns]
注意:如果有人知道迭代 a 中行的更好方法datatable.Frame
,请发表评论,因为我不喜欢这部分:
for n in range(expressions.nrows):
col = expressions[n, :][0, 'NAME']
请注意,StringIO
仅导入以在代码中包含 .csv 文件,您不需要它们。