让我们假设我们得到以下功能:
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
答案 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