2

I would like to modify multiple columns with pandas.

import pandas as pd
df = pd.DataFrame({'a': [1,2], 'b':[3,4]})
df = df.assign(**{v: lambda x:x[v]*10 for v in ['a', 'b']})

doesn't return the expected result.

10 30
20 40

It returns

30 30
40 40

To my understanding this is due to lazy binding, explained here: https://sopython.com/wiki/Common_Gotchas_In_Python

The desired result can be obtained by a proper function.

def fun(x):
    return x*10

df[['a','b']] = df[['a','b']].apply(fun)

Is there a way to break the lazy binding in a dictionary comprehension like above? Or are lambda functions too limited ?

Marcel Flygare
  • 837
  • 10
  • 19
  • 3
    Have you tried: `df.assign(**{v: lambda x,v=v:x[v]*10 for v in ['a', 'b']})` ? (note the `v=v`) – Jon Clements Jun 08 '22 at 11:07
  • 1
    Which I think the lazy binding example on sopython does show - but I might think about updating it if that example isn't that clear... – Jon Clements Jun 08 '22 at 11:08
  • Given your example though... you'd be better of using `df *= 10`... – Jon Clements Jun 08 '22 at 11:13
  • @JonClements First comment is the acceptable answer for me. (I'll missed the idea on using two vars in a lambda on skimming through sopython's code). Background: Agreed, df *= 10 is even shorter. I ran into this issue whilst refactoring a data cleansing pipeline and isolated it to the above toy example. – Marcel Flygare Jun 09 '22 at 07:31
  • yeah... probably a dupe then... if you've any suggestions as to how to improve the page on sopython that'd make it clearer - I'd be happy to make edits (I'm a co-founder of the site :p) – Jon Clements Jun 09 '22 at 08:47
  • @JonClements: should your first comment be elevated to an answer for this question? This helped me resolve a very frustrating issue. – Alex Trueman Aug 01 '22 at 18:04

1 Answers1

0

As @jon-clements correct comment:

df.assign(**{v: lambda x,v=v:x[v]*10 for v in ['a', 'b']}) ?

Explained in a answer in the topic How does python dict comprehension work with lambda functions inside

the_RR
  • 311
  • 2
  • 9