当前位置: 首页 > 面试题库 >

在传递给apply()的自定义函数中访问先前计算的结果

黄飞翮
2023-03-14
问题内容

我正在使用Python处理Pandas,在将自定义函数应用于序列时,我想访问先前计算的结果。

大致像这样:

import pandas

# How can I obtain previous_result?
def foo(value, previous_result = None):

    # On the first iteration there is no previous result
    if previous_result is None:
        previous_result = value

    return value + previous_result

series = pandas.Series([1,2,3])
print(series.apply(foo))

这也可以概括为“如何将n以前的结果传递给函数?”。我知道,series.rolling()但是即使滚动,我也无法获得先前的 结果
,只能获得输入序列的先前值。


问题答案:

最特别的类型你所描述的操作都可以作为cummaxcummincumprodcumsumf(x) = x + f(x-1))。

可以在expanding对象中找到更多功能:平均值,标准偏差,方差峰度,偏度,相关性等。

在大多数情况下,您可以使用expanding().apply() 自定义函数。例如,

from functools import reduce  # For Python 3.x
ser.expanding().apply(lambda r: reduce(lambda prev, value: prev + 2*value, r))

相当于 f(x) = 2x + f(x-1)

我列出的方法已经过优化,并且运行速度非常快,但是当您使用自定义函数时,性能会变差。为了进行指数平滑,对于长度为1000的Series,熊猫开始表现出比循环更好expanding().apply()的性能,但是reduce的性能却很糟糕:

np.random.seed(0)    
ser = pd.Series(70 + 5*np.random.randn(10**4))    
ser.tail()
Out: 
9995    60.953592
9996    70.211794
9997    72.584361
9998    69.835397
9999    76.490557
dtype: float64


ser.ewm(alpha=0.1, adjust=False).mean().tail()
Out: 
9995    69.871614
9996    69.905632
9997    70.173505
9998    70.139694
9999    70.774781
dtype: float64

%timeit ser.ewm(alpha=0.1, adjust=False).mean()
1000 loops, best of 3: 779 µs per loop

带循环:

def exp_smoothing(ser, alpha=0.1):
    prev = ser[0]
    res = [prev]
    for cur in ser[1:]:
        prev = alpha*cur + (1-alpha)*prev
        res.append(prev)
    return pd.Series(res, index=ser.index)

exp_smoothing(ser).tail()
Out: 
9995    69.871614
9996    69.905632
9997    70.173505
9998    70.139694
9999    70.774781
dtype: float64

%timeit exp_smoothing(ser)
100 loops, best of 3: 3.54 ms per loop

总时间仍以毫秒为单位,但是expanding().apply()

ser.expanding().apply(lambda r: reduce(lambda p, v: 0.9*p+0.1*v, r)).tail()
Out: 
9995    69.871614
9996    69.905632
9997    70.173505
9998    70.139694
9999    70.774781
dtype: float64

%timeit ser.expanding().apply(lambda r: reduce(lambda p, v: 0.9*p+0.1*v, r))
1 loop, best of 3: 13 s per loop

类似的方法cummincumsum进行了优化,只需要X的当前值和功能的前值。但是,使用自定义功能时,复杂度为O(n**2)。这主要是因为在某些情况下,函数的先前值和x的当前值不足以计算函数的当前值。对于累积量,您可以使用以前的累积量并添加当前值以得出结果。您不能这样做,例如说几何均值。这就是为什么expanding即使中等大小的Series也无法使用的原因。

通常,对Series进行迭代并不是很昂贵的操作。对于DataFrames,它需要返回每一行的副本,因此效率非常低,但是Series并非如此。当然,应该在可用的情况下使用向量化方法,但是如果不是这种情况,则对诸如递归计算之类的任务使用for循环是可以的。



 类似资料:
  • 使用,并希望将常量/参数传递给自定义映射器 我的目的地具有 Map 类型的字段

  • 问题内容: 当我定义一个自定义类型时,基础类型的类型似乎对我是否可以按原样将其传递给函数还是需要对其进行转换有所不同。 问题是: 为什么和起作用,但不起作用? https://play.golang.org/p/buKNkrg5y- 在这里,当我运行此函数时,它会抱怨,尽管它是基础类型。但是当我打电话或他们成功运行时。 问题答案: 和 您的新类型是2种不同的不同类型。在预期的地方,您必须传递typ

  • 我定义了一个变量: 在

  • 我正在尝试使用对每一行执行一个函数并创建一个考虑多列的新列,我最初使用的是,但速度非常慢。我希望我的自定义函数中的列列表是一个变量,但除非显式地列出变量名,否则无法使其工作。例如,这是可行的: 但如果我希望它使用列输入作为vars进行计算:

  • 我试图使一个异常处理程序接受不同类型的异常争论,我声明了一个函数类型,它接受扩展throwable的任何类型。它可以在声明: > 类型函数 不适用于参数(IllegalStateException) 类型不匹配:无法从函数 到函数

  • 我有一个自定义函数,我想在刀片模板中传递它。这里是功能: 用法如下: 是否可以将自定义功能传递给刀片模板?非常感谢。