如何在 Pandas 中执行行级逻辑
How to do line level logic in Pandas
我有一个 table,它有一堆列,我需要根据行类型创建一个新列,但每种类型的行的逻辑都不同。
我的数据是这样的:
type
field1
field2
field3
field4
1
a
b
c
17
2
e
f
g
20
3
i
j
k
100
类型 1 的行的逻辑是连接字段 1、字段 2、字段 3
类型 2 的行的逻辑是连接字段 2、字段 3、字段 4
类型 3 的行的逻辑是平方字段 4
超级重要的部分
我想避免手动编码每种类型,因为有数百种不同的类型,每种类型都有自己独特的逻辑,这些逻辑会不断变化。我们执行严格的 SDLC,因此部署更新将是一场噩梦。理想情况下,我会将此逻辑放入 SQL table 某处,然后以某种方式在我的 pandas 逻辑中使用数据,但我不知道该怎么做。
示例:
data = pd.read_sql(query) #above data
rules = pd.read_sql(query)
rules.head()
Type
Rule
1
field1+field2+field3
2
field2+field3+field4
3
field4**2
for i in rules:
data['output'] = data[filtered to i.type].apply(i.typeLogic)
data.head()
output
abc
fg20
10000
如果 df
是你的 pandas 数据框,我会定义一个函数:
def rowwise(x):
if x['type '] == 1:
return x['field1 '] + x['field2 '] + x['field3 ']
if x['type '] == 2:
return x['field2 '] + x['field3 '] + str(x['field4'])
if x['type '] == 3:
return str(float(x['field4'])**2)
然后使用选项 axis=1
应用它
df.apply(rowwise, axis=1)
有几个陷阱是串联仅适用于字符串,并且生成的列应该具有一致的数据类型。这就是函数中有这么多类型转换的原因。
您可以尝试使用:
cond1 = df['type'] == 1
cond2 = df['type'] == 2
cond3 = df['type'] == 3
result1 = df[['field1', 'field2', 'field2']].sum(1)
result2 = df[['field2', 'field3', 'field4']].astype('str').sum(1)
result3 = df['field4'] ** 2
df['result'] = np.select([cond1, cond2, cond3], [result1, result2, result3])
输出:
type field1 field2 field3 field4 result
0 1 a b c 17 abb
1 2 e f g 20 fg20
2 3 i j k 100 10000
将规则合并到数据中,使用eval
方法根据类型评估规则
# data
df = pd.DataFrame({'type': [1, 2, 3],
'field1': ['a', 'e', 'i'],
'field2': ['b', 'f', 'j'],
'field3': ['c', 'g', 'k'],
'field4': [17, 20, 100]})
# rules df
rules = pd.DataFrame({'type': [1, 2, 3],
'rule': ['field1+field2+field3', 'field2+field3+field4', 'field4**2']})
# merge the dfs to be able to do a rules lookup later
df = df.merge(rules, on='type')
# create a list in a loop
lst = []
for _, d in df.groupby("type"):
# get the field columns
f_cols = [c for c in d.columns if 'field' in c]
# get the rule
r = d.rule.iat[0]
# rules with + concatenates strings and ints, so convert such rows to string dtype
if '+' in r:
d[f_cols] = d[f_cols].astype(str)
# evaluate the rule
d['new'] = d[f_cols].eval(f"{r}", engine='python')
# append to lst
lst.append(d)
# concatenate all dfs in lst into a single df
res = pd.concat(lst)
res
如果您有任何问题,请告诉我。
我有一个 table,它有一堆列,我需要根据行类型创建一个新列,但每种类型的行的逻辑都不同。
我的数据是这样的:
type | field1 | field2 | field3 | field4 |
---|---|---|---|---|
1 | a | b | c | 17 |
2 | e | f | g | 20 |
3 | i | j | k | 100 |
类型 1 的行的逻辑是连接字段 1、字段 2、字段 3
类型 2 的行的逻辑是连接字段 2、字段 3、字段 4
类型 3 的行的逻辑是平方字段 4
超级重要的部分 我想避免手动编码每种类型,因为有数百种不同的类型,每种类型都有自己独特的逻辑,这些逻辑会不断变化。我们执行严格的 SDLC,因此部署更新将是一场噩梦。理想情况下,我会将此逻辑放入 SQL table 某处,然后以某种方式在我的 pandas 逻辑中使用数据,但我不知道该怎么做。
示例:
data = pd.read_sql(query) #above data
rules = pd.read_sql(query)
rules.head()
Type | Rule |
---|---|
1 | field1+field2+field3 |
2 | field2+field3+field4 |
3 | field4**2 |
for i in rules:
data['output'] = data[filtered to i.type].apply(i.typeLogic)
data.head()
output |
---|
abc |
fg20 |
10000 |
如果 df
是你的 pandas 数据框,我会定义一个函数:
def rowwise(x):
if x['type '] == 1:
return x['field1 '] + x['field2 '] + x['field3 ']
if x['type '] == 2:
return x['field2 '] + x['field3 '] + str(x['field4'])
if x['type '] == 3:
return str(float(x['field4'])**2)
然后使用选项 axis=1
df.apply(rowwise, axis=1)
有几个陷阱是串联仅适用于字符串,并且生成的列应该具有一致的数据类型。这就是函数中有这么多类型转换的原因。
您可以尝试使用:
cond1 = df['type'] == 1
cond2 = df['type'] == 2
cond3 = df['type'] == 3
result1 = df[['field1', 'field2', 'field2']].sum(1)
result2 = df[['field2', 'field3', 'field4']].astype('str').sum(1)
result3 = df['field4'] ** 2
df['result'] = np.select([cond1, cond2, cond3], [result1, result2, result3])
输出:
type field1 field2 field3 field4 result
0 1 a b c 17 abb
1 2 e f g 20 fg20
2 3 i j k 100 10000
将规则合并到数据中,使用eval
方法根据类型评估规则
# data
df = pd.DataFrame({'type': [1, 2, 3],
'field1': ['a', 'e', 'i'],
'field2': ['b', 'f', 'j'],
'field3': ['c', 'g', 'k'],
'field4': [17, 20, 100]})
# rules df
rules = pd.DataFrame({'type': [1, 2, 3],
'rule': ['field1+field2+field3', 'field2+field3+field4', 'field4**2']})
# merge the dfs to be able to do a rules lookup later
df = df.merge(rules, on='type')
# create a list in a loop
lst = []
for _, d in df.groupby("type"):
# get the field columns
f_cols = [c for c in d.columns if 'field' in c]
# get the rule
r = d.rule.iat[0]
# rules with + concatenates strings and ints, so convert such rows to string dtype
if '+' in r:
d[f_cols] = d[f_cols].astype(str)
# evaluate the rule
d['new'] = d[f_cols].eval(f"{r}", engine='python')
# append to lst
lst.append(d)
# concatenate all dfs in lst into a single df
res = pd.concat(lst)
res
如果您有任何问题,请告诉我。