【问题标题】:Multiple regression with pykalman?pykalman的多元回归?
【发布时间】:2019-08-09 05:58:34
【问题描述】:

我正在寻找一种使用 pykalman 从 1 到 N 回归量来概括回归的方法。我们一开始不会担心在线回归 - 我只是想要一个玩具示例来为 2 个回归量而不是 1 个回归量设置 卡尔曼滤波器,即Y = c1 * x1 + c2 * x2 + const

对于单一回归量情况,以下代码有效。我的问题是如何更改过滤器设置,使其适用于两个回归器:

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    from pykalman import KalmanFilter

    if __name__ == "__main__":
        file_name = '<path>\KalmanExample.txt'
        df = pd.read_csv(file_name, index_col = 0)
        prices = df[['ETF', 'ASSET_1']] #, 'ASSET_2']]
    
        delta = 1e-5
        trans_cov = delta / (1 - delta) * np.eye(2)
        obs_mat = np.vstack( [prices['ETF'], 
                            np.ones(prices['ETF'].shape)]).T[:, np.newaxis]
    
        kf = KalmanFilter(
            n_dim_obs=1,
            n_dim_state=2,
            initial_state_mean=np.zeros(2),
            initial_state_covariance=np.ones((2, 2)),
            transition_matrices=np.eye(2),
            observation_matrices=obs_mat,
            observation_covariance=1.0,
            transition_covariance=trans_cov
        )
    
        state_means, state_covs = kf.filter(prices['ASSET_1'].values)
    
        # Draw slope and intercept...
        pd.DataFrame(
            dict(
                slope=state_means[:, 0],
                intercept=state_means[:, 1]
            ), index=prices.index
        ).plot(subplots=True)
        plt.show()

示例文件 KalmanExample.txt 包含以下数据:

Date,ETF,ASSET_1,ASSET_2
2007-01-02,176.5,136.5,141.0
2007-01-03,169.5,115.5,143.25
2007-01-04,160.5,111.75,143.5
2007-01-05,160.5,112.25,143.25
2007-01-08,161.0,112.0,142.5
2007-01-09,155.5,110.5,141.25
2007-01-10,156.5,112.75,141.25
2007-01-11,162.0,118.5,142.75
2007-01-12,161.5,117.0,142.5
2007-01-15,160.0,118.75,146.75
2007-01-16,156.5,119.5,146.75
2007-01-17,155.0,120.5,145.75
2007-01-18,154.5,124.5,144.0
2007-01-19,155.5,126.0,142.75
2007-01-22,157.5,124.5,142.5
2007-01-23,161.5,124.25,141.75
2007-01-24,164.5,125.25,142.75
2007-01-25,164.0,126.5,143.0
2007-01-26,161.5,128.5,143.0
2007-01-29,161.5,128.5,140.0
2007-01-30,161.5,129.75,139.25
2007-01-31,161.5,131.5,137.5
2007-02-01,164.0,130.0,137.0
2007-02-02,156.5,132.0,128.75
2007-02-05,156.0,131.5,132.0
2007-02-06,159.0,131.25,130.25
2007-02-07,159.5,136.25,131.5
2007-02-08,153.5,136.0,129.5
2007-02-09,154.5,138.75,128.5
2007-02-12,151.0,136.75,126.0
2007-02-13,151.5,139.5,126.75
2007-02-14,155.0,169.0,129.75
2007-02-15,153.0,169.5,129.75
2007-02-16,149.75,166.5,128.0
2007-02-19,150.0,168.5,130.0

单回归器案例提供以下输出,对于双回归器案例,我想要第二个“斜率”图,表示 C2

【问题讨论】:

  • 你能用一些虚拟数据分享一个完整的例子吗? 1 变量回归需要 2 个状态,2 变量回归需要 3 个状态,这似乎很奇怪。我认为有一种更好的方法来处理 pykalman 库中的固定偏移量 - 我使用它已经有一段时间了,所以我不确定。
  • 好的,我已经浓缩并重申了这个问题,删除了回归的在线版本并添加了一些示例数据。对于两个回归量的情况,我显然需要将 ASSET_2 列/向量传递给 kf.filter() 方法,并且我还需要更改各种输入数组和矩阵的维数,但我不知道怎么做。
  • ...只是为了澄清-我对回归中的截距(常量)值不感兴趣-只是系数。

标签: python regression kalman-filter pykalman


【解决方案1】:

已编辑答案以反映我对问题的修改后理解。

如果我理解正确,您希望将可观察输出变量 Y = ETF 建模为两个可观察值的线性组合; ASSET_1, ASSET_2

这个回归的系数将被视为系统状态,即ETF = x1*ASSET_1 + x2*ASSET_2 + x3,其中x1x2分别是系数资产1和2,x3是截距。假设这些系数会缓慢演变。

下面给出了实现此功能的代码,请注意,这只是扩展现有示例以增加一个回归量。

还请注意,您可以通过使用delta 参数获得完全不同的结果。如果将其设置得较大(远离零),则系数将变化得更快,并且回归的重建将接近完美。如果将其设置得较小(非常接近于零),则系数将演变得更慢,并且回归的重建将不太完美。您可能想研究 期望最大化 算法 - supported by pykalman

代码:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pykalman import KalmanFilter

if __name__ == "__main__":
    file_name = 'KalmanExample.txt'
    df = pd.read_csv(file_name, index_col = 0)
    prices = df[['ETF', 'ASSET_1', 'ASSET_2']]
    delta = 1e-3
    trans_cov = delta / (1 - delta) * np.eye(3)
    obs_mat = np.vstack( [prices['ASSET_1'], prices['ASSET_2'],  
                          np.ones(prices['ASSET_1'].shape)]).T[:, np.newaxis]
    kf = KalmanFilter(
        n_dim_obs=1,
        n_dim_state=3,
        initial_state_mean=np.zeros(3),
        initial_state_covariance=np.ones((3, 3)),
        transition_matrices=np.eye(3),
        observation_matrices=obs_mat,
        observation_covariance=1.0,
        transition_covariance=trans_cov        
    )

    # state_means, state_covs = kf.em(prices['ETF'].values).smooth(prices['ETF'].values)
    state_means, state_covs = kf.filter(prices['ETF'].values)


    # Re-construct ETF from coefficients and 'ASSET_1' and ASSET_2 values:
    ETF_est = np.array([a.dot(b) for a, b in zip(np.squeeze(obs_mat), state_means)])

    # Draw slope and intercept...
    pd.DataFrame(
        dict(
            slope1=state_means[:, 0],
            slope2=state_means[:, 1],
            intercept=state_means[:, 2],
        ), index=prices.index
    ).plot(subplots=True)
    plt.show()

    # Draw actual y, and estimated y:
    pd.DataFrame(
        dict(
            ETF_est=ETF_est,
            ETF_act=prices['ETF'].values
        ), index=prices.index
    ).plot()
    plt.show()

地块:

【讨论】:

  • 我应该更具体一点:使用卡尔曼滤波的整个想法是系数确实是随时间变化的。一种替代方法是基于某个窗口应用滚动 OLS 回归,但这会引入一个易于曲线拟合的参数(窗口大小)。它还会引入滞后。这一特定领域的几项研究表明,使用卡尔曼滤波器是建立两种资产之间对冲比率的一种优越方法。我只是试图将问题从两个资产扩展到三个。
  • 这里有一个很好的例子来描述一对仪器的基本应用:thealgoengineer.com/2014/online_linear_regression_kalman_filter
  • 我还没有阅读完整的页面,但快速浏览了一下,似乎这种方法将系数和截距视为系统的状态(而不是价格本身)。这使得 KF 的应用对我来说更加明智 - 因为它的这些未观察到的系数被求解,并且其缓慢变化的动态被建模为滤波器的一部分。
  • 已编辑我的答案以反映我修改后的理解。
  • 太棒了!这就是我要找的。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-05-27
  • 2014-12-24
  • 2011-10-11
  • 2018-11-03
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 2019-07-02
相关资源
最近更新 更多