使用pykalman进行多元回归?

问题描述 投票:0回答:1

我正在寻找一种使用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的图。

enter image description here

python regression kalman-filter pykalman
1个回答
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()

图:

States evolving

Reconstruction of regressand

© www.soinside.com 2019 - 2024. All rights reserved.