public void Test() { // Make a random list. RandomHelper.Random = new Random(77); List <VectorF> points = new List <VectorF>(); for (int i = 0; i < 10; i++) { var vector = new VectorF(4); RandomHelper.Random.NextVectorF(vector, -1, 10); points.Add(vector); } PrincipalComponentAnalysisF pca = new PrincipalComponentAnalysisF(points); Assert.Greater(pca.Variances[0], pca.Variances[1]); Assert.Greater(pca.Variances[1], pca.Variances[2]); Assert.Greater(pca.Variances[2], pca.Variances[3]); Assert.Greater(pca.Variances[3], 0); Assert.IsTrue(pca.V.GetColumn(0).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(1).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(2).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(3).IsNumericallyNormalized); // Compute covariance matrix and check if it is diagonal in the transformed space. MatrixF cov = StatisticsHelper.ComputeCovarianceMatrix(points); MatrixF transformedCov = pca.V.Transposed * cov * pca.V; for (int row = 0; row < transformedCov.NumberOfRows; row++) { for (int column = 0; column < transformedCov.NumberOfColumns; column++) { if (row != column) { Assert.IsTrue(Numeric.IsZero(transformedCov[row, column])); } } } // The principal components must be Eigenvectors which means that multiplying with the covariance // matrix does only change the length! VectorF v0 = pca.V.GetColumn(0); VectorF v0Result = cov * v0; Assert.IsTrue(VectorF.AreNumericallyEqual(v0.Normalized, v0Result.Normalized)); VectorF v1 = pca.V.GetColumn(1); VectorF v1Result = cov * v1; Assert.IsTrue(VectorF.AreNumericallyEqual(v1.Normalized, v1Result.Normalized)); VectorF v2 = pca.V.GetColumn(2); VectorF v2Result = cov * v2; Assert.IsTrue(VectorF.AreNumericallyEqual(v2.Normalized, v2Result.Normalized)); VectorF v3 = pca.V.GetColumn(3); VectorF v3Result = cov * v3; Assert.IsTrue(VectorF.AreNumericallyEqual(v3.Normalized, v3Result.Normalized)); }
public void Test() { // Make a random list. RandomHelper.Random = new Random(77); List<VectorF> points = new List<VectorF>(); for (int i = 0; i < 10; i++) { var vector = new VectorF(4); RandomHelper.Random.NextVectorF(vector, -1, 10); points.Add(vector); } PrincipalComponentAnalysisF pca = new PrincipalComponentAnalysisF(points); Assert.Greater(pca.Variances[0], pca.Variances[1]); Assert.Greater(pca.Variances[1], pca.Variances[2]); Assert.Greater(pca.Variances[2], pca.Variances[3]); Assert.Greater(pca.Variances[3], 0); Assert.IsTrue(pca.V.GetColumn(0).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(1).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(2).IsNumericallyNormalized); Assert.IsTrue(pca.V.GetColumn(3).IsNumericallyNormalized); // Compute covariance matrix and check if it is diagonal in the transformed space. MatrixF cov = StatisticsHelper.ComputeCovarianceMatrix(points); MatrixF transformedCov = pca.V.Transposed * cov * pca.V; for (int row = 0; row < transformedCov.NumberOfRows; row++) for (int column = 0; column < transformedCov.NumberOfColumns; column++) if (row != column) Assert.IsTrue(Numeric.IsZero(transformedCov[row, column])); // The principal components must be Eigenvectors which means that multiplying with the covariance // matrix does only change the length! VectorF v0 = pca.V.GetColumn(0); VectorF v0Result = cov * v0; Assert.IsTrue(VectorF.AreNumericallyEqual(v0.Normalized, v0Result.Normalized)); VectorF v1 = pca.V.GetColumn(1); VectorF v1Result = cov * v1; Assert.IsTrue(VectorF.AreNumericallyEqual(v1.Normalized, v1Result.Normalized)); VectorF v2 = pca.V.GetColumn(2); VectorF v2Result = cov * v2; Assert.IsTrue(VectorF.AreNumericallyEqual(v2.Normalized, v2Result.Normalized)); VectorF v3 = pca.V.GetColumn(3); VectorF v3Result = cov * v3; Assert.IsTrue(VectorF.AreNumericallyEqual(v3.Normalized, v3Result.Normalized)); }
private void DoPca() { // Create random 2-dimensional vectors. var points = new List <VectorF>(); for (int i = 0; i < 20; i++) { var x = RandomHelper.Random.NextFloat(-200, 200); var y = RandomHelper.Random.NextFloat(-100, 100); var randomVector = new VectorF(new float[] { x, y }); points.Add(randomVector); } // Draw a small cross for each point. var debugRenderer = GraphicsScreen.DebugRenderer2D; debugRenderer.Clear(); var center = new Vector3(640, 360, 0); foreach (var point in points) { var x = point[0]; var y = point[1]; debugRenderer.DrawLine( center + new Vector3(x - 10, y - 10, 0), center + new Vector3(x + 10, y + 10, 0), Color.Black, true); debugRenderer.DrawLine( center + new Vector3(x + 10, y - 10, 0), center + new Vector3(x - 10, y + 10, 0), Color.Black, true); } // Compute the average of the points. var average = new Vector2F(); foreach (var point in points) { average += (Vector2F)point; } average /= points.Count; // Compute the PCA of the point set. var pca = new PrincipalComponentAnalysisF(points); // Get the principal components. // pca.V is a matrix where each column represents a principal component. // The first column represents the first principal component, which can be loosely // interpreted as the "direction of the widest spread". Vector2F pc0 = (Vector2F)pca.V.GetColumn(0); // The second column represents the second principal component, which is a vector // orthogonal to the first. Vector2F pc1 = (Vector2F)pca.V.GetColumn(1); // pca.Variances contains the variances of the data points along the principal components. // The square root of the variance is the standard deviation. float standardDeviation0 = (float)Math.Sqrt(pca.Variances[0]); float standardDeviation1 = (float)Math.Sqrt(pca.Variances[1]); // Draw a line in the direction of the first principal component through the average point. // The line length is proportional to the standard deviation with an arbitrary scaling. debugRenderer.DrawLine( center + new Vector3(average.X, average.Y, 0) - 3 * standardDeviation0 * new Vector3(pc0.X, pc0.Y, 0), center + new Vector3(average.X, average.Y, 0) + 3 * standardDeviation0 * new Vector3(pc0.X, pc0.Y, 0), Color.Black, true); // Draw a line in the direction of the second principal component through the average point. debugRenderer.DrawLine( center + new Vector3(average.X, average.Y, 0) - 3 * standardDeviation1 * new Vector3(pc1.X, pc1.Y, 0), center + new Vector3(average.X, average.Y, 0) + 3 * standardDeviation1 * new Vector3(pc1.X, pc1.Y, 0), Color.Black, true); }