如何在 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

如果您有任何问题,请告诉我。