pandas apply: difference if function name is in quotes or not

Viewed 207

Example simple dataframe definition:

df = pd.DataFrame({'A':[2,4,1],'B':[8,4,1],'C':[6,2,7]})
df
    A   B   C
0   2   8   6
1   4   4   2
2   1   1   7

Trying to understand the difference in the calls for the function argument in the chunks below:

df.apply(sum)

df.apply('sum')

Both seem to give the same correct result:

A     7
B    13
C    15
dtype: int64

I understand that for this simple example I could have used the DataFrame sum() function directly but the question came from a more convoluted code.

2 Answers

According to the documentation the DataFrame apply() function only accepts functions as first argument, but looking in the source code of pandas.core.apply the following happens in the method FrameApply.get_result:

# string dispatch
if isinstance(self.f, str):
       # Support for `frame.transform('method')`
       # Some methods (shift, etc.) require the axis argument, others
       # don't, so inspect and insert if necessary.
       func = getattr(self.obj, self.f)
       sig = inspect.getfullargspec(func)
       if "axis" in sig.args:
           self.kwds["axis"] = self.axis
       return func(*self.args, **self.kwds)

Here self.f ist the argument of DataFrame.apply (which normally is a function, but in your case is a string) and self.obj is the DataFrame. The interesting part is the

func = getattr(self.obj, sel.f)

That means if you execute df.apply("function_name") the variable func will be set to df.function_name (that's how getattr works). The remaining lines of the above source code aren't relevant to your question and just finalize the execution of apply by filling in additional keyword arguments.

So, in your case df.apply(sum) will use the built-in sum function from Python and df.apply("sum") will somehow use the DataFrame.sum function.

Some justification for why passing strings in general is possible can be found in the comment in the source code, though I've personally never encountered this use case and I can't read the developers' minds. All in all, you should stick to the documentation and only pass functions to DataFrame.apply unless you really know what you are doing.

Supplementary info:
The same applies to .agg() as well:

import pandas as pd
import numpy as np
df = pd.DataFrame(
    columns="   index    who     msg    num ".split(),
    data= [
            [       0,  "U1", "ALRM",     2, ],
            [       1,  "U1", "ALRM",     5, ],
            [       2,  "U3", "INFO",     3, ],]).set_index("index", drop=True)

gp = df.groupby('who')
gp.agg('count') # using pd.Series.count()
gp.agg(count) # trying to find python's built-in count(), but it doesn't exist
              # NameError: name 'count' is not defined
Related