动态为Pandas DataFrame列应用Series方法报错原因咨询
嘿,这个问题我之前踩过坑,咱们先把核心问题说清楚:你代码里的testframe[col].func写法是错误的,Python根本不知道你说的func是那个变量里的函数对象——它会直接去Series里找名为"func"的属性,那肯定找不到,所以才报AttributeError。
为什么单独执行没问题?
你单独跑testframe['col1']=testframe['col1'].astype(*argdict['col1'][0])能成功,是因为这里你直接写了方法名astype,Python明确知道要调用Series的astype方法。但在循环里,你用了变量func,然后试图用.func来调用,这完全是两种语法——Python不支持把变量名直接当成属性名来访问(除非用getattr)。
解决方案
我们有两种靠谱的修改方式,都能实现你的需求:
方式1:直接调用函数对象(传入Series实例)
因为你存在funcdict里的是函数对象(比如pd.Series.astype),这类类方法可以直接把Series作为第一个参数传进去。不过要注意str.replace是字符串方法,需要用apply逐元素处理:
import pandas as pd testframe = pd.DataFrame.from_dict({'col1': [1,2], 'col2': [3,4]}) funcdict = {'col1': [pd.Series.astype, str.replace], 'col2': [pd.Series.astype, str.replace]} argdict = {'col1': [['str'], ['1', 'A']], 'col2': [['str'], ['3', 'B']]} for col in testframe.columns: for func in funcdict[col]: idx = funcdict[col].index(func) args = argdict[col][idx] if func == pd.Series.astype: # 直接调用类方法,把Series作为第一个参数 testframe[col] = func(testframe[col], *args) elif func == str.replace: # 字符串方法需要逐元素处理 testframe[col] = testframe[col].apply(lambda x: func(x, *args)) print(testframe)
方式2:用getattr动态获取方法(更通用)
这种方法更灵活,推荐你把方法名以字符串形式存在funcdict里,避免函数对象索引可能出现的问题(比如如果有重复函数的话,index会返回第一个匹配的索引):
import pandas as pd testframe = pd.DataFrame.from_dict({'col1': [1,2], 'col2': [3,4]}) # 存方法名字符串,更可靠 funcdict = {'col1': ['astype', 'str.replace'], 'col2': ['astype', 'str.replace']} argdict = {'col1': [['str'], ['1', 'A']], 'col2': [['str'], ['3', 'B']]} for col in testframe.columns: for idx, func_name in enumerate(funcdict[col]): args = argdict[col][idx] if '.' in func_name: # 处理像str.replace这种链式方法 obj_name, method_name = func_name.split('.') testframe[col] = testframe[col].apply( lambda x: getattr(getattr(x, obj_name), method_name)(*args) ) else: # 直接获取Series的方法并调用 testframe[col] = getattr(testframe[col], func_name)(*args) print(testframe)
运行上面任意一段代码,都能得到你想要的输出:
col1 col2 0 A B 1 1 4
额外提醒
你原代码里用funcdict[col].index(func)来获取索引,这种方式如果funcdict里有重复的函数对象,会拿到第一个匹配的索引,可能导致参数不匹配。用enumerate遍历索引和方法(或方法名)会更安全。
内容的提问来源于stack exchange,提问作者tired

