2014-03-06 75 views
5

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

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}) 

的问题是,我有很多的数据,并拟合函数是昂贵的,所以我不想两次称呼它为每个样品。我宁愿做的是这样的:

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) 

如果结果是DataFrame有两列。如果我尝试运行此操作,则会发生异常: TypeError: a float is required。有没有可能做到这一点,如果是的话,如何?

+0

如果你返回一个系列而不是字典,它工作吗? –

+0

@AndyHayden不,这给'TypeError:无法将系列转换为' – aquavitae

+0

看到这个问题http://stackoverflow.com/questions/19121854/using-rolling-apply-on-a-dataframe-对象 – Jeff

回答

0

我有一个类似的问题,并通过在应用过程中使用单独的辅助类的成员函数来解决它。该成员函数根据需要返回单个值,但我将其他计算结果存储为类的成员,并可以在以后使用它。

简单的例子:

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 

假设你的函数f将返回两个值V1,V2的元组。然后,您可以返回v1并将其分配给column_v1到您的数据框。第二个值v2只是在辅助类中的series series_val2中累积。之后,您只需将该系列作为您的数据框的新列。 JML

1

我也有同样的问题。我通过生成一个全局数据框并从滚动函数中提供它来解决它。在下面的示例脚本中,我生成了一个随机输入数据。然后,我用一个滚动应用函数计算最小值,最大值和平均值。

import pandas as pd 
import numpy as np 

global outputDF 
global index 

def myFunction(array): 

    global index 
    global outputDF 

    # Some random operation 
    outputDF['min'][index] = np.nanmin(array) 
    outputDF['max'][index] = np.nanmax(array) 
    outputDF['mean'][index] = np.nanmean(array) 

    index += 1 
    # Returning a useless variable 
    return 0 

if __name__ == "__main__": 

    global outputDF 
    global index 

    # A random window size 
    windowSize = 10 

    # Preparing some random input data 
    inputDF = pd.DataFrame({ 'randomValue': [np.nan] * 500 }) 
    for i in range(len(inputDF)): 
     inputDF['randomValue'].values[i] = np.random.rand() 


    # Pre-Allocate memory 
    outputDF = pd.DataFrame({ 'min': [np.nan] * len(inputDF), 
           'max': [np.nan] * len(inputDF), 
           'mean': [np.nan] * len(inputDF) 
           }) 

    # Precise the staring index (due to the window size) 
    d = (windowSize - 1)/2 
    index = np.int(np.floor(d)) 

    # Do the rolling apply here 
    inputDF['randomValue'].rolling(window=windowSize,center=True).apply(myFunction,args=()) 

    assert index + np.int(np.ceil(d)) == len(inputDF), 'Length mismatch' 

    outputDF.set_index = inputDF.index 

    # Optional : Clean the nulls 
    outputDF.dropna(inplace=True) 

    print(outputDF) 
0

我以前有过类似的问题。这里是我的解决方案:

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} 
    )