pandas apply的lambda内字符串切片未按预期生效问题排查
问题原因
两段代码运行结果差异的核心是你混淆了pandas整列批量操作和apply逐行传入的标量值操作的适用方法:
- 第一段正常运行的代码中,
data.col3.astype('str').str.slice(3)是对col3整列做批量类型转换、字符串切片,生成的t列每个元素都是单个字符串值,后续apply逐行取x.t时,拿到的是普通字符串,直接和'7'做等值判断完全合法。 - 第二段报错的代码中,
apply(axis=1)会逐行把单行的Series对象传入lambda函数,此时x.col3是单个整数类型的标量值(比如第一行对应值是2347),不是整列Series:- 首先
astype()是pandas对象的专属方法,Python原生整数没有这个方法,调用就会触发异常; - 其次
.str访问器是pandas专门给存储字符串的Series/Index设计的批量操作接口,就算你手动把单个整数转成字符串,普通Python字符串也没有.str属性,自然无法运行。
- 首先
修正方案
方案1:保留apply写法,改用原生Python标量操作
直接在lambda里对单个值用Python原生的类型转换、字符串索引逻辑即可,不需要调用pandas的批量接口:
import pandas as pd data = pd.DataFrame({'col1':[1,2,3,4],'col2':[2018, 2018, 2019, 2020], 'col3':[2347, 1327, 2355, 2111]}) # 取最后一位直接用字符串负索引即可,不需要调用slice data['col4'] = data.apply(lambda x: x.col2 - 1 if str(x.col3)[-1] == '7' else x.col2, axis=1)
方案2:向量化写法(推荐,性能远高于apply)
pandas中尽量避免用apply做逐行循环,直接用整列操作效率会高几个量级,逻辑也更简洁:
# endswith直接判断字符串是否以7结尾,布尔值转int后True为1、False为0,刚好实现减1/不减的逻辑 data['col4'] = data['col2'] - data['col3'].astype(str).str.endswith('7').astype(int)
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

