Programming
python python-3.x pandas functional-programming series
Updated Sun, 24 Jul 2022 23:04:53 GMT

Apply a method from a list of methods to pandas dataframe


this is my first question here so please be patient with me.

My problem is as follows:

Assume we have a pandas Dataframe and we want to apply dynamically some pd.Series methods to a set of columns of this Dataframe. Why the following example doesn't work?

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)
            testframe[col]=testframe[col].func(*argdict[col][idx])

Expected outcome would be

  col1 col2
0  'A'  'B'
1  '1'  '4'

But instead i get

AttributeError: 'Series' object has no attribute 'func'

Remarkably

testframe['col1']=testframe['col1'].astype(*argdict['col1'][0])

works as expected, so somehow python seems to have a problem with the '.func' syntax despite the fact that

print(func)

yields the desired output: 'function NDFrame.astype at 0x00000186954EB840' etc.




Solution

Your syntax for calling a method is incorrect. There are 2 ways you can call a method in Python.

Direct

As you found, this will work. Note that astype isn't referencing some other object, it's the actual name of the method belonging to pd.Series.

testframe['col1'] = testframe['col1'].astype(*argdict['col1'][0])

Functional

The functional method demonstrates explicitly that astype is the name of the method.

from operator import methodcaller
testframe['col1'] = methodcaller('astype', *argdict['col1'][0])(testframe[col])

Trying testframe[col].func(...) will never work as func is not the name of a pd.Series method.





Comments (1)

  • +1 – This solved my problem by using $func.__name__$ as a first argument for methodcaller. Didn't know about that functionality..thx! — May 15, 2018 at 22:50