Home > other >  python pandas how to use function with math use apply and lambda
python pandas how to use function with math use apply and lambda

Time:12-07

I have some slice of program with example df:

import pandas as pd
from math import floor

d = {'ind': ['a', 'b', 'c'], 'col1': [1, 2, 3], 'col2': [4, 5, 6], 'col3': [7, 8, 9], 'spec': [9, 6, 3]}
df = pd.DataFrame(data=d).set_index('ind')

def func(x,y):
    return (1-x)*(y 1)*0.9

print(df)

df2 = df.apply(lambda x: func(x, df.spec))

print(df2)

Its working ok, but when i change a bit func and add floor to it:

def func(x,y):
    return floor((1-x)*(y 1)*0.9)

with it i have error:

TypeError: cannot convert the series to <class 'float'>

how can I change df2 or func to get it to work?

EDIT AFTER GOOD ANWSER:

Now i see, that i forgot that i have condition in function, and i need something else to work.

def func(x,y):
    if x == 1:
        return y
    else:
        return floor((1-x)*(y 1)*0.9)

In this func with yours answers i get:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

pointing on line if x == 1:

CodePudding user response:

If you want to use floor from math module, you have to pass scalar values and not a list-like. You can use a comprehension:

def func(x,y):
    return [floor(r) for r in (1-x)*(y 1)*0.9]

print(df.apply(lambda x: func(x, df.spec)))

# Output:
     col1  col2  col3  spec
ind                        
a       0   -27   -54   -72
b      -7   -26   -45   -32
c      -8   -18   -29    -8

Alternative is to use floor from numpy:

def func(x,y):
    return np.floor((1-x)*(y 1)*0.9).astype(int)

print(df.apply(lambda x: func(x, df.spec)))

# Output:
     col1  col2  col3  spec
ind                        
a       0   -27   -54   -72
b      -7   -26   -45   -32
c      -8   -18   -29    -8

Update

Now i see, that i forgot that i have condition in function, and i need something else to work.

def func(x, y):
    out = []
    for i, j in zip(x, y):
        if i == 1:
            out.append(j)
        else:
            out.append(floor((1-i)*(j 1)*0.9))
    return out

print(df.apply(lambda x: func(x, df.spec)))

# Output:
     col1  col2  col3  spec
ind                        
a       9   -27   -54   -72
b      -7   -26   -45   -32
c      -8   -18   -29    -8

But it's really not optimal. You have to use Pandas/NumPy:

def func(x, y):
    x = x.mask(x == 1)
    r = (1-x)*(y 1)*0.9
    return np.floor(r.fillna(y)).astype(int)
    
print(df.apply(lambda x: func(x, df.spec)))

# Output:
     col1  col2  col3  spec
ind                        
a       9   -27   -54   -72
b      -7   -26   -45   -32
c      -8   -18   -29    -8
  • Related