使用Python的累积OLS

使用Python的累积OLS,python,optimization,pandas,regression,Python,Optimization,Pandas,Regression,我正在使用Pandas 0.8.1,目前无法更改版本。如果更新的版本有助于解决以下问题,请在评论中注明,而不是在回答中注明。此外,这是一个研究复制项目,因此即使在只添加一个新数据点后重新运行回归可能很愚蠢(如果数据集很大),我仍然必须这样做。谢谢 在Pandas中,对于Pandas.ols的window_type参数,有一个rolling选项,但这似乎隐含着需要选择窗口大小或使用整个数据样本作为默认值。我希望以累积方式使用所有数据 我试图在按日期排序的pandas.DataFrame上运行回归。

我正在使用Pandas 0.8.1,目前无法更改版本。如果更新的版本有助于解决以下问题,请在评论中注明,而不是在回答中注明。此外,这是一个研究复制项目,因此即使在只添加一个新数据点后重新运行回归可能很愚蠢(如果数据集很大),我仍然必须这样做。谢谢

在Pandas中,对于
Pandas.ols
window_type
参数,有一个
rolling
选项,但这似乎隐含着需要选择窗口大小或使用整个数据样本作为默认值。我希望以累积方式使用所有数据

我试图在按日期排序的
pandas.DataFrame
上运行回归。对于每个索引
i
,我希望使用从最小日期到索引
i
日期的可用数据运行回归。因此,窗口在每次迭代中有效地增长一次,所有数据从最早的观测开始累积使用,并且没有数据从窗口中丢失

我已经编写了一个函数(如下),它与
apply
一起工作来执行此操作,但速度太慢,令人无法接受。相反,有没有一种方法可以使用
pandas.ols
直接执行这种累积回归

以下是关于我的数据的更多细节。我有一个
pandas.DataFrame
,其中包含一列标识符、一列日期、一列左侧值和一列右侧值。我想使用
groupby
根据标识符进行分组,然后对包含左侧和右侧变量的每个时间段执行累积回归

以下是我可以在标识符分组对象上与
apply
一起使用的函数:

def cumulative_ols(
                   data_frame, 
                   lhs_column, 
                   rhs_column, 
                   date_column,
                   min_obs=60
                  ):

    beta_dict = {}
    for dt in data_frame[date_column].unique():
        cur_df = data_frame[data_frame[date_column] <= dt]
        obs_count = cur_df[lhs_column].notnull().sum()

        if min_obs <= obs_count:
            beta = pandas.ols(
                              y=cur_df[lhs_column],
                              x=cur_df[rhs_column],
                             ).beta.ix['x']
            ###
        else:
            beta = np.NaN
        ###
        beta_dict[dt] = beta
    ###

    beta_df = pandas.DataFrame(pandas.Series(beta_dict, name="FactorBeta"))
    beta_df.index.name = date_column
    return beta_df
def累积函数(
数据帧,
lhs_柱,
rhs_柱,
日期栏,
最小值=60
):
beta_dict={}
对于数据框[日期列]中的dt,唯一()

cur_df=data_frame[data_frame[date_column]根据评论中的建议,我创建了自己的函数,该函数可以与
apply
一起使用,并依赖
cumsum
来累积所有需要的术语,以便从OLS单变量回归向量表达系数

def cumulative_ols(
                   data_frame,
                   lhs_column,
                   rhs_column,
                   date_column,
                   min_obs=60,
                  ):
    """
    Function to perform a cumulative OLS on a Pandas data frame. It is
    meant to be used with `apply` after grouping the data frame by categories
    and sorting by date, so that the regression below applies to the time
    series of a single category's data and the use of `cumsum` will work    
    appropriately given sorted dates. It is also assumed that the date 
    conventions of the left-hand-side and right-hand-side variables have been 
    arranged by the user to match up with any lagging conventions needed.

    This OLS is implicitly univariate and relies on the simplification to the
    formula:

    Cov(x,y) ~ (1/n)*sum(x*y) - (1/n)*sum(x)*(1/n)*sum(y)
    Var(x)   ~ (1/n)*sum(x^2) - ((1/n)*sum(x))^2
    beta     ~ Cov(x,y) / Var(x)

    and the code makes a further simplification be cancelling one factor 
    of (1/n).

    Notes: one easy improvement is to change the date column to a generic sort
    column since there's no special reason the regressions need to be time-
    series specific.
    """
    data_frame["xy"]         = (data_frame[lhs_column] * data_frame[rhs_column]).fillna(0.0)
    data_frame["x2"]         = (data_frame[rhs_column]**2).fillna(0.0)
    data_frame["yobs"]       = data_frame[lhs_column].notnull().map(int)
    data_frame["xobs"]       = data_frame[rhs_column].notnull().map(int)
    data_frame["cum_yobs"]   = data_frame["yobs"].cumsum()
    data_frame["cum_xobs"]   = data_frame["xobs"].cumsum()
    data_frame["cumsum_xy"]  = data_frame["xy"].cumsum()
    data_frame["cumsum_x2"]  = data_frame["x2"].cumsum()
    data_frame["cumsum_x"]   = data_frame[rhs_column].fillna(0.0).cumsum()
    data_frame["cumsum_y"]   = data_frame[lhs_column].fillna(0.0).cumsum()
    data_frame["cum_cov"]    = data_frame["cumsum_xy"] - (1.0/data_frame["cum_yobs"])*data_frame["cumsum_x"]*data_frame["cumsum_y"]
    data_frame["cum_x_var"]  = data_frame["cumsum_x2"] - (1.0/data_frame["cum_xobs"])*(data_frame["cumsum_x"])**2
    data_frame["FactorBeta"] = data_frame["cum_cov"]/data_frame["cum_x_var"]
    data_frame["FactorBeta"][data_frame["cum_yobs"] < min_obs] = np.NaN
    return data_frame[[date_column, "FactorBeta"]].set_index(date_column)
### End cumulative_ols
def累积函数(
数据帧,
lhs_柱,
rhs_柱,
日期栏,
最小obs=60,
):
"""
函数在数据帧上执行累积OLS。它是
用于按类别对数据帧进行分组后与“应用”一起使用
并按日期排序,以便下面的回归适用于时间
一系列单一类别的数据和使用“cumsum”将起作用
适当地给出排序日期。还假定日期
对左侧和右侧变量的约定进行了讨论
由用户安排,以符合所需的任何滞后约定。
此OLS是隐式单变量的,依赖于对
公式:
Cov(x,y)~(1/n)*和(x*y)-(1/n)*和(x)*(1/n)*和(y)
Var(x)~(1/n)*和(x^2)-(1/n)*和(x))^2
β~Cov(x,y)/Var(x)
代码做了进一步的简化,取消了一个因素
of(1/n)。
注意:一个简单的改进是将日期列更改为通用排序
因为没有特别的原因,回归需要时间-
特定系列。
"""
数据帧[“xy”]=(数据帧[lhs\U列]*数据帧[rhs\U列])。fillna(0.0)
数据帧[“x2”]=(数据帧[rhs\U列]**2)。填充(0.0)
数据帧[“yobs”]=数据帧[lhs\u列].notnull().map(int)
数据帧[“xobs”]=数据帧[rhs\U列].notnull().map(int)
数据帧[“cum_yobs”]=数据帧[“yobs”]。cumsum()
数据帧[“cum_xobs”]=数据帧[“xobs”]。cumsum()
数据帧[“cumsum_xy”]=数据帧[“xy”]。cumsum()
数据帧[“cumsum”]=数据帧[“x2”]。cumsum()
数据帧[“cumsum\ux”]=数据帧[rhs\u列].fillna(0.0).cumsum()
数据帧[“cumsum\u y”]=数据帧[lhs\u列].fillna(0.0).cumsum()
数据帧[“cum_cov”]=数据帧[“cumsum_xy”]-(1.0/数据帧[“cum_yobs”])*数据帧[“cumsum_x”]*数据帧[“cumsum_y”]
数据帧[“cum_x_var”]=数据帧[“cumsum_x2”]-(1.0/数据帧[“cum_xobs”])*(数据帧[“cumsum_x”])**2
数据帧[“FactorBeta”]=数据帧[“cum_cov”]/数据帧[“cum_x_var”]
数据帧[“FactorBeta”][数据帧[“cum_yobs”]

我已经在许多测试用例中验证了这与我以前的函数的输出和NumPy的
linalg.lstsq
函数的输出相匹配。我还没有对计时进行完整的基准测试,但有趣的是,在我一直在研究的用例中,它大约快了50倍。

你看过
pd.expanding\u apply()吗
?这似乎是一个较新的版本,但我一定会看一看。谢谢!@EMS如果您无法升级,扩展应用程序实际上只是语法上的糖分。如果您指定滚动应用程序,窗口大小为整个集合的长度,最小周期等于1,那么您将获得与提供cum相同的扩展窗口行为总和(累积总和)和累积积你可以应用到一个系列中。如果你能把你的函数分解成乘积和和,你就可以达到你想要达到的目的…是的,我昨晚大部分时间都在做这个。我会发布我为一元回归系数创建的函数。这让人难以置信的快了多少。