滚动窗口多项式适合大熊猫

时间:2015-02-11 22:33:09

标签: python numpy pandas

我正在尝试从应用于时间序列的 t -day窗口的 n -degree多项式计算系数。但是,我收到例外TypeError: only length-1 arrays can be converted to Python scalars

我的版本是:

  • Python 3.6
  • pandas version 0.22.0
  • numpy version 1.13.3

代码:

import pandas as pd
import numpy as np
my_ts = pd.Series(data = np.random.normal(size = 365 * 2), index = pd.date_range(start = '2013-01-01', periods = 365 * 2))
coefs = pd.rolling_apply(my_ts, 21, lambda x: np.polyfit(range(len(x)), x, 3))

然而,当我将np.polyfit换行以便它只返回一个系数时,rolling_apply没有问题。

def pf_wrapper(x):
    coef_lst = np.polyfit(range(len(x)), x, 3)
    return coef_lst[0]
coefs = pd.rolling_apply(my_ts, 21, pf_wrapper)

更新:

由于pd.rolling_apply()无法返回非标量,我目前的解决方案如下:

def get_beta(ts, deg):
    coefs = polyfit(range(len(ts)), ts, deg = 3)[::-1]
    return coefs[deg]

b0 = pd.rolling_apply(my_ts, 21, lambda x: get_beta(x, 0))
...
b3 = pd.rolling_apply(my_ts, 21, lambda x: get_beta(x, 3))

4 个答案:

答案 0 :(得分:1)

我认为rolling_apply无法实现。 documentation表示应用函数"必须从ndarray输入生成单个值"。它实际上意味着什么是"必须产生一个值,它可以被转换为单个浮动"。如果您跟进完整的异常追溯,它会引导您在algos.pyx

中使用此代码
output = np.empty(n, dtype=float)
counts = roll_sum(np.isfinite(input).astype(float), win, minp)

bufarr = np.empty(win, dtype=float)
oldbuf = <float64_t*> bufarr.data

n = len(input)
for i from 0 <= i < int_min(win, n):
    if counts[i] >= minp:
        output[i] = func(input[int_max(i - win + 1, 0) : i + 1], *args,
                         **kwargs)
    else:
        output[i] = NaN

output[i] = func(...)行引发错误。您可以看到输出数组已硬编码为dtype float。您收到的错误与尝试将numpy数组(长度大于1)转换为浮点数时所得到的错误相同:

>>> float(np.array([1, 2, 3]))
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    float(np.array([1, 2, 3]))
TypeError: only length-1 arrays can be converted to Python scalars

所以发生的事情是它试图将polyfit的输出分配给float ndarray的单个元素,并且失败,因为polyfit的输出是一个无法转换为a的数组浮。

这可能是&#34;固定&#34;通过使output具有dtype对象,但这会减慢速度。

我认为您必须将rolling_apply视为仅可用于返回单个float的函数。要支持非标量输出,您必须滚动(har har)您自己的rolling_apply版本。

答案 1 :(得分:0)

我想创建一个IIR过滤器类型的时间序列扩展。 例如:[1,2,3,4,5]窗口= 2应该给出:[[1,2],[2,3],[3,4],[4,5]]

这是我的解决方案基于一些糟糕的编码实践,但完成了工作。 将指数从rolling_apply()返回到全局字典/数组,并丢弃返回值。当rolling_apply返回时,解决方案已在dict中准备就绪。

import pandas as pd
import numpy as np

dataDict = dict()
INDEX = 0

def windowFunc(w):
  global INDEX
  global dataDict
  dataDict[INDEX] = np.copy(w)
  INDEX = INDEX + 1
  return INDEX

dd = pd.DataFrame([1,2,3,4,5,6,7,8,9,0])
dd2 = pd.rolling_apply(dd, window=2, func = windowFunc)
print(list(dataDict.values()))

答案 2 :(得分:0)

我遇到了同样的问题,您只需将[0]添加到lambda函数:

coefs = pd.rolling_apply(my_ts, 21, lambda x: np.polyfit(range(len(x)), x, 3)[0])

现在工作正常。

答案 3 :(得分:0)

由于不建议使用rolling_apply,因此Nissar的解决方案也可以使用pd.rolling.apply方法:

coefs = my_ts.rolling(21).apply(lambda x: np.polyfit(range(len(x)), x, 3)[0])    

此处特别重要的是Nissar使用range(len(x))来满足时间分量,这避免了无法使用rolling.apply应用于具有两列或系列的lambda函数(因为x的占位符计数) (时间)组件通常位于数据框的另一列或其他系列中。