应用具有更新值的lambda函数

时间:2017-06-22 18:40:32

标签: python pandas dataframe lambda

让我们假设我们得到以下功能:

def f(x,y):
    y = x + y
    return y

函数f(x,y)对两个数字求和(但它可能是两个参数的任何或多或少复杂的函数)。现在让我们考虑以下内容

import pandas as pd
import random
import numpy as np

random.seed(1234)
df = pd.DataFrame({'first': random.sample(range(0, 9), 5),
                   'second': np.NaN}, index = None)
y = 1

df
   first  second
0      7     NaN
1      1     NaN
2      0     NaN
3      6     NaN
4      4     NaN

对于问题的范围,数据框的第二列在这里是不相关的,因此我们可以在不失一般性的情况下假设它是NaN。考虑到变量f(x,y)已经初始化为1,让我们将y应用于数据帧的每一行。第一次迭代返回7 + 1 = 8;现在,当再次将函数应用于第二行时,我们希望将y值更新为先前计算的8,因此最终结果为1 + 8 = 9,依此类推。

处理此问题的pythonic方法是什么?我想避免循环并重新分配循环中的变量,因此我的猜测将是

def apply_to_df(df, y):
    result = df['first'].apply(lambda s: f(s,y))
    return result

然而,人们可能很容易看出上述内容并未考虑更新后的值,而是使用y=1的初始原始值计算所有计算。

print(apply_to_df(df,y))
0    8
1    2
2    1
3    7
4    5 

2 个答案:

答案 0 :(得分:1)

注意,您可以使用现有累积功能解决此特定情况。但是,在一般情况下,您可以依靠全局状态来破解它:

In [7]: y = 1

In [8]: def f(x):
   ...:     global y
   ...:     y = x + y
   ...:     return y
   ...:

In [9]: df['first'].apply(lambda s: f(s))
Out[9]:
0     8
1     9
2     9
3    15
4    19
Name: first, dtype: int64
  

我想避免循环并在循环中重新分配变量

注意,pd.DataFrame.apply 是一个vanilla Python循环,它实际上效率较低,因为它会对输入进行大量检查/验证。它并不意味着有效,但方便。因此,如果您关心表现,如果您依赖.apply

,您已经放弃了

老实说,我认为我宁愿在函数内部的行上编写显式循环,而不是依赖于全局状态。

答案 1 :(得分:0)

您可以使用生成器函数来记住先前的计算结果:

def my_generator(series, foo, y_seed=0):
    y = y_seed  # Seed value for `y`.
    s = series.__iter__()  # Create an iterator on the series.
    while True:
        # Call the function on the next `x` value together with the most recent `y` value.
        y = foo(x=s.next(), y=y)   
        yield y

df = df.assign(new_col=list(my_generator(series=df['first'], foo=f, y_seed=1)))
>>> df
   first  second  new_col
0      8     NaN        9
1      3     NaN       12
2      0     NaN       12
3      5     NaN       17
4      4     NaN       21