【问题标题】:Binning data into equal box sizes and apply OLS to each bin将数据分箱到相同大小的箱中,并将 OLS 应用于每个箱
【发布时间】:2016-12-20 14:07:29
【问题描述】:

我有一个 DataFrame df1:

import pandas as pd
import numpy as np
import statsmodels.formula.api as sm

df1 = pd.DataFrame( np.random.randn(3000,1), index= pd.date_range('1/1/1990', periods=3000), columns = {"M"})

我想将元素分组为大小 = 10 的框,使用 OLS 拟合它们并计算 Y_t,其中 Y_t代表一系列直线拟合。

换句话说,我想取前 10 个值,使用 OLS ( Y_t = b*X_t+a_0) 拟合它们并获得这 10 个值的值 Y_t。再次对接下来的 10 个值执行相同操作(不是滚动窗口!),依此类推。

我的方法

我遇到的第一个问题是我无法使用 DateTime 值作为预测变量来拟合元素,因此我定义了一个新的 DataFrame df_fit,其中包含两列 AB。列A包含从0到9的整数,列B以10个元素为一组的df1的值:

 def compute_yt(df,i,bs):

    df_fit = pd.DataFrame({"B": np.arange(1,bs+1),\
                           "A": df.reset_index().loc[i*bs:((i+1)*bs-1), "M"]})

    fit = sm.ols(formula = "A ~ B", data = df_fit).fit()
    yt = fit.params.B*df_fit["B"] + fit.params.Intercept

    return yt

其中bs 是框大小(本例中为10),i 是允许扫描所有值的索引。

最后,

 result = [compute_yt(df1,n,l) for n in np.arange(0,round(len(df1)/l)-1)]           

 result =    
      Name: B, dtype: float64, 840   -0.249590
      841   -0.249935
      842   -0.250280
      843   -0.250625
      844   -0.250970
      845   -0.251315
      846   -0.251660
      847   -0.252005
      848   -0.252350
      849   -0.252695
      Name: B, dtype: float64, 850   -0.252631
      851   -0.252408
      ...    ... 

result 是一个列表,应该包含直线拟合的值。

所以,我的问题如下:

  1. 有没有办法使用 DateTime 值作为预测变量来运行 OLS?

  2. 我想使用列表推导来构建一个包含y_t 值的DataFrame(与df1 具有相同的形状)。这与问题(1)有关,因为我想获得这些值的时间序列。

  3. 有没有更“pythonic”的方式来编写这段代码?我对数据框进行切片的方式似乎不太合适。

【问题讨论】:

  • 在日期方面,显而易见的选择就是转换为整数 astype(np.int64) 或使用 dt 访问器(例如 dt.year)或 dt 访问器的组合。
  • 我不知道它是否比你所做的更 Pythonic,但你可以使用 pd.cutpd.qcut 进行分箱。

标签: python pandas curve-fitting statsmodels binning


【解决方案1】:

不太确定这是否是您想要做的,但我首先向数据框的每一行添加了一个组编号和一个观察编号,然后对其进行旋转,以便每行都有 10 个观察值。

df1 = pd.DataFrame( data={'M':np.random.randn(3000)}, index= pd.date_range('1/1/1990', periods=3000))

df1['group_num'] = np.repeat(range(300), 10)
df1['obs_num'] = np.tile(range(10), 300)

df_pivot = df1.pivot(index='group_num', columns='obs_num')
print(df_pivot.head())

输出

                  M                                                    \
obs_num           0         1         2         3         4         5   
group_num                                                               
0         -0.063775 -1.293410  0.395011 -1.224491  1.777335 -2.395643   
1         -1.111679  1.668670  1.864227 -1.555251  0.959276  0.615344   
2         -0.213891 -0.733493  0.175590  0.561410  1.359565 -1.341193   
3          0.534735 -2.154626 -1.226191 -0.309502  1.368085  0.769155   
4         -0.611289 -0.545276 -1.924381  0.383596  0.322731  0.989450   


obs_num           6         7         8         9  
group_num                                          
0         -1.461194 -0.481617 -1.101098  1.102030  
1         -0.120995 -1.046757  1.286074 -0.832990  
2          0.322485 -0.825315 -2.277746 -0.619008  
3          0.794694  0.912190 -1.006603  0.572619  
4         -1.191902  1.229913  1.105221  0.899331 

然后我编写了一个函数来使用 statsmodels 进行普通最小二乘 - 而不是公式类型。

import statsmodels.api as sm
def compute_yt(row):
    X = sm.add_constant(np.arange(10))
    fit = sm.OLS(row.values, X).fit()
    yt = fit.params[1] * row.values + fit.params[0]
    return yt

然后我通过apply 在所有行上调用了这个函数。

df_pivot.apply(compute_yt, axis=1)

为每个原始的 10 个值集输出一个预测值。

                  M                                                    \
obs_num           0         1         2         3         4         5   
group_num                                                               
0         -0.063775 -1.293410  0.395011 -1.224491  1.777335 -2.395643   
1         -1.111679  1.668670  1.864227 -1.555251  0.959276  0.615344   
2         -0.213891 -0.733493  0.175590  0.561410  1.359565 -1.341193   
3          0.534735 -2.154626 -1.226191 -0.309502  1.368085  0.769155   
4         -0.611289 -0.545276 -1.924381  0.383596  0.322731  0.989450   


obs_num           6         7         8         9  
group_num                                          
0         -1.461194 -0.481617 -1.101098  1.102030  
1         -0.120995 -1.046757  1.286074 -0.832990  
2          0.322485 -0.825315 -2.277746 -0.619008  
3          0.794694  0.912190 -1.006603  0.572619  
4         -1.191902  1.229913  1.105221  0.899331 

【讨论】:

  • 非常感谢您的回答。这绝对比我做的好很多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
  • 2018-04-15
相关资源
最近更新 更多