65.9K
CodeProject 正在变化。 阅读更多。
Home

使用主成分分析进行匹配(和分析)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (8投票s)

2009年9月26日

MIT

2分钟阅读

viewsIcon

36199

downloadIcon

1177

PCA 是一种众所周知的从多维数据集中提取特征的算法。 使用我编写的库,这变得很容易。

引言

PCA 匹配算法分析来自 n 维的数据坐标,并返回一个表示数据主要偏差的正交坐标。

数据主要偏差的坐标表示给定坐标密度的方向。 此信息可用于最大限度地减少维度数量,同时尽可能减少数据损失,用于有损压缩。

另一种用途是排列在参数上有所不同的两组数据,例如对齐的、向后旋转/缩放/放置的形状。

背景

基于主成分分析(又名 PCA 算法)的匹配是“形状匹配框架”的一部分,该框架旨在在使用 .NET 构建绘图相似性/差异软件时提供核心支持。

该项目仅使用并依赖于“形状匹配框架”解决方案提供的矩阵库实现。 我们可以轻松地分离这两个项目/DLL,以仅获得此算法的功能。

对于此库有两种使用方法:一种是使用“普通”PCA 算法来提取绘图的坐标属性。 另一种是使用提供的匹配算法将目标绘图优化得更接近源。

使用代码

在 PCA 项目中,有一个 PCAtransform 实现,它是一个纯粹的、按部就班的实现。 这为我们提供了一组特征值和一组对应的特征向量,它们作为 DoubleMatrix 返回。 从这两个参数中,我们可以推断出两个计算输入的相对角度和相对密度。

在下面的示例中,我们将发现,使用两个 PCA 变换,可以将两组旋转的坐标识别为旋转的。

我们还将看到,两个输入的密度(与缩放相同)因子是相同的,这将指向这样一个事实:为了整合这两个输入,不应该对它们进行缩放。

请注意,如果需要缩放,请使用 PCA 变换找到的缩放因子的平方根。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using LiniarAlgebra;
using Adaption;
using System.Drawing;
using System.Reflection;
using PCA;

namespace New_Project
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            //Preparing rotation matrix 30 deg. counterclockwise
            double angle = Math.PI/180 * 30; //~= 0.52...
            DoubleMatrix rotationMatrix = PrepareRotationMatrix(angle);
            //rotationMatrix seems like:
            //  cos(30) -sin(30)
            //  sin(30)  cos(30)

            //This will create 2x3 matrix of zeroes
            DoubleMatrix matrix1 = new DoubleMatrix(2, 3);
            //Lets fill some data here too
            matrix1[0, 0] = 1;
            matrix1[0, 1] = 2;
            matrix1[0, 2] = 3;
            matrix1[1, 0] = 4;
            matrix1[1, 1] = 5;
            matrix1[1, 2] = 6;
            //matrix1 looks like this:
            //         1 2 3
            //         4 5 6

            //Creating a copy of the 1st matrix , this copy will be rotated
            DoubleMatrix matrix2 = new DoubleMatrix((Matrix<double>)matrix1.Clone()); 
            //now rotating it
            matrix2 = rotationMatrix * matrix2;
            //matrix2 looks like this: (same form but rotated 30 deg. c.clockwise
            //       4.10   5.24   6.39
            //      -0.37  -1.20  -2.03

            //Now we'll see that the data of both matrices has same PCA properties
            
            //Creating PCA transform instances for both martices
            PCAtransform transform1 = new PCAtransform(matrix1);
            PCAtransform transform2 = new PCAtransform(matrix2);
            //The result from calculate is a MxM dims eigenVectors matrix
            DoubleMatrix eigenVects1 = transform1.Calculate();
            DoubleMatrix eigenVects2 = transform2.Calculate();

            //It is enough for us to get the absolute 
            //angle of the first vector (the first column)
            double absAngle1 = Math.Atan(eigenVects1[1, 0] / eigenVects1[0, 0]);
            double absAngle2 = Math.Atan(eigenVects2[1, 0] / eigenVects2[0, 0]);

            //Lets see that the relative angle is the same 
            //as the rotation angle from the beginning
            double relativeAngle = absAngle2 - absAngle1; //~=0.52...
            // = -0.00000000000000011102230246251565 ~= 0 
            double anglesDiff = relativeAngle - angle;
            //Not exactly because of precision pervertion, 
            //but this is enought to get convinced

            //Another aspect of similarity is by eigenvalues 
            //(they represen the squares of the scaling factors):
            double[] eigenVals1 = transform1.EigenValues;
            //This array looks like this: 0,2
            double[] eigenVals2 = transform2.EigenValues;
            //This array looks like this: 0,2            
        }

        private static DoubleMatrix PrepareRotationMatrix(double angle)
        {
            DoubleMatrix rotationMatrix = new DoubleMatrix(2);
            rotationMatrix[0, 0] = Math.Cos(angle);
            rotationMatrix[0, 1] = -1 * Math.Sin(angle);
            rotationMatrix[1, 0] = Math.Sin(angle);
            rotationMatrix[1, 1] = Math.Cos(angle);
            return rotationMatrix;
        }
    }
}

PCA 变换也适用于数据分析和有损压缩。 由于这不是我工作的目的,这里将不作解释。 更多关于此类使用的信息可以在互联网上找到。 假设我们只想将绘图或坐标集与给定的源集进行匹配; 使用 PCA 匹配更容易完成。 我们将使用来自前一个示例的数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using LiniarAlgebra;
using System.Drawing;
using System.Reflection;
using PCA;

namespace New_Project
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            //Preparing rotation matrix 30 deg. counterclockwise
            double angle = Math.PI / 180 * 30; //~= 0.52...
            DoubleMatrix rotationMatrix = PrepareRotationMatrix(angle);
            //rotationMatrix seems like:
            //  cos(30) -sin(30)
            //  sin(30)  cos(30)

            //This will create 2x3 matrix of zeroes
            DoubleMatrix matrix1 = new DoubleMatrix(2, 3);
            //Lets fill some data here too
            matrix1[0, 0] = 1;
            matrix1[0, 1] = 2;
            matrix1[0, 2] = 3;
            matrix1[1, 0] = 4;
            matrix1[1, 1] = 5;
            matrix1[1, 2] = 6;
            //matrix1 looks like this:
            //         1 2 3
            //         4 5 6


            //Creating a copy of the 1st matrix , this copy will be rotated
            DoubleMatrix matrix2 = new DoubleMatrix((Matrix<double>)matrix1.Clone());
            //now rotating it
            matrix2 = rotationMatrix * matrix2;
            //matrix2 looks like this: (same form but rotated 30 deg. c.clockwise
            //       4.10   5.24   6.39
            //      -0.37  -1.20  -2.03

            //Preparing and calculating the matching object
            PCAMatching matching = new PCAMatching(matrix1, matrix2);
            matching.Calculate();

            //Getting the transformed data of matrix2 
            //as much as possible closer to matrix1
            DoubleMatrix result = matching.Result;
            //The result is:
            //      1   2   3
            //      4   5   6

            double calculatedAngle = matching.AngleFromSource;
            //calculatedAngle = -0.5235987755982987 the opposite to the original rotation
        }
    }
}

关注点

这个算法在某些方面开阔了我的视野。 在开始编码之前,我没有想到会有一个匹配算法能以如此大的复杂度(O(n))来完成这项工作。 当然,它有自己的缺点,但这是一个良好的开端。

本文及所包含的项目是形状匹配框架的一部分,该框架可以在 http://sites.google.com/site/smfmproject/ 找到。 如您所见,通过一些额外的工作,它甚至可以更好地匹配形状

© . All rights reserved.