pandas如何对列应用自定义函数并将结果存入另一DataFrame
问题根因分析
你代码里的两个问题本质是缩进错误+逻辑疏漏,具体如下:
- 函数缩进完全错误:
recognize_delivery_service定义下除了service = None,其余正则规则、匹配判断、return语句都不在函数体内,调用函数时根本不会执行快递商匹配逻辑,自然返回结果错误。 - 循环缩进错误:for循环块内只有
temp_track = df.iloc[i, 44]这一行,后续的函数调用、df3赋值操作都在循环外,只会在循环结束后处理最后一行的单号,不可能逐行写入结果。 - 额外的匹配逻辑漏洞:一是没有处理快递单号的空值、前后空格、非字符串类型,遇到异常值直接报错;二是正则拼接后没有提前编译,匹配效率低,且纯数字规则的匹配顺序有概率出现误判;三是如果df3没有提前初始化和df等长的结构,直接用iloc赋值会触发索引越界报错。
修正方案
提供两种可直接运行的实现方式,第一种保留你原有的循环逻辑做修正,第二种用pandas原生方法实现,效率更高。
方式1:修正原有循环逻辑
修正函数缩进、补全异常处理,调整循环缩进,提前初始化df3结构:
import pandas as pd import re # 修正缩进,将所有函数逻辑包入函数体,增加异常值处理 def recognize_delivery_service(tracking): # 处理空值、非字符串、带前后空格的异常单号 if pd.isna(tracking): return None tracking = str(tracking).strip() usps_pattern = [ '^(94|93|92|95)[0-9]{20}$', '^(94|93|92|95)[0-9]{22}$', '^(70|14|23|03)[0-9]{14}$', '^(M0|82)[0-9]{8}$', '^[A-Z]{2}[0-9]{9}[A-Z]{2}$' ] ups_pattern = [ '^1Z[0-9A-Z]{16}$', '^T+[0-9A-Z]{10}$', '^[0-9]{9}$', '^[0-9]{26}$' ] fedex_pattern = [ '^[0-9]{20}$', '^[0-9]{15}$', '^[0-9]{12}$', '^[0-9]{22}$' ] # 预编译正则提升匹配效率 usps_re = re.compile("|".join(usps_pattern)) ups_re = re.compile("|".join(ups_pattern)) fedex_re = re.compile("|".join(fedex_pattern)) # 优先匹配特征辨识度高的规则(UPS的1Z开头、USPS带字母后缀的规则),避免纯数字规则重叠导致误判 if ups_re.match(tracking): return 'UPS' if usps_re.match(tracking): return 'USPS' if fedex_re.match(tracking): return 'FedEx' return None # 提前初始化df3,保证长度和df一致,避免iloc赋值触发索引错误 df3 = pd.DataFrame(index=df.index, columns=['delivery_service']) # 修正循环缩进,所有循环内逻辑统一缩进4个空格 for i in range(len(df)): temp_track = df.iloc[i, 44] temp_service = recognize_delivery_service(temp_track) df3.iloc[i, 0] = temp_service
方式2:pandas apply实现(推荐)
无需编写显式for循环,pandas自动逐行处理,代码更简洁运行效率更高:
# 复用上面定义好的recognize_delivery_service函数即可 df3 = pd.DataFrame() df3['delivery_service'] = df.iloc[:, 44].apply(recognize_delivery_service)
注意:如果需要调整快递商匹配优先级,直接修改函数内三个正则判断的先后顺序即可。如果后续需要新增其他快递商的匹配规则,直接在函数内追加对应正则和判断逻辑即可。
内容的提问来源于stack exchange,提问作者Tac147
相关产品推荐
相关产品推荐

