Python 中的函数,用于遍历列并在满足条件时替换值

function in python to loop through columns and replace values if condition is met

提问人:user3641630 提问时间:9/15/2023 最后编辑:user3641630 更新时间:9/15/2023 访问量:71

问:

我想创建一个计算列 A-C 的函数。如果行值为 Type,后跟 A、B、C,则将这些列中的值替换为 “”。如果替换了一个值,我想创建一个名为“Replaced”=1 的列。

下面是创建 df 的代码和我编写的函数。我想知道我在这个功能中做错了什么?有人可以帮我吗?

import pandas as pd 
df = pd.DataFrame(
            {
                    'ID': ['1','2','3','4','5'],
                    'Values': [57, 98, 87, 69, 98],
                    'A': ['Type', 'Type', 'Type', 'Type', 'Type'],
                    'B': ['A', 'B', 'Type', 'Type', 'Type'],
                    'C': ['B', 'B','A', 'Type', 'C']
            }
    )
df





#function I wrote:
cols=['A','B','C']
def fix_type(self):
    for i in range(len(cols) - 1):
        if cols[i] == 'Type' and cols[i+1] in ['A', 'B', 'C']:
            cols[i] = ''
            cols[i+1] = ''
            Replaced = 1

df[cols].apply(fix_type)
df

上面的函数没有给出我想要的结果。结果如下所示:如上所述,如果 Type 后面跟着 A、B、C,我想用 “” #replace “Type” 和后面的 A/B/C。

df_result=pd.DataFrame(
            {
                    'ID': ['1','2','3','4','5'],
                    'Values': [57, 98, 87, 69, 98],
                    'A': ['', '', 'Type', 'Type', 'Type'],
                    'B': ['', '','', 'Type', ''],
                    'C': ['B', 'B','', 'Type', ''],
                    'Replaced': [1, 1,1,0, 1]
            }
    )

df_result
pandas 函数 for-loop

评论

0赞 Quang Hoang 9/15/2023
您应该解释预期的输出。不清楚为什么第二行变成 .'','','B'
0赞 user3641630 9/15/2023
我希望我的评论能澄清它。我想替换 type 后跟 A、B 或 C 的行。

答:

0赞 RomanPerekhrest 9/15/2023 #1

1)具有自定义更换功能:

def replace_type_pair(s):
    abc_cols = s[:-1]   # (A, B, C) columns
    idx = ((abc_cols.eq('Type') & abc_cols.shift(-1).isin(abc_cols.index))
            .values.nonzero()[0])   # index of 'Type' value conditioned
    if idx.size:
        s[idx[0]: idx[0] + 2] = ''  # reset 'Type' and the value next to it
        s['Replaced'] = 1
    return s

df['Replaced'] = 0
cols = ['A', 'B', 'C', 'Replaced']
df.loc[:, cols] = (df[cols].apply(replace_type_pair, axis=1))
print(df)

  ID  Values     A     B     C  Replaced
0  1      57                 B         1
1  2      98                 B         1
2  3      87  Type                     1
3  4      69  Type  Type  Type         0
4  5      98  Type                     1

2) 使用布尔掩码和基于初步发现/计算的索引对匹配行的遍历:

cols = ['A', 'B', 'C']
df['Replaced'] = 0
m = (df[cols].eq('Type', axis=1) & df[cols].shift(-1, axis=1).isin(cols))
idx = np.argwhere(m.values)
df.loc[idx[:, 0], 'Replaced'] = 1
for row, col in idx:
    df.loc[row, cols[col: col + 2]] = ''
print(df)

评论

0赞 user3641630 9/15/2023
谢谢!作为 python 的新手,我学到了一些新东西。
0赞 RomanPerekhrest 9/15/2023
@user3641630,欢迎,检查我的第二种方法,它对你来说可能更有效率
1赞 user3641630 9/15/2023
谢谢 - 非常感谢。
0赞 Timeless 9/15/2023 #2

另一种可能的解决方案:

tmp = df[cols]
N = 1 # "OP: immediately followed"
m1 = tmp.mask(tmp.eq("Type")).bfill(axis=1, limit=N).isnull()
m2 = tmp.shift(axis=1, fill_value="Type").ne("Type")

out = (
    df[df.columns.difference(cols)].join(tmp.where(m1|m2, ""))
        .assign(Replaced=(~(m1^m2).all(axis=1)).astype(int))
)

输出:

print(out)

  ID  Values     A     B     C  Replaced
0  1      57                 B         1
1  2      98                 B         1
2  3      87  Type                     1
3  4      69  Type  Type  Type         0
4  5      98  Type                     1