我得到了一組三維向量(x,y,z),並且我想計算協方差矩陣而不存儲向量。我會在C#中做到這一點,但最終我會用C語言在微控制器上實現它,所以我需要算法本身,而不是庫。運行(單程)協方差計算
僞代碼也會很棒。
我得到了一組三維向量(x,y,z),並且我想計算協方差矩陣而不存儲向量。我會在C#中做到這一點,但最終我會用C語言在微控制器上實現它,所以我需要算法本身,而不是庫。運行(單程)協方差計算
僞代碼也會很棒。
我想我找到了解決方案。它基於這篇文章約how to calculate covariance manually和這個約calculating running variance。然後我根據第一篇文章中的理解,對後者中的算法進行了調整,以計算協方差而非方差。
public class CovarianceMatrix
{
private int _n;
private Vector _oldMean, _newMean,
_oldVarianceSum, _newVarianceSum,
_oldCovarianceSum, _newCovarianceSum;
public void Push(Vector x)
{
_n++;
if (_n == 1)
{
_oldMean = _newMean = x;
_oldVarianceSum = new Vector(0, 0, 0);
_oldCovarianceSum = new Vector(0, 0, 0);
}
else
{
//_newM = _oldM + (x - _oldM)/_n;
_newMean = new Vector(
_oldMean.X + (x.X - _oldMean.X)/_n,
_oldMean.Y + (x.Y - _oldMean.Y)/_n,
_oldMean.Z + (x.Z - _oldMean.Z)/_n);
//_newS = _oldS + (x - _oldM) * (x - _newM);
_newVarianceSum = new Vector(
_oldVarianceSum.X + (x.X - _oldMean.X) * (x.X - _newMean.X),
_oldVarianceSum.Y + (x.Y - _oldMean.Y) * (x.Y - _newMean.Y),
_oldVarianceSum.Z + (x.Z - _oldMean.Z) * (x.Z - _newMean.Z));
/* .X is X vs Y
* .Y is Y vs Z
* .Z is Z vs X
*/
_newCovarianceSum = new Vector(
_oldCovarianceSum.X + (x.X - _oldMean.X) * (x.Y - _newMean.Y),
_oldCovarianceSum.Y + (x.Y - _oldMean.Y) * (x.Z - _newMean.Z),
_oldCovarianceSum.Z + (x.Z - _oldMean.Z) * (x.X - _newMean.X));
// set up for next iteration
_oldMean = _newMean;
_oldVarianceSum = _newVarianceSum;
}
}
public int NumDataValues()
{
return _n;
}
public Vector Mean()
{
return (_n > 0) ? _newMean : new Vector(0, 0, 0);
}
public Vector Variance()
{
return _n <= 1 ? new Vector(0, 0, 0) : _newVarianceSum.DivideBy(_n - 1);
}
}
的公式很簡單,如果你有Matrix
和Vector
班的手:
Vector mean;
Matrix covariance;
for (int i = 0; i < points.size(); ++i) {
Vector diff = points[i] - mean;
mean += diff/(i + 1);
covariance += diff * diff.transpose() * i/(i + 1);
}
我個人總是喜歡這種風格,而不是雙通道計算。代碼簡短,結果完美無瑕。
Matrix
和Vector
可以具有固定的尺寸並且可以容易地爲此編碼。您甚至可以將代碼重寫爲離散浮點計算,並避免計算協方差矩陣的對稱部分。
請注意,在最後一行代碼上有一個向量外部產品。並非所有的矢量庫都能正確解釋它。
從鴯鶓的代碼是優雅,但需要一個額外的步驟是正確的:
Vector mean;
Matrix covariance;
for (int i = 0; i < points.size(); ++i) {
Vector diff = points[i] - mean;
mean += diff/(i + 1);
covariance += diff * diff.transpose() * i/(i + 1);
}
covariance = covariance/(points.size()-1);
注正規化的協方差的最後步驟。
是的,這可以解決!如果您想移動窗口並刪除離開當前窗口的值,只需從舊的協方差總和中減去對於x,首先將「oldMean」計算爲tempMean.X =((oldMean.x * n) - x)/(n-1),然後使用oldCov.x - =(y - oldMean.y)更新協方差和。 *(x - tempMean.x) ,然後將您的oldMean更新爲tempMean。 – optional