估计卡尔曼滤波器的置信区间
我一直在努力实现一个卡尔曼滤波器,用来在一个二维数据集中寻找异常值。这和我在这里找到的一个很棒的帖子非常相似。接下来的步骤,我想预测置信区间(比如说95%的置信度,表示下限和上限的值),也就是我预测下一个值会落在什么范围内。所以除了下面的那条线,我还想生成另外两条线,表示有95%的置信度下一个值会高于下限或低于上限。
我想我需要使用卡尔曼滤波器每次生成预测时返回的不确定性协方差矩阵(P),但我不太确定这样做是否正确。任何指导或参考资料都将非常感谢!
上面帖子中的代码生成了一组随时间变化的测量值,并使用卡尔曼滤波器来平滑结果。
import numpy as np
import matplotlib.pyplot as plt
def kalman_xy(x, P, measurement, R,
motion = np.matrix('0. 0. 0. 0.').T,
Q = np.matrix(np.eye(4))):
"""
Parameters:
x: initial state 4-tuple of location and velocity: (x0, x1, x0_dot, x1_dot)
P: initial uncertainty convariance matrix
measurement: observed position
R: measurement noise
motion: external motion added to state vector x
Q: motion noise (same shape as P)
"""
return kalman(x, P, measurement, R, motion, Q,
F = np.matrix('''
1. 0. 1. 0.;
0. 1. 0. 1.;
0. 0. 1. 0.;
0. 0. 0. 1.
'''),
H = np.matrix('''
1. 0. 0. 0.;
0. 1. 0. 0.'''))
def kalman(x, P, measurement, R, motion, Q, F, H):
'''
Parameters:
x: initial state
P: initial uncertainty convariance matrix
measurement: observed position (same shape as H*x)
R: measurement noise (same shape as H)
motion: external motion added to state vector x
Q: motion noise (same shape as P)
F: next state function: x_prime = F*x
H: measurement function: position = H*x
Return: the updated and predicted new values for (x, P)
See also http://en.wikipedia.org/wiki/Kalman_filter
This version of kalman can be applied to many different situations by
appropriately defining F and H
'''
# UPDATE x, P based on measurement m
# distance between measured and current position-belief
y = np.matrix(measurement).T - H * x
S = H * P * H.T + R # residual convariance
K = P * H.T * S.I # Kalman gain
x = x + K*y
I = np.matrix(np.eye(F.shape[0])) # identity matrix
P = (I - K*H)*P
# PREDICT x, P based on motion
x = F*x + motion
P = F*P*F.T + Q
return x, P
def demo_kalman_xy():
x = np.matrix('0. 0. 0. 0.').T
P = np.matrix(np.eye(4))*1000 # initial uncertainty
N = 20
true_x = np.linspace(0.0, 10.0, N)
true_y = true_x**2
observed_x = true_x + 0.05*np.random.random(N)*true_x
observed_y = true_y + 0.05*np.random.random(N)*true_y
plt.plot(observed_x, observed_y, 'ro')
result = []
R = 0.01**2
for meas in zip(observed_x, observed_y):
x, P = kalman_xy(x, P, meas, R)
result.append((x[:2]).tolist())
kalman_x, kalman_y = zip(*result)
plt.plot(kalman_x, kalman_y, 'g-')
plt.show()
demo_kalman_xy()
3 个回答
因为你的统计数据是从一个样本中得出的,所以总体统计数据大于2个标准差的概率是0.5。这意味着,如果你没有使用2倍标准差的上限置信因子,那么你需要考虑一下你对下一个测量值的预测是否靠谱,特别是你希望这个值有95%的概率低于某个值。这个置信因子的大小会根据你用来计算0.5总体概率的样本大小而变化。样本越小,计算出的协方差矩阵就越不稳定,那么为了得到95%的概率,总体的95%统计数据低于经过调整的样本统计数据时,你需要的因子就会越大。
如果你想知道接下来可能出现的值在什么范围内,并且希望这个范围有95%的把握,那么你需要的是预测区间,而不是置信区间(http://en.wikipedia.org/wiki/Prediction_interval)。
对于二维(或三维)数据,可以通过计算数据的协方差矩阵的特征值来找到椭圆(或椭球)的半轴长度,并根据需要的预测概率来调整半轴的大小。
可以查看预测椭圆和预测椭球,这里有一段Python代码可以帮助你计算95%的预测椭圆或椭球。这可能会帮助你为你的数据计算预测椭圆。
二维的1-sigma区间可以理解为置信椭圆,它的特点是由这个公式定义的:(x-mx).T P^{-1}.(x-mx)==1
。这里的x
是一个二维的参数向量,mx
是二维的平均值或者说椭圆的中心,而P^{-1}
是逆协方差矩阵。想了解如何绘制这样的椭圆,可以参考这个回答。就像sigma区间一样,这个椭圆的面积对应着一个固定的概率,表示真实值落在这个区域内的可能性。如果我们用一个因子n
来缩放(也就是调整区间的长度或椭圆的半径),就可以达到更高的置信度。需要注意的是,因子n
在一维和二维中的概率是不同的:
|`n` | 1D-Intverval | 2D Ellipse |
==================================
1 | 68.27% | 39.35%
2 | 95.5% | 86.47%
3 | 99.73% | 98.89%
在二维中计算这些值有点复杂,遗憾的是我没有公开的参考资料。