机器学习-特性选择(线性相关法/相关因子SRCF算法/最小描述长度MDL算法)

1.特性选择
特性选择:为特定的应用在不失去数据原有价值的基础上选择最小的属性子集,去除不相关和冗余的属性。特性选择用于在建立分类模型后,或者预测模型之前,对原始数据库进行预处理。本节将介绍特性选择的概念,特性选择的三个常用算法:线性相关算法,相关因子SRCF算法,以及最小描述长度MDL算法。
1.1特性选择概念
我们把被预测的那个属性称为目标变量(Target Variable),把用来预测目标变量值的属性称为预测变量(Predictor Variable)。特性选择,就是要考查数据库中的预测变量与目标变量的关联程度,或者说考察每个预测变量对最终预测结果的重要程度。这个重要程度用一个指数(importance)来表示,特性选择算法要计算每个预测变量的importance指数。
特性选择的步骤
特性选择算法包含以下三个步骤:
筛选(screening):除去不重要或者有问题的预测变量和数据,例如预测变量含有过多缺失值,或者预测变量的变化太大或太小而变得无用。
评分(ranking):对所有预测变量根据其重要程度进行评价、打分、排序。
选择(selecting):生成在后续模型中使用的功能子集,例如,仅保留最重要的预测变量,过滤或排除所有其他预测变量。

在评分阶段:也就是特性选择的评分阶段,通常使用一些特征评价函数来对所有的属性相对于目标属性的预测重要性进行评价。常用的特征评估函数可分为五类:相关性、距离、信息增益、一致性和分类错误率。具体的评价方法有:欧式距离、非线性测量、Minkowski距离、信息增益、最小描述长度(MDL)、依赖性度量、相关性度量、一致性度量、分类错误率(正确率)等。其中最小描述长度(简称MDL算法)是一种应用普遍的主要评价方法,下面我们对MDL算法做一些简单介绍。
MDL算法源自最小指数描述长度原则,由Rissane基于数据压缩和通信原理首先提出。其基本思想是:对于一个给定的数据集D(Data Set),为了最大限度地节省数据集的存储空间,我们试图从n个可能的模型(或程序/或算法)中寻找一个模型Mi(1<=i<=n),Mi能最大限度地提取数据集D中所有的规律,并将其进行数据压缩,然后将模型Mi本身连带压缩后的数据Ci一同存储起来,其总存储大小为Si(Size)。由于不同的模型对D的压缩效率不同,一般来说D的压缩率越高模型的复杂度就越高。因此我们从可行的诸多压缩方案中,将最小的S称为D的最小描述长度。最小描述长度的原理就是要选择总描述长度最小的模型Mi.
MDL原理应用于特性选择的方法是,MDL算法将D中的每一个属性都看作是目标属性(如分类属性)的一个简单预测模型。使用其相应的MDL度量对这些单一预测模型进行比较和评分。使用MDL算法,模型选择问题变成了变成了数据通信问题。属性评分使用两部分代码来传送数据。前一部分传送模型,模型参数是与每个预测值相关联的目标概率。后一部分传送的是使用该模型后预测错误的原始数据。公式如下:
Si(MODELi,D)=S(MOSELi)+S(Ci)
其中:Si(MODELi,D)为数据集D上应用第i个属性对目标属性建立简单的预测模型后得到的总大小,S(MOSELi)为应用第i个属性对目标属性建立简单预测模型(MOSELi)的大小,S(Ci)是对i个属性数据应用MODELi后,所有预测错误的原数据大小总和。
最小描述长度的英文表达为Minimun Desription Length(MDL)。这里的Length(长度)是指压缩后的全部数据(程序+剩余数据)占存储空间(存储字节)的总大小,我们也可以用L表示。通常情况下,某个预测属性对目标属性的预测正确率(压缩率)很难达到100%,因此不同的预测属性对目标属性的预测正确率表现为不同的概率,如下图所示:在这里插入图片描述
加粗样式们分别应用n个预测属性X1,X2,…Xn对目标属性Y建立预测模型,其中X1的预测正确率(压缩率)为80%,也就是说X1可以正确地描述Y数据的80%,剩余的20%Y数据(压缩后数据)没能被X1正确地描述,因此其总长度L1为Length(Model(X1,Y))+Length(Y)*20%.其余的X2,…Xn的预测模型的总长度为L2,…,Ln。最小描述长度模型就是要从L1,L2,…Ln中找到最小的长度所对应的分类属性。
接着上面的数据集D,我们取最小的Si(MODELi,D),即Minimum(Si,(MODELi,D)),这样我们应用MDL算法将得到一个最佳预测属性,该属性可以被理解为拥有最多的描述目标属性规律的属性,也就是该属性含有与目标属性相关的最多的信息,因此我们将称为目标属性的一个相对最优待性。同理,我们按照MDL评分的排序(MDL值最小的排在最前面),依次得到不同属性相对于目标属性的特征评分。
线性相关
对于探索与连续的目标变量具有相关性的连续型变量,也就是分析两个连续型变量是否存在相关性,一种比较简单的方法是线性相关算法。直线关系是函数关系中最简单的一种,直线相关分析是判断两变量间是否有直接关系,给出相关方向和相关密切程度的度量,度量的指标为相关系数。应用于双变量正态分布资料,两变量是平等关系。
Pearson相关
相关系数亦称Pearson积差相关系数(coefficient of product-moment correlation),用r表示相关系数,p表示总体相关系数,总体相关系数是未知的,通常用样本相关系数r进行估计。在这里插入图片描述
其中X和Y是两个连续变量,Ixy是X和Y的离均差交叉乘积和,Ixx,Ixy分别是X和Y的离均差平方和。
相关系数没有单位,其值-1<=r<=1.当两变量呈同向变化时,0<r<1,为正相关;两变量程反向变化时,-1<r<0,为负相关;r=0为零相关,表示无直线相关关系;r=1或r=-1时为完全直线相关。直线相关的性质可由下图直观说明。在这里插入图片描述
相关系数的假设检验。相关系数r是样本相关系数,由于存在抽样误差,p=0但r不一定等于0,计算出r值后,接着应做p=0的假设检验,以判断两变量的总体是否有直线相关关系,常用t检验,检验统计量t值的计算公式如下:在这里插入图片描述
其中n是样本量。

Spearman秩相关
Spearman秩相关(rank correlation)是一种非参数统计方法,适用于资料不是双变量正态分布或总体分布未知,数据一端或两端有不确定值的资料或等级资料。用等级相关系数rs来说明两个变量间相关关系的密切程度与相关方向,将两个变量分别排序求秩次,然后对秩次进行计算,分别用P、Q表示X和Y求完秩后的秩值,对于P和Q使用如下公式:在这里插入图片描述
等级相关系数系数r(s)的假设检验。r(s)是总体等级相关系数p(s)的估计值,存在着抽样误差,故计算出r(s)后,需作p(s)=0的假设检验。当n<=50时,可通过r(s)界值表实现p(s)=0的假设检验;当n>50;在这里插入图片描述
线性相关分析要求两个变量服从双变量正态分布,所以进行线性相关之前需要进行双变量正态分布验证,如果数据不服从双变量正态分布,则使用Spearman秩相关方法分析。
相关因子SRCF
对于探索与离散型的目标变量具有相关性的变量,也就是分析至少一个离散型变量的两变量是否存在相关性,方法相对复杂一些,我们这里应用相关因子SRCF算法来处理,
SRCF(Chi-Square Rank Correlation Factorization)是基于卡方-秩和检验的相关因子算法,由两个子算法组成,一个SRCF1,一个是SRCF2。其中SRCF1又分成两个小算法,分别为SRCF1.1和SRCF1.2;SRCF2又分成三个小算法,分别为SRCF2.2、SRCF2.2和SRCF2.3。我们先看一下它的逻辑算法,然后再逐步分解:
算法一:SRCF1
SRCF1是相关因子算法SRCF的一个子算法,是用于探索与离散型的目标变量(分类变量)具有相关性的连续型变量,我们将这些具有相关性的连续型变量成为连续性相关因子,它也是特性选择的一种算法。SRCF1采用的是基于秩和检验的非参数统计方法,同时使用相对熵(Relative Entropy,以下用Entropy代替)、特征记分准则(RFSC)和多组K-W秩和不同组量方法进行相关因子排序。
对于目标变量,当分类取值不同时,我们采用不同的统计方法,加以处理,这里分为两种情况:
1)目标变量分两类时,采用两独立样本的秩和检验,也称Wilcoxon检验(Wilcoxon rank test for two independent samples)。
2)目标变量是大于两分类时,采用多个独立样本的秩和检验,也称K-W检验(Kruskal-Wallis test for indenpendent samples)或H检验。
1.目标变量是两分类(SRCF1.1)
对于x1、x2、…、xm,我们按照Y中值的分类,将某个连续变量xi分为两组(Y=0组和Y=1组),然后对这两组数据的分布进行统计检验。对于两组连续变量数据的差异检验方法,通常采用的是参数统计方法条件(数据正态分布)的情况并不多,所以我们采用非参数统计方法,即两独立样本的秩和检验,该方法虽然统计检验效能较参数统计方法差一些,但通用性好。
SRCF1算法实现如下:
首先是编秩,就是按照数值的大小进行排序。将两组数据由小到大统一编秩,可先将两组数据分别由小到大排序,然后再将两组数据合在一起由小到大统一排序。编秩时有数值相同的数据时,取它们的平均秩次。编秩完成后,将两组秩次(排名)分别相加,求秩和(排名总和)。
然后是确定统计量。无论两组数据的记录是否相等,均选取记录数较小者对应的秩和为统计量。
最后确定P值。P值的确定可采用查表法和正态近似法。
**查表法:**查统计量的界值表。当n1<=10,n2-n1<=10,采用查表法,将检验统计量T值与T临界值相比,若T值在界值范围内,其P值大于相应的概率;否则小于相应的概率。
正态近似法: 组1的记录数n1,组2的记录数为n2,并且n1<n2,如果n1或n2-n1超出界值范围,用正态近似检验:
在这里插入图片描述
若两组有相同的秩次时,需要校正:
在这里插入图片描述
当执行完上述的秩和校验后,就可以做出推论结论了,如果检验的结果为阳性,即p<0.05,则说明组1和组2的数据分布有显著差异。进一步,我们可以推断Xi变量(i=1,…,m)与目标分类变量Y具有相关性,也就是说Xi是Y的相关因子。还可以说,Xi是从m个变量当中选择出来的Y的一个特性。
相关因子的相关度分析如下:对于目标变量是两分类的相关因子相关度的评估,可采用相对熵、特征记分准则方法。
相对熵方法,计算两组连续型数据的相对熵值。对于Y为二分类时,可以直接使用下面公式计算两组直间的相对熵:在这里插入图片描述
其中,P和Q为两个概率密度函数。
相对熵的值越大,Xi与Y的相关度就越高。

特征记分准则方法:计算多组连续型数据的特征记分。对于Y为多分类时,可以直接使用下面公式计算多组之间的特征记分:
在这里插入图片描述
特征记分的值越大,Xi与Y的相关度就越高。
2.目标变量是多分类(SRCF1.2)
对于X1,X2,… ,Xm,我们按照Y中值的分类,将某个连续变量Xi分为四组(Y=0、Y=1、Y=2、Y=3),然后对这四组数据的分布进行统计检验。对于两组以上连续变量数据的差异检验方法,通常采用的参数统计方法为方差分析。方差分析需要首先检验多组数据的正态性,然后还要检验多组数据间的方差齐性。但是,实际应用数据中,数据满足参数统计方法的条件(即各组数据正态分布,同时多组数据方差齐性)的情况并不多。所以我们采用非参数统计方法,即多个独立样本的秩和检验,其目的是推断多个样本的中位数分别代表的总体中位数是否相等。该方法虽然统计检验效能较方差分析方法差一些,但通用性比方差分析方法好。本方法虽然由Kraskal和Wilcoxon秩和检验的基础上扩展而来,所以称为K-W检验(Kruskal-Wallis test for independent samples)。
算法实现如下所示:
1)K-W检验,其编秩和求秩和与Wilcoxon秩和检验的方法都是一样的;
2)统计量的计算,公式为:
在这里插入图片描述
式中Ri为各组的秩和,ni为各组对应的例数,n=求和(ni)。
3)P值的确定分两种情况。
当组数g=3,每组例数ni<=5,可查H界值表得到P值。
当组数g>3,或g=3且最小样本例数ni>5时,H近似地服从自由度为v=g-1的卡方分布,可查卡方界值表得到P值。
若有相同秩次时,应计算下公式校正Hc。
Hc=H/c
4)当执行完上述的秩和检验后,可以做出推断结论。如果检验的结果为阳性,即P<0.05,则说明组1、组2、组3、组4的数据分布不完全相同。进一步我们可以推断Xi变量(i=1,…,m)与目标分类变量Y具有相关性,也就是说,Xi是Y的相关因子。还可以说,Xi是从m个变量当中选择出来的Y的一个特性。
相关因子的相关度分析:对于目标变量是多分类的相关因子相关度的评估,可采用特征记分准则和多组K-W秩和不同组量方法。

fisheye::undistortPoints 函数的源码如下: ```c++ void cv::fisheye::undistortPoints(InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray R, InputArray P) { CV_INSTRUMENT_REGION(); CV_Assert(distorted.isMat() && distorted.depth() == CV_32F && distorted.channels() == 1); CV_Assert((K.empty() || K.type() == CV_64F) && (D.empty() || D.type() == CV_64F) && (R.empty() || R.type() == CV_64F) && (P.empty() || P.type() == CV_64F)); CV_Assert(!K.empty() && K.size() == Size(3, 3) && !D.empty() && D.total() >= 4 && (R.empty() || R.size() == Size(3, 3)) && (P.empty() || P.size() == Size(3, 3))); Mat src = distorted.getMat(), intrinsics = K.getMat(), distCoeffs = D.getMat(), rotation = R.getMat(), newCamMat = P.getMat(); int npoints = src.checkVector(2); CV_Assert(npoints >= 0); undistorted.create(npoints, 1, CV_32FC2); Mat dst = undistorted.getMat(); Mat_<double> A, Ar, I = Mat_<double>::eye(3, 3); intrinsics.convertTo(A, CV_64F); if (!rotation.empty()) rotation.convertTo(Ar, CV_64F); else A.copyTo(Ar); Mat_<double> Dk; distCoeffs.convertTo(Dk, CV_64F); Mat_<double> R_, P_; if (!rotation.empty()) rotation.convertTo(R_, CV_64F); else R_ = I; if (!newCamMat.empty()) newCamMat.convertTo(P_, CV_64F); else { P_.create(3, 3); A.copyTo(P_(Range(0, 3), Range(0, 3))); P_(0, 2) = src.cols * 0.5; P_(1, 2) = src.rows * 0.5; } Mat_<double> mx(1, npoints), my(1, npoints); double* _mx = mx[0], *_my = my[0]; double fx = A(0, 0), fy = A(1, 1); double ifx = 1. / fx, ify = 1. / fy; double cx = A(0, 2), cy = A(1, 2); double k1 = Dk(0, 0), k2 = Dk(1, 0), k3 = Dk(4, 0), k4 = Dk(5, 0), k5 = Dk(6, 0), k6 = Dk(7, 0); const Point2f* srcf = src.ptr<Point2f>(); for (int i = 0; i < npoints; i++) { double x = srcf[i].x, y = srcf[i].y; double x0 = x = (x - cx) * ifx; double y0 = y = (y - cy) * ify; double r2 = x * x + y * y; double theta = atan(sqrt(r2)); double theta2 = theta * theta, theta4 = theta2 * theta2, theta6 = theta4 * theta2, theta8 = theta4 * theta4; double theta_d = theta * (1 + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8); double inv_r = 1 / sqrt(r2); double cdist = x * x + y * y == 0 ? 1 : theta_d * inv_r; double x_d = x * cdist, y_d = y * cdist; if (dst.depth() == CV_32F) { _mx[i] = static_cast<float>(x_d * fx + cx); _my[i] = static_cast<float>(y_d * fy + cy); } else { _mx[i] = x_d * fx + cx; _my[i] = y_d * fy + cy; } } Mat mx_mat(1, npoints, CV_64F, mx.ptr<double>()); Mat my_mat(1, npoints, CV_64F, my.ptr<double>()); Mat XY; merge(mx_mat, my_mat, XY); if (!rotation.empty() || !newCamMat.empty()) cv::transform(XY, XY, P_); else if (D.total() >= 5) { Mat_<double> scaled_XY(XY.size()); cv::undistortPoints(XY, scaled_XY, A, Dk, Mat(), A); XY = scaled_XY; } Mat X = XY.col(0); Mat Y = XY.col(1); double* _X = X.ptr<double>(); double* _Y = Y.ptr<double>(); double* _dst = dst.ptr<double>(); if (!rotation.empty()) { Mat_<double> R = cv::Mat_<double>(3, 3, CV_64F, Ar.data()); for (int i = 0; i < npoints; i++) { double x = _X[i], y = _Y[i], z = sqrt(max(1. - x * x - y * y, 0.)); double Xr = _X[i], Yr = _Y[i], Zr = z; _X[i] = R(0, 0) * Xr + R(0, 1) * Yr + R(0, 2) * Zr; _Y[i] = R(1, 0) * Xr + R(1, 1) * Yr + R(1, 2) * Zr; double Z = R(2, 0) * Xr + R(2, 1) * Yr + R(2, 2) * Zr; _dst[i * 2] = _X[i] * Z; _dst[i * 2 + 1] = _Y[i] * Z; } } else { for (int i = 0; i < npoints; i++) { double x = _X[i], y = _Y[i], z = sqrt(max(1. - x * x - y * y, 0.)); _dst[i * 2] = x * z; _dst[i * 2 + 1] = y * z; } } } ``` 这个函数的作用是将鱼眼相机图像中的畸变点进行矫正,输出矫正后的点坐标。函数的输入参数包括畸变点坐标、相机内参矩阵、畸变系数、旋转矩阵和新的相机内参矩阵。函数的输出参数是矫正后的点坐标。 函数的具体实现过程如下: 1. 通过输入参数获取畸变点坐标、相机内参矩阵、畸变系数、旋转矩阵和新的相机内参矩阵。 2. 对相机内参矩阵和旋转矩阵进行类型转换。 3. 根据相机内参矩阵和畸变系数计算矫正后的点坐标。 4. 如果有旋转矩阵或新的相机内参矩阵,则对矫正后的点坐标进行相应的变换。 5. 输出矫正后的点坐标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值