Skip to main content
 首页 » 编程设计

python之Pandas str.replace 方法正则表达式标志引发不一致的异常

2024年11月24日27oomusou

当我在 pd.Series.str.replace() 方法中使用 regex=[True|False] 标志时,我得到了矛盾的异常:

  • repl 是一个字典 => 它说 repl must be a string or callable
  • repl is a callable => 它说 Cannot use a callable replacement when regex=False

我正在尝试用相应的英文短名称替换 DataFrame 索引中西类牙日期的月份部分。

import pandas as pd 
import numpy as np 
 
# Define the months' short names in English and Spanish 
ENG = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] 
ESP = ['ENE', 'FEB', 'MAR', 'ABR', 'MAY', 'JUN', 'JUL', 'AGO', 'SEP', 'OCT', 'NOV', 'DIC'] 
 
# Dictionary mapping Spanish months to English months 
esp2eng = dict(zip(ESP, ENG)) 
 
# Function to make the dictionary "callable" 
def eng_from_esp(key): 
    return esp2eng[key] 
 
# Create the DF with date in the "%d-%b-%y" format as index, where %b is the Spanish naming 
idx = ['06-{}-19'.format(m) for m in ESP] 
col = ['ordinal'] 
data = pd.DataFrame(np.arange(12).reshape((12, 1)), 
                   index=idx, 
                   columns=col) 
 
data.index.str.replace('ENE', esp2eng, regex=False) 
TypeError: repl must be a string or callable 
 
data.index.str.replace('ENE', eng_from_esp, regex=False) 
ValueError: Cannot use a callable replacement when regex=False 

请您参考如下方法:

如果您查看 pandas.Series.str.replace 的文档您会看到 repl 参数可以是 string 或 callable,但不支持 dict。

考虑到这一点,不支持您的第一次尝试。

深入研究源代码(下面转载的关键部分),您仍然看到 string 或 callable 的检查是首先完成的,在检查 regex 标志之前。

# Check whether repl is valid (GH 13438, GH 15055) 
if not (is_string_like(repl) or callable(repl)): 
    raise TypeError("repl must be a string or callable") 
 
if regex: 
    # omitted 
else: 
    # omitted 
    if callable(repl): 
        raise ValueError("Cannot use a callable replacement when " 
                         "regex=False") 

因此,您的第一次尝试(使用 repl 的字典)触发了第一个 if 检查,打印出消息 “repl must be a string or callable”.

您的第二次尝试通过了此检查,但随后被 regex 检查的 else block 内的可调用检查绊倒了。

所以简而言之,没有不一致。当然,第一个错误消息可能可能会被改进为类似“repl 必须是字符串或可调用的(除非您使用的是 regex=False)”,但事实并非如此必要的。


FWIW,这是一个应该达到预期结果的 Pandas “单线”:

print( 
    data.reset_index() 
        .replace(esp2eng, regex=True) 
        .set_index("index", drop=True) 
        .rename_axis(None, axis=0) 
) 
#           ordinal 
#06-JAN-19        0 
#06-FEB-19        1 
#06-MAR-19        2 
#06-APR-19        3 
#06-MAY-19        4 
#06-JUN-19        5 
#06-JUL-19        6 
#06-AUG-19        7 
#06-SEP-19        8 
#06-OCT-19        9 
#06-NOV-19       10 
#06-DEC-19       11