用一个值替换Pandas系列中的多个子字符串

22

大家好,

为了替换特定列中的某个字符串,我用了以下方法并且成功了:

dataUS['sec_type'].str.strip().str.replace("LOCAL","CORP")

现在,我想用一个字符串替换多个字符串,比如用"CORP"替换["LOCAL", "FOREIGN", "HELLO"]

怎样才能使它工作呢?下面的代码没有起作用。

dataUS['sec_type'].str.strip().str.replace(["LOCAL", "FOREIGN", "HELLO"], "CORP")
6个回答

36
你可以通过构建一个以“|”分隔的字符串来完成此任务。这样做的原因是 pd.Series.str.replace 支持正则表达式:

用其他字符串替换 Series/Index 中模式/正则表达式的出现次数。等同于 str.replace() 或 re.sub()。

这避免了创建字典的需要。
import pandas as pd

df = pd.DataFrame({'A': ['LOCAL TEST', 'TEST FOREIGN', 'ANOTHER HELLO', 'NOTHING']})

pattern = '|'.join(['LOCAL', 'FOREIGN', 'HELLO'])

df['A'] = df['A'].str.replace(pattern, 'CORP')

#               A
# 0     CORP TEST
# 1     TEST CORP
# 2  ANOTHER CORP
# 3       NOTHING

你的解决方案对我来说最好。谢谢。我也喜欢提出的解决方案(但我认为已被删除)dataUS.replace({"sec_type": { 'POOL' : "OTHERS", 'ABS' : "OTHERS"}})。 - SBad
请问给我点踩的人能否提出这种方法存在的问题? - jpp
这对我没有起作用,是因为我使用的是Python 2吗?另外,您没有解释它为什么有效(这将是更好的答案),但我推断这是一个正则表达式格式?我不熟悉Python 3,但我在这里没有看到文档记录:https://docs.python.org/2/library/string.html#string.replace - Jeff Ellen
这对我来说能用(Python 3.6 / Pandas 0.19.2),也许您正在使用较旧版本的Pandas和/或Python。 OP已经接受了它,虽然... - jpp
1
我下投票了,因为我认为使用Rakesh建议的内置pandas要优于其他方法(甚至是我的答案)。 - Jeff Ellen
@JeffEllen,但是Rakesh的答案(像你的一样)对于子字符串不起作用。 - jpp

13

replace 可以接受 dict ,因此我们只需为那些需要替换的值创建一个字典即可。

dataUS['sec_type'].str.strip().replace(dict(zip(["LOCAL", "FOREIGN", "HELLO"], ["CORP"]*3)),regex=True)

字典信息

dict(zip(["LOCAL", "FOREIGN", "HELLO"], ["CORP"]*3))
Out[585]: {'FOREIGN': 'CORP', 'HELLO': 'CORP', 'LOCAL': 'CORP'}
你收到错误的原因是,str.replacereplace 是不同的。

1
尝试使用dict.fromkeys(["LOCAL", "FOREIGN", "HELLO"], 'CORP')代替。 - cs95
我已经尝试了两种建议的解决方案,但是出现了错误TypeError: replace()至少需要3个参数(给定了2个)。 - SBad
是的,我也有一个不同的解决方案。 - Jeff Ellen
1
@cᴏʟᴅsᴘᴇᴇᴅ 哈哈,就像这个,即使你改进了,仍然…… - BENY

12

@Rakesh的答案非常简洁,但不允许子字符串。然而,通过一个小改变它可以做到。

  1. 使用替换字典,因为它使得更加通用;
  2. Series.replace()(而不是Series.str.replace)中添加关键字参数regex=True。它实际上会做两件事情:它将你的替换更改为正则表达式替换,这更加强大,但你必须转义特殊字符。请注意这一点。其次,它将使替换作用于子字符串而不是整个字符串。这真的很酷!
replacement = {
    "LOCAL": "CORP",
    "FOREIGN": "CORP",
    "HELLO": "CORP"
}

dataUS['sec_type'].replace(replacement, regex=True)

完整代码示例

dataUS = pd.DataFrame({'sec_type': ['LOCAL', 'Sample text LOCAL', 'Sample text LOCAL sample FOREIGN']})

replacement = {
    "LOCAL": "CORP",
    "FOREIGN": "CORP",
    "HELLO": "CORP"
}

dataUS['sec_type'].replace(replacement, regex=True)

输出

0                            CORP
1                            CORP
2                Sample text CORP
3    Sample text CORP sample CORP
Name: sec_type, dtype: object

这个解决方案相对于逐一在列上使用多个替换调用来说比较慢。 - Naresh Kumar

4

如果您有一个很长的列表,@JJP提供的答案是个不错的选择。但是如果您只有两三个,那么您可以在模式中使用 '|' 。请确保增加regex=True参数。

显然,.str.strip()不是必须的,但是这是一个好习惯。

import pandas as pd

df = pd.DataFrame({'A': ['LOCAL TEST', 'TEST FOREIGN', 'ANOTHER HELLO', 'NOTHING']})

df['A'] = df['A'].str.strip().str.replace("LOCAL|FOREIGN|HELLO", "CORP", regex=True)

输出

    A
0   CORP TEST
1   TEST CORP
2   ANOTHER CORP
3   NOTHING

谢谢分享,但是当我尝试在列名上使用这个函数 df.columns.str.replace(' '|'/'|'-','_', regex = True) 时,出现了一个错误 "TypeError: unsupported operand type(s) for |: 'str' and 'str'"。我做错了什么? - Bowen Liu
1
尝试使用df.columns.str.strip().str.replace('[\s\/\-]','_', regex = True) - Cam
非常感谢,Cam!它起作用了。显然是由于我对正则表达式的知识不足。我想\s捕获空格。但我的方法有什么问题呢? - Bowen Liu

2

用于替换pandas Series中多个值的函数:

最初的回答
def replace_values(series, to_replace, value):
    for i in to_replace:
        series = series.str.replace(i, value)
    return series

希望这能对某些人有所帮助。

最初的回答:


0

尝试:

dataUS.replace({"sec_type": { 'LOCAL' : "CORP", 'FOREIGN' : "CORP"}})

这比我的解决方案更好,因为它使用了pandas的本地方法,而我在专注于str.replace()中已知的问题时忽略了它。 - Jeff Ellen
这对于子字符串不起作用。你需要使用pd.Series.str.replace,而不是pd.Series.replace - jpp
@jpp 抱歉,我不明白。 - Rakesh
3
请查阅pd.Series.replace [需要完全匹配字符串]和pd.Series.str.replace [替换子字符串]之间的区别。它们是不同的方法,执行不同的操作。 - jpp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接