Python TypeError:str.contains参数需为字符串或编译模式问题排查
问题描述
需求是判断names文件中的员工姓名是否存在于record文件中,若存在则提取对应员工编号。由于两个文件姓名格式不同(names名在前,record姓在前),已将names中的姓名拆分为n1、n2、n3、n4四列,需实现以下步骤:
- 检查
names中每位员工的n1、n2、n4、n3是否都出现在record的员工姓名字段中 - 满足条件则标记姓名存在
- 记录该姓名在
record中的行号 - 通过行号提取对应员工编号
其中record DataFrame的员工姓名字段在第8列,员工编号在第2列;names DataFrame拆分后的姓名字段在第2、3、4、5列。使用的循环代码如下:
for i in range(len(names)): x1 = record.index[record.iloc[:, 8].str.contains(names.iloc[i, 3])].values if x1.size > 0: x2 = record.index[record.iloc[:, 8].str.contains(names.iloc[i, 2])].values if x2.size > 0: if names.iloc[i, 4] is not None: x3 = record.index[record.iloc[:, 8].str.contains(names.iloc[i, 4])].values if x3.size > 0: if names.iloc[i, 5] is not None: x4 = record.index[record.iloc[:, 8].str.contains(names.iloc[i, 5])].values if x4.size > 0: flag = 1 loc = x4[0] else: flag = 0 else: flag = 1 loc = x3[0] else: flag = 0 else: flag = 1 loc = x2[0] else: flag = 0 else: flag = 0 if flag == 1: names.iloc[i, 6] = record.iloc[loc,2]
执行时在第2行报错:
----> 2 x1 = record.index[record.iloc[:, 8].str.contains(names.iloc[i, 3])].values TypeError: first argument must be string or compiled pattern
问题分析与解决
报错原因
str.contains()要求第一个参数必须是字符串或编译后的正则表达式,报错说明names.iloc[i,3]的值不是有效字符串——大概率是该位置为NaN、None,或者是数值类型等非字符串数据。
解决步骤
- 预处理姓名列:先将
names中拆分后的姓名列(第2、3、4、5列)转换为字符串类型,并将空值/NaN替换为空字符串,避免传入无效参数:
# 转换为字符串并处理空值 names.iloc[:, [2,3,4,5]] = names.iloc[:, [2,3,4,5]].astype(str).replace({'nan': '', 'None': ''})
- 优化循环逻辑:在调用
str.contains()前,先检查当前字段是否非空,同时简化嵌套结构,提升可读性:
for i in range(len(names)): # 获取当前员工的四个姓名片段并去除前后空格 seg1 = names.iloc[i, 3].strip() seg2 = names.iloc[i, 2].strip() seg3 = names.iloc[i, 4].strip() seg4 = names.iloc[i, 5].strip() flag = 0 loc = None # 先检查seg1是否存在 if seg1: match1 = record.iloc[:, 8].str.contains(seg1, na=False) if match1.any(): # 初始化匹配条件为seg1的结果 combined_match = match1 # 检查seg2是否存在并更新匹配条件 if seg2: match2 = record.iloc[:, 8].str.contains(seg2, na=False) combined_match &= match2 if not combined_match.any(): continue # 检查seg3是否存在并更新匹配条件 if seg3: match3 = record.iloc[:, 8].str.contains(seg3, na=False) combined_match &= match3 if not combined_match.any(): continue # 检查seg4是否存在并更新匹配条件 if seg4: match4 = record.iloc[:, 8].str.contains(seg4, na=False) combined_match &= match4 if not combined_match.any(): continue # 获取第一个匹配的行号 loc = record.index[combined_match].values[0] flag = 1 if flag == 1: names.iloc[i, 6] = record.iloc[loc, 2]
- 关键说明:
- 使用
na=False参数,避免record中姓名列的NaN值导致str.contains()返回NaN,引发索引错误 - 用
strip()去除姓名片段的前后空格,避免因空格导致匹配失败 - 用
&合并所有非空姓名片段的匹配条件,确保所有需要检查的片段都同时出现在record的姓名字段中,贴合需求逻辑
内容的提问来源于stack exchange,提问作者Meenakshi Seshagiri
相关产品推荐
相关产品推荐

