The question might be very simple, but I get a strange result from Kalman Filter. Let us consider the simplest state-space model, the random walk plus noise: $$ y_{t} = x_{t} + \varepsilon_{t}\\ x_{t} = x_{t-1} + \mu_{t-1} $$ Let us generate $N_{data} = 3000$ data points and with parameters: $Var(\mu_{t}) = 1$ (which is transition variance) and $Var(\varepsilon_{t}) = 1$ (which is observation variance).
Using Kalman EM in Python, I try to estimate the transition and observation variance.
First, I would like to estimate "observation_covariance" and I assume that "transition_covariance" is known:
kf = KalmanFilter(
transition_matrices=[1.], observation_matrices=Data['x'],
transition_covariance=[1.], initial_state_mean=3,
initial_state_covariance=[1.],
em_vars=['observation_covariance']
)
kf = kf.em(Data['y'])
the result is $0.79$.
Second, I do the opposite, i.e. I estimate "transition_covariance" and I assume that "observation_covariance" is known:
kf = KalmanFilter(
transition_matrices=[1.], observation_matrices=Data['x'],
observation_covariance=[1.], initial_state_mean=3,
initial_state_covariance=[1.],
em_vars=['transition_covariance']
)
kf = kf.em(Data['y'])
the result is $0.001$, which is far from $1$!
Next, I assume that both "transition_covariance" and "observation_covariance" are unknown:
kf = KalmanFilter(
transition_matrices=[1.], observation_matrices=Data['x'],
initial_state_mean=3, initial_state_covariance=[1.],
em_vars=['transition_covariance', 'observation_covariance']
)
kf = kf.em(Data['y'])
the result is "observation_covariance" = 0.77 and "transition_covariance" = 0.0002.
What do I do wrong? Shouldn't those estimated variances be close to $1$?
The all code I use is below:
#%%
import pandas as pd
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
import pylab as pl
from pykalman import KalmanFilter
N_data = 3000
Data = pd.DataFrame(columns=['NoiseTrs', 'NoiseObs', 'x', 'y'], index=range(N_data))
Data['NoiseTrs'] = np.random.normal(loc=0.0, scale=1.0, size=N_data)
Data['NoiseObs'] = np.random.normal(loc=0.0, scale=1.0, size=N_data)
# random walk
x_f_v = 3 # first value for the simulation
for i in range(N_data):
if i == 0:
Data.loc[i, 'x'] = x_f_v
else:
Data.loc[i, 'x'] = Data.loc[i - 1, 'x'] + Data.loc[i, 'NoiseTrs']
# plt.plot(Data['x'])
# plt.show()
Data['y'] = Data['x'] + Data['NoiseObs']
# plt.plot(Data[['x', 'y']])
# plt.show()
F = [1.] # transition matrix
H = Data['x'].values.reshape(N_data,1,1).astype(float) # observation matrix
Q = [1.] # transition noise
R = [1.] # observation noise
#%%
init_state_mean = [3.]
init_state_cov = [1.]
kf = KalmanFilter(
transition_matrices=F,
observation_matrices=H,
# transition_covariance=Q,
# observation_covariance=R,
initial_state_mean=init_state_mean,
initial_state_covariance=init_state_cov,
em_vars=['transition_covariance', 'observation_covariance']
# em_vars=['observation_covariance']
# em_vars=['transition_covariance']
)
kf = kf.em(Data['y'].values.astype(float))
print("observation_covariance R :", kf.observation_covariance)
print("transition_covariance Q :", kf.transition_covariance)
```