从pandas.rolling_apply返回两个值

aqu*_*tae 13 python pandas

我正在使用pandas.rolling_apply将数据拟合到分布并从中获取值,但我需要它还报告滚动的拟合优度(特别是p值).目前我这样做:

def func(sample):
    fit = genextreme.fit(sample)
    return genextreme.isf(0.9, *fit)

def p_value(sample):
    fit = genextreme.fit(sample)
    return kstest(sample, 'genextreme', fit)[1]

values = pd.rolling_apply(data, 30, func)
p_values = pd.rolling_apply(data, 30, p_value)
results = pd.DataFrame({'values': values, 'p_value': p_values})
Run Code Online (Sandbox Code Playgroud)

问题是我有很多数据,而且拟合函数很昂贵,所以我不想为每个样本调用两次.我宁愿做的是这样的事情:

def func(sample):
    fit = genextreme.fit(sample)
    value = genextreme.isf(0.9, *fit)
    p_value = kstest(sample, 'genextreme', fit)[1]
    return {'value': value, 'p_value': p_value}

results = pd.rolling_apply(data, 30, func)
Run Code Online (Sandbox Code Playgroud)

结果是DataFrame两列的结果.如果我试图运行它,我得到一个例外: TypeError: a float is required.是否有可能实现这一目标,如果是这样,如何实现?

小智 5

我有一个类似的问题,并通过在应用期间使用单独的帮助程序类的成员函数解决了它。该成员函数按要求返回单个值,但我将其他计算结果存储为类的成员,然后可以使用它。

简单示例:

class CountCalls:
    def __init__(self):
        self.counter = 0

    def your_function(self, window):
        retval = f(window)
        self.counter = self.counter + 1


TestCounter = CountCalls()

pandas.Series.rolling(your_seriesOrDataframeColumn, window = your_window_size).apply(TestCounter.your_function)

print TestCounter.counter
Run Code Online (Sandbox Code Playgroud)

假设您的函数 f 将返回一个包含两个值 v1,v2 的元组。然后您可以返回 v1 并将其分配给 column_v1 到您的数据帧。您只需在 helper 类中的 Series series_val2 中累积第二个值 v2。之后,您只需将该系列作为数据框的新列。JML


Yi *_* Yu 5

我之前也遇到过类似的问题。这是我的解决方案:

from collections import deque
class your_multi_output_function_class:
    def __init__(self):
        self.deque_2 = deque()
        self.deque_3 = deque()

    def f1(self, window):
        self.k = somefunction(y)
        self.deque_2.append(self.k[1])
        self.deque_3.append(self.k[2])
        return self.k[0]    

    def f2(self, window):
        return self.deque_2.popleft()   
    def f3(self, window):
        return self.deque_3.popleft() 

func = your_multi_output_function_class()

output = your_pandas_object.rolling(window=10).agg(
    {'a':func.f1,'b':func.f2,'c':func.f3}
    )
Run Code Online (Sandbox Code Playgroud)