A further question about lambda, what does "k" mean here?

Viewed 248

Would anyone please tell me what is k here?

def rule(x, y):
    if x == 'high' and y > 10:
         return 1
    else:
         return 0
df = pd.DataFrame({ 'c1':[ 'high' ,'high', 'low', 'low'], 'c2': [0, 23, 17, 4]})
df['new'] = df.apply(lambda k: rule(k['c1'], k['c2']), axis =  1)
df.head()

and why can't I just use the following?

df['new'] = df["c1","c2"].apply(rule['c1'], ['c2'])
2 Answers

There is possible to vectorize arbitrary function:

import numpy as np
df['new'] = np.vectorize(rule)(df.c1, df.c2)

Above solution is not changing Your original function.

Another way is to rewrite function:

def rule(row):
    if row['c1'] == 'high' and row['c2'] > 10:
         return 1
    else:
         return 0

and apply it to dataframe:

df['new'] = df.apply(rule, axis = 1)

Note that axis = 1 is necessary to pass arguments by rows to function applied.

There are two sides that one should understand here.

Argument for func in obj.apply(func)

It depends. You can control what is passed as an argument to func:

  1. If the obj is a pandas.DataFrame, as it is if you use apply on df[["c1", "c2"]] or just df, then refer to documentation of pd.DataFrame.apply(). Note that there is also argument axis with which you may control if the function is applied to rows (1) or columns (0, Default). Then, there is argument raw that can be used to define if the argument passed to func will be pd.Series (False, Default) or numpy arrays (True).

    Therefore, by default, columns are passed to func (as.pd.Series). Now, since you have axis=1, the data is passed row by row, as pd.Series. That means, type of k would be pd.Series and it would contain data for one row.

  2. If the obj is pandas.Series as it is if you use df["col"], then refer to documentation of pandas.Series.apply(). As you can see, in this case pandas will either feed each element in the Series to the function (if func processes one value at time) or the whole array (if func is numpy ufunc).

lambdas are just functions

The k in the lambda is just a name for the argument. See, for example

myfunc = lambda k: rule(k['c1'], k['c2'])

is roughly equivalent to

def myfunc(k):
    return rule(k['c1'], k['c2'])  

Why can't I just apply following?

In the following line

df['new'] = df["c1","c2"].apply(rule['c1'], ['c2'])

The argument(s) passed to apply would not be callable, and that is the reason this would not work. Since rule is a function, rule['c1'] makes no sense. There is no attribute 'c1' for that function.


In case you just want to know how this should be done, I would recommend using np.vectorize as in the @ipj's answer.

Related