本文主要介绍了以下几个方面的内容:简单介绍了经典的主成分分析方法,包括其数学推导,算法步骤,和几个实际算例;简单介绍了其它的数据降维方法,譬如局部线性嵌入以及它的简单算例;更近一步,我们介绍了函数型主成分分析方法(FPCA),包括其基本思想、数学推导、算法描述等,最为重要的是,我们将该方法和本领域进行结合,有了一些新的思考。
文章目录
前言
“维数灾难"带来的直接结果就是很多低维空间行之有效的算法在高维空间中变得不可计算,为此,我们需要进行降维。在另一个方面,数据偏平化的情况下,降维有助于我们抓住数据的主要结构,过滤可能的误差带来的影响,使模型更加真实。另外,在某些情况下,降维可用于可视化。数据降维的方法有很多,比如说基于"最小化投影误差”(最大化类内方法)的主成分分析方法(PCA),以及基于保持拓扑结构不变(高维空间中是邻居,到了地位空间中还是邻居)的局部线性嵌入(LLE)等方法。
在多元统计分析中,主成分分析(Principal Components Analysis,PCA)是一种统计分析、简化数据集的方法。它利用正交变换来对一系列可能相关的变量的观测值进行线性变换,从而投影为一系列线性不相关变量的值,这些不相关变量称为主成分(Principal Components)。具体地,主成分可以看做一个线性方程,其包含一系列线性系数来指示投影方向。PCA对原始数据的正则化或预处理敏感(相对缩放)。PCA本质上寻求的是数据点在低秩空间中的一个表示。
高维数据,意味着数据需要多于两个或三个维度来表示,一般很难被解释。一种简化的方法是假设数据嵌在高维空间的一个非线性流形上。如果这个流形维数足够低,那么数据可以在低维空间中被可视化。局部线性嵌入(Locally Linear Embedding,LLE)关注于降维时保持样本局部的线性特征,由于LLE在降维时保持了样本的局部特征,它广泛的用于图像图像识别,高维数据可视化等领域。
有了降维和主成分分析,我们做PDE的就会思考,既然可以对空间中的数据做降维,那么函数作为一组基函数的线性组合,如果将基函数看作一些座标系中的一个个座标轴,是否也可以对函数空间中的"数据"做降维呢?答案是肯定的。函数型(数据)主成分分析(Functional Principal Components analysis)可以视为是传统的主成分分析的一种推广。类比于PCA,它希望能将高维函数空间中的函数放到低维空间中去表示,而使得被表示的数据集损失最小。更通俗地说,就是希望用更少的基函数来表示某个已知基函数的函数空间的一堆函数,新空间的基函数用旧空间的基函数来线性表出。那么,我们就需要定义函数之间的距离,函数空间的内积等等。
主成分分析(PCA)
数据降维简介
在机器学习和统计学领域,降维是指在某些限定条件下,降低随机变量个数,得到一组"不相关"主变量的过程。
降维可进一步细分为变量选择和特征提取两大方法。除了考虑"维数灾难"的问题,降维还有一些本质的原因。目前大部分降维算法处理向量表达的数据,也有一些降维算法处理高阶张量表达的数据。之所以使用降维后的数据表示是因为在原始的高维空间中,包含有冗余信息以及噪音信息,在实际应用例如图像识别中造成了误差,降低了准确率,通过降维,我们希望减少冗余信息所造成的误差,提高识别(或其他应用)的精度,又或者希望通过降维算法来寻找数据内部的本质结构特征。目前比较流行的降维算法有主成分分析、线性判别分析、局部线性嵌入和拉普拉斯特征映射等等。
PCA算法的原理解释
所谓的主成分分析,不过是在高维的空间中寻找一个低维的正交座标系,比如说在三维空间中寻找一个二维的直角座标系。那么这个二维的直角座标系就会构成一个平面,将三维空间中的各个点在这个二维平面上做投影,就得到了各个点在二维空间中的一个表示,由此数据点就从三维降成了二维。
这个过程的关键在于,我们如何选取这个低维的座标系,即座标系原点在哪?各个轴朝哪个方向?一个原则就是使得各个点到到这个平面的距离平方和达到最小。由此,通过简单地数学推导,就能得到原点的表达公式和座标系的各个基向量的表达公式。
PCA算法的数学推导
我们假设输入为p维的N个对象,表示如下图所示的一个矩阵:
通过PCA降维,将其降为d维的N个对象,假设为,同前,每列表示一个对象,每行表示一个特征:
我们要将所有点投影到新的座标系中去,无非是寻找新座标系的座标原点和各个座标轴。
我们假设的每一列为新的座标系中单位正交的座标轴表示,为新座标系的原点(相对于原座标系)。
那么,我们要做的就是找到一个合适的和,使其极小化所有点到新的座标平面的距离平方和。
容易知道,每一个点到新座标系的距离平方为(其中表示的是位置参数):
对其进行化简,可得:
进而有,
让所有点到投影点距离平方和最小,即求解约束优化问题:
我们借助拉格朗日乘子法来求解此约束优化问题:
由两个偏导为0,可以得到:
因为半正定矩阵的特征值非负,所以,原最小化损失函数可进行转化:
我们利用矩阵的性质,要想最小化距离平方和,有:
令为的矩阵。有性质:
则有,
由此我们可以看到,要得到极小值,我们只要计算矩阵的前d个最大特征值,是投影后样本具有最小损失的特点。那么此时的就是矩阵前d个最大特征值对应的特征向量。
不难知道,对于的特征分解:
这里的U就是前天提到的奇异值分解的U。同理,虽然我们这里没有用到,但其实奇异值分解的正式的特征值分解的特征矩阵。
为了比较特征分解和进行奇异值分解的消耗,写了一段小程序,并使用matlab探查功能进行比较如下:
这个比较事实上没有太大的意义。所用的代码如附录。
PCA算法简单描述
假设是一个m*n矩阵,表示n个对象的m个特征表示数据,即每一列表示一个对象,每一行表示一个特征。我们希望将特征降为d维,d远小于m。输出结果为,一个d*n的矩阵。
-
记,计算每个对象点的平均值。
-
对做奇异值分解:。
-
则即为新座标系的原点,的前d列即为去中心化后的新的座标系,不妨记为。那么,所有点在新座标系下的表示为:。同样地,要将新的投影点还原到原座标系中,可以写为:。
下面以基于矩阵的视角写出PCA算法的算法流程,输入为矩阵p*N矩阵X,输出为d*N矩阵Y。矩阵的每一列都表示一个对象,每一行都表示对象的一个特征表示。
PCA算例一
假设小明和小红有身高和体重两个特征(实际操作数据要进行预处理,这里不做),如下表:
那么此时,现在试图通过PCA降维,将身高和体重合并为一个特征。走一遍上面的过程,可得:
其中,
那么,有
那就是说,最后数据可降维为:
这个问题MATLAB计算的小程序在附录。
PCA算例二
这是一个对于人脸数据进行降维的例子,人脸数据是我从网上找的。MATLAB源代码见附录。
选取了2000x1680的数据集进行了测试,选取降维后维数为20,其降维前后的图像(降维后的图像指的是投影点还原到原空间对应的座标值重构出的图像)如下所示(选取第一个点为代表):
我们使用别人制作的降维工具箱"drtoolbox"重新进行计算并和我的程序结果进行比较。工具箱的使用代码见附录。结果如下:
当然,我们也可以比较我的程序和工具箱程序的误差的大小,比如误差。都很简单,暂且不提。
其他数据降维方法
其他的数据降维方法还有很多,比如说线性判别分析,拉普拉斯特征映射等等,我这里就简单介绍一下局部线性嵌入。
当数据具备某些非线性结构,如流形结构时,我们希望降维后的数据仍然保持这些结构。那么就提出了LLE降维算法。LLE(Locally linear embedding):在数据降维后仍然保留原始高维数据的拓扑结构,这种拓扑结构表现为数据点的局部邻接关系。
此算法我们首先要寻求每个数据点的k个最近邻,然后将当前数据点用k个最近邻线性表出,那么就有相对的权重系数。
我们希望数据在降维后数据点之间依然能保持这种线性表出的关系,并且在满足另外一些约束条件的前提下,我们很容易求得降维后的数据。
具体原理和公式网络上有很多人整理得很好,这里不提了。
下面是LLE算法的算法流程,输入为矩阵p*N矩阵X,输出为d*N矩阵Y。矩阵的每一列都表示一个对象,每一行都表示对象的一个特征表示。
源代码见附录。
选取了409×698的图像数据集进行了测试,选取降维后维数为2,选取最近邻个数,实验后的部分结果如下:
我们使用别人制作的降维工具箱"drtoolbox"重新进行计算并和我的程序结果进行比较。工具箱的使用代码见附录。
降维后的部分数据截图如下:
为了比较性能,找个一个别人写的LEE算法,算是网络版本,代码在附录。"网络版"的数据结果和我的版本的结果是一样的。我们开启Matlab的探查功能来比较耗时,结果如图。
函数型数据主成分分析
Idea的萌生
前一段时间我在做一个流体力学上的东西(虽然现在已经不做这个方向了),其中比较关键的步骤就是需要用一个带时间变量的多项式公式,来刻画一个物理过程。这个多项式的各个项前面的系数是未知的,由物理规律来决定。我们希望从一些物理实验数据中来通过一些机器学习的手段来学到多项式各个项前面的系数。
这个问题本质的困难在于,我们不知道那些函数项(基函数)是我们需要的。事实上,只要知道了多项式包含哪些项,是可以通过一些物理原理求得前面的系数的。一个基本的想法就是选足够多的基函数,使得函数空间足够大而包含真值。但是,函数空间太大会带来使用物理原理求系数时的计算困难增大。所以,我们希望能找一个原来大的函数空间的一个子空间,使得用这个子空间,就能够基本刻画原来的物理过程。再用物理原理来求得以子空间基函数为各个项的多项式系数。
仔细一想,这不正是函数空间的PCA吗?如果把每一个函数看做一个数据点,把各个基函数看做是组成座标系的座标轴,那么"函数点"在高维函数空间中的表示,就可以通过类似于主成分分析的技巧,变成在低维函数空间中的表示。只要有了能表示刻画整个物理过程的各个数据点的低维空间,那么刻画物理过程的多项式的项(即低维空间的基函数)也就明确了,剩下的事情也就自然而然了。
FPCA简介和理论推导
函数型主成分分析(FPCA,Functional Principal Components Analysis)是传统的PCA的一种推广。考虑我们已经从数据中得到拟合曲线,所谓的第一主成分,就是我们希望能找到一个模为1的函数,使得在上的投影(内积)的方差达到最大,方差最大其实也就体现整体到的距离达到最小。一般就叫做权重函数(可以理解为"座标轴"单位长度量)。
我们管各个函数到上的投影叫做观测曲线的主成分得分:
故而,求解第一个主成分就变成了求解一个优化问题:
求解这个优化问题,我们就得到了第一主成分。
第主成分无非就是在满足和前面个主成分权重函数垂直的基础上,求解上述优化问题而已,即求解
这个优化问题的解可以表述如下。记协方差函数:
那么权重函数满足特征方程:
定义积分变换:
这里的称为协方差算子,它将函数变成一个函数。那么,我们有:
我们也类比PCA,使用特征值的累积贡献率来衡量主成分所占比例:
这里之所以对只累计到是因为协方差算子的秩为样本数量减一个,则非零特征根的个数最多为个。
由上述已知,我们求解主成分最后归结为求解一个特征值问题。
求解这个问题,目前比较流行的有三种方法:
-
对函数进行SVD离散化
-
对函数进行基函数展开
-
运用一般性的数值积分方法
我们最后需要的是特征函数,为了避免插值而带来更大的误差,我选用对基函数进行展开的方法。下面简单介绍一个对函数进行基函数展开的基本思路。
我们的样本基函数可以通过基函数展开,如下:
我们记
那么样本函数就可以写为等价的矩阵形式。那么协方差函数就可以写为(假设已经标准化):
定义K阶对称矩阵
当选择正交基的时候,比如说正交傅里叶基,这就是一个单位矩阵。关于这个基如何选取,我们后面还会详谈。
同样地,将特征函数进行展开:
将其代入
就可以得到():
进一步能得到,由特征向量正交和单位长度的约束要求,有
对做cholesky分解,可得。
定义,那么上述问题就变成了对称矩阵的代数特征值问题:
据此可以求得,进而求得,最后求得特征函数。
常用的基函数有傅里叶基函数和B样条基函数,傅里叶基函数适用于周期性函数数据,B样条基函数适用于非周期函数数据,当然,也可以用多项式基函数。
B样条基函数的递归定义为:
附录中有一段简单的以多项式为基的MATLAB代码。
FPCA和PCA的区别和联系
如上所述,可以看出,如果所选的基函数是正交的,本质上和PCA的以拟合系数为座标点的函数空间PCA推广是实际上是一样的。若基函数不是正交的,无非就是在此基础上对要求特征值的矩阵得多乘一个,再求特征向量,以及进行意义下对特征向量进行单位化而已(不单位化也没事,只不过权重函数不再是模长为1的而已,意义下的单位话也就意味着让新的基函数模长为1)。这个也非常容易理解,因为在从函数的元(primal)表示左乘一个质量矩阵就到了到它的对偶(dual)表示,而在基函数不正交的情况下,我们应该在对偶空间中再进行它的主成分分析降维,即各个函数的向量表示应该为这个函数和各个基函数的内积。同理,在对偶框架下得到的新的基函数的向量表示也是在对偶空间下的,应该左乘一个质量矩阵才能回到元空间中去。
基于FPCA的模型约化
Onsager原理简介
Onsager基本原理是基于物理规律的一个原理,利用它不难得到,如果刻画物理过程的模型方程有哪些项知道了,也就是基函数知道了,那么我们可以通过这个原理求得各个项前面的系数。
定义势能函数(自由能): 定义能量耗散函数:
那么系统随时间演化由最小化以下函数得到:
最小化,可以得到:
这就是我们要求解的ODE系统。
简单例子:斜板液滴滑动
问题描述
考虑一个液滴在斜板上从静止开始下滑,如图。
从正面或者侧面拍摄到的图案大概如图。
我们现在想要刻画这个液滴的状态,即在每一时刻液滴的俯视形状以及侧视高度。
我们可以用一个方程来描述这个过程:
其中为平行平板沿着液滴运动的方向,为平行平板垂直于液滴运动的方向,为时刻,为垂直于平板距离平板的一个高度。这里面的是两个函数,分别刻画了俯视的形状和侧视的形状。事实上,取,可以得到描述了俯视图(垂直于板)的形状(一半),取,得到,体现的是侧视图。再者,若给定了值,高度随着是呈现出抛物的变化。因此,这个公式看起来不无道理。
接下来,我们对做一个简单的假定:
容易想到,这里的表示的是液滴的前后端点(采用欧拉座标系),因为在两端点处的值为零。
原理的应用
我们希望能通过上面提到的Onsager原理来确定这里的系数。
固定时刻的液滴体积:
因为体积是守恒量,所以问题的自由度个数就变成了5。 势能函数定义为:
这里的表示液滴的表面张力,表示密度,是平衡态下的接触角大小,是重力加速度,是前面提到的斜面角。我也不知道势能函数为什么能写成这样,需要一些物理的分析。
可以把的表达式代入到这个势能函数的表达式中。我们还需要知道能量耗散函数。由滑润近似,能量耗散函数可以写成关于速度的变量:
这里的表示两个方向上的速度,表示流体的粘性。但是我们想要的耗散函数是关于
的,所以要想办法替换掉速度。 由体积守恒,我们有:
将的表达式代入上式,可得:
这个约束满足的一个充分条件是:
一个如下所示的速度场能够满足这样的条件:
其中,的表达为:
那么,我们得到的能量耗散函数其实是:
我们把看成常量,由于是的线性组合,意味着也是,那么就是的二次函数,不妨记为:
这里的是的函数。
这下有了势能函数和能量耗散函数,我们可以得到关于的发展方程为:
求解之,可得。
算法步骤
总结一下上述的计算过程,就是:
-
能量耗散函数:
其中,
-
由此,我们计算出表达式,并提取前面的线性组合的系数:
-
势能函数:
-
求解ODE方程组(数值解),得出。
数值实验
所用的参数如下:
下面有一些数值结果如图。
所用的程序比较冗长,就不往本文后面贴了。
FPCA在液滴下滑问题的应用
这只是我的一个想法,目前有很多问题都没有明确。由于时间关系,我这里也不会展开细述这一部分内容。基本的做法可以分成以下几个步骤:
-
收集数据:除了网络上搜到的三个物理实验视频和论文中的一些截图之外,我没有找到更多的数据,数据严重不足。和文章作者联系,也未要到数据。
-
图像处理:对收集到的视频,按帧提取图像,对每个图像进行去噪,二值化,归一化,提取边缘的座标位置。
-
FPCA降维:对于提取到的数据,选用适当的基函数,做小二乘意义下的拟合,得到拟合系数。这一组组拟合系数,就是我们做FPCA降维的数据。做FPCA,得到子函数空间。
-
Onsager原理确定系数:在子函数空间中,使用Onsager基本原理,得到液滴下滑物理过程的表达式系数。
数据不够怎么办?有两个基本的想法。一个是利用同一组参数(如斜板角度)下不同时刻的数据(一个视频),来降维生成这组参数下的随时间变化的物理过程表达过程。另一个是查找更多的数据,哪怕利用上别人文章中的图片,堆砌所有的数据,寻求刻画这个物理过程的"真"表达,找到物理上的"真"规律。
收集到的原始数据如图所示。
处理后的数据如图所示。
其中用到的一些代码见附录。根据这个问题的特殊性,有一个新的想法就是Robust
PCA和流行学习能不能推广到FPCA上?这也是一个有趣的问题。其实我们还是不太清楚这个问题中数据的分布。
参考文献
[1] Rio E , Daerr A , Andreotti B , et al. Boundary Conditions in the
Vicinity of a Dynamic Contact Line: Experimental Investigation of
Viscous Drops Sliding Down an Inclined Plane[J]. Physical Review
Letters, 2005, 94(2):024503.
[2] Rudy S H , Brunton S L , Proctor J L , et al. Data-driven
discovery of partial differential equations[J]. Science Advances,
2017, 3(4):e1602614.
[3] Brunton S L , Proctor J L , Kutz J N . Discovering governing
equations from data by sparse identification of nonlinear dynamical
systems[J]. Proceedings of the National Academy of Sciences,
2016:201517384.
[4] Xu X , Di Y , Doi M . Variational method for liquids moving on a
substrate[J]. Physics of Fluids, 2016, 28(8):087101.
[5] 胡宇. 函数型数据分析方法研究及其应用[D]. 东北师范大学, 2011.
[6] 陈宜治. 函数型数据分析若干方法及应用[D]. 浙江工商大学, 2011.
[7] 沈关友. 基于函数型数据主成分分析的银行股票数据预测[D].
[8] 吴刚, 胡新荣. 基于函数型主成分分析的织物状态研究[J].
科技创业月刊, 2017(12).
[9] 李敏. 基于函数型主成分分析方法的用水量数据分析[J].
合肥学院学报(综合版), 2014(4):21-25.
ear dynamical
systems[J]. Proceedings of the National Academy of Sciences,
2016:201517384.
[4] Xu X , Di Y , Doi M . Variational method for liquids moving on a
substrate[J]. Physics of Fluids, 2016, 28(8):087101.
[5] 胡宇. 函数型数据分析方法研究及其应用[D]. 东北师范大学, 2011.
[6] 陈宜治. 函数型数据分析若干方法及应用[D]. 浙江工商大学, 2011.
[7] 沈关友. 基于函数型数据主成分分析的银行股票数据预测[D].
[8] 吴刚, 胡新荣. 基于函数型主成分分析的织物状态研究[J].
科技创业月刊, 2017(12).
[9] 李敏. 基于函数型主成分分析方法的用水量数据分析[J].
合肥学院学报(综合版), 2014(4):21-25.
附录
{a}
clc
clear
p = 10000;
N = 10;
d = 10;
AR = randn(p,N);
x0 = mean(AR,2); % 计算样本均值
AR_shift = AR - repmat(x0,1,N); % 中心平移每个训练样本
Sigma = AR_shift*AR_shift';
[W,D] = eigs(Sigma,d); % 前d个特征向量作为wi
Lambda = diag(D); % 提取特征值
%%
[U,S,V] = svd(AR_shift);
{b}
\begin{lstlisting}%[language=MATLAB,frame=shadowbox]
clc
clear
X = [178 165; 70 65];
x0 = sum(X,2)/2;
X_x0 = X - [x0 x0];
[U,S,V] = svd(X_x0);
W = U(:,1);
Y = W'*(X_x0);
rebuild_X = [x0 x0]+W*Y;
{c}
\begin{lstlisting}%[language=MATLAB,frame=shadowbox]
%%
%编写程序,实现PCA算法
%对图像进行降维实验,并显示降维重建后的图像
%运行已有程序,和自己的对比
%实验报告(伪代码(或流程图)、源代码、实验结果及分析)
%%
%编写程序,实现PCA和LEE算法
%对图像进行降维实验,并显示降维重建后的图像
%运行已有程序,和自己的对比
%实验报告(伪代码(或流程图)、源代码、实验结果及分析)
clc
clear
addpath(genpath(pwd));%将子孙文件添加到工作目录
load AR %导入数据
d = 20;
%%
AR = double(AR);%双进度化
[p ,N] = size(AR);%特征维度和对象数目
% for i = 1:N
% image = AR(:,i);
% image = reshape(image,50,40);
% imshow(mat2gray(image));%对原矩阵归一化
% end
x0 = mean(AR,2);%计算样本均值
AR_shift = AR - repmat(x0,1,N);%中心平移每个训练样本
%计算协方差矩阵的(n-1)倍,不用内置函数cov,提高代码的重用率和运行速度
Sigma = AR_shift*AR_shift';
%Sigma = cov(AR')*(N-1);
[W,D] = eigs(Sigma,d);%前d个特征向量作为wi
Lambda = diag(D);%提取特征值
%%
close all;
k = 1;
Y = W'*AR_shift(:,k);%第k个图像的输出表示
X_rebuid = W*Y + x0;%第k个图像的重建还原
image = AR(:,k);
image = reshape(image,50,40);
imshow(mat2gray(image));%对原矩阵归一化
figure;
image_re = X_rebuid;
image_re = reshape(image_re,50,40);
imshow(mat2gray(image_re));%对原矩阵归一化
{d}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%%
%编写程序,实现PCA和LLE算法
%对图像进行降维实验,并显示降维重建后的图像
%运行已有程序,和自己的对比
%实验报告(伪代码(或流程图)、源代码、实验结果及分析)
%%
%编写程序,实现PCA和LEE算法
%对图像进行降维实验,并显示降维重建后的图像
%运行已有程序,和自己的对比
%实验报告(伪代码(或流程图)、源代码、实验结果及分析)
clc
clear
addpath(genpath(pwd));%将子孙文件添加到工作目录
load AR %导入数据
d = 20;
%%
AR = double(AR);%双进度化
[p ,N] = size(AR);%特征维度和对象数目
% for i = 1:N
% image = AR(:,i);
% image = reshape(image,50,40);
% imshow(mat2gray(image));%对原矩阵归一化
% end
x0 = mean(AR,2);%计算样本均值
AR_shift = AR - repmat(x0,1,N);%中心平移每个训练样本
%计算协方差矩阵的(n-1)倍,不用内置函数cov,提高代码的重用率和运行速度
Sigma = AR_shift*AR_shift';
%Sigma = cov(AR')*(N-1);
[W,D] = eigs(Sigma,d);%前d个特征向量作为wi
Lambda = diag(D);%提取特征值
%%
close all;
k = 1;
Y = W'*AR_shift(:,k);%第k个图像的输出表示
X_rebuid = W*Y + x0;%第k个图像的重建还原
image = AR(:,k);
image = reshape(image,50,40);
imshow(mat2gray(image));%对原矩阵归一化
figure;
image_re = X_rebuid;
image_re = reshape(image_re,50,40);
imshow(mat2gray(image_re));%对原矩阵归一化
{e}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%%
%编写程序,实现PCA和LEE算法
%对图像进行降维实验,并显示降维重建后的图像
%运行已有程序,和自己的对比
%实验报告(伪代码(或流程图)、源代码、实验结果及分析)
%% 预处理和数据输入
clc
clear
addpath(genpath(pwd));%将子孙文件添加到工作目录
load face_images; %导入数据
data = images;
%data = data(:,1:50);
%% 初始化参数
d = 2;
len = 64;
wid = 64;
k = 12;
%%
[p ,N] = size(data);%特征维度和对象数目
[IDX,~] = knnsearch(data',data','K',k+1);
IDX = IDX(:,2:end);
W = zeros(N);
for i = 1:N
xk = data(:,i);
index = IDX(i,:);
Qk_temp = repmat(xk,1,k) - data(:,index);
Qk = Qk_temp'*Qk_temp;
wk_temp = Qk\ones(k,1);
wk = wk_temp/sum(wk_temp);
W(i,index) = wk;
end
W = W';
I = eye(N);
M = (I-W)*(I-W)';
[P,L] = eigs(M,d+1,0);
P = P(:,2:end);
Y = (P*sqrt(N))';
{f}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%% 使用工具箱进行进行降维来和我的实验结果进行比较
clc
clear
close all
method = 'LLE';%可选LLE或者PCA
addpath(genpath(pwd));
% 产生测试数据
%[X, labels] = generate_data('helix', 2000);
if strcmp(method,'PCA')
load AR %导入数据
[p,N] = size(AR);
X = double(AR);%导入数据
else
load face_images %导入数据
[p,N] = size(images);
X = double(images);%导入数据
end
% 估计本质维数
%no_dims = round(intrinsic_dim(X, 'MLE'));
%disp(['MLE estimate of intrinsic dimensionality: ' num2str(no_dims)]);
d = 2;
k = 12;
% PCA降维或LLE降维
[mappedX, mapping] = compute_mapping(X', method,d);
Y = mappedX';
if strcmp(method,'PCA')
x0 = (mapping.mean)';
W = (mapping.M);
AR_shift = X - repmat(x0,1,N);
%%
close all;
k = 1;
y = Y(:,k);
X_rebuid = W*y + x0;%第k个图像的重建还原
image = AR(:,k);
image = reshape(image,50,40);
imshow(mat2gray(image));%对原矩阵归一化
figure;
image_re = X_rebuid;
image_re = reshape(image_re,50,40);
imshow(mat2gray(image_re));%对原矩阵归一化
end
{g}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
% LLE ALGORITHM (using K nearest neighbors)
% [Y] = lle(X,K,dmax)
% X :data as D x N matrix (D = dimensionality, N = #points)
% K :number of neighbors
% dmax :max embedding dimensionality
% Y :embedding as dmax x N matrix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%function [Y] = lle(X,K,d)
addpath(genpath(pwd));%将子孙文件添加到工作目录
load face_images; %导入数据
data = images;
X = data;
K = 12;
d = 2;
%%
[D,N] = size(X);
fprintf(1,'LLE running on %d points in %d dimensions\n',N,D);
%% Step1: compute pairwise distances & find neighbour
fprintf(1,'-->Finding %d nearest neighbours.\n',K);
X2 = sum(X.^2,1);
distance = repmat(X2,N,1)+repmat(X2',1,N)-2*X'*X;
[sorted,index] = sort(distance);
neighborhood = index(2:(1+K),:);
% Step2: solve for recinstruction weights
fprintf(1,'-->Solving for reconstruction weights.\n');
if(K>D)
fprintf(1,' [note: K>D; regularization will be used]\n');
tol=1e-3; % regularlizer in case constrained fits are ill conditioned
else
tol=0;
end
W = zeros(K,N);
for ii=1:N
z = X(:,neighborhood(:,ii))-repmat(X(:,ii),1,K); % shift ith pt to origin
C = z'*z; % local covariance
C = C + eye(K,K)*tol*trace(C); % regularlization (K>D)
W(:,ii) = C\ones(K,1); % solve Cw=1
W(:,ii) = W(:,ii)/sum(W(:,ii)); % enforce sum(w)=1
end;
% Step 3: compute embedding from eigenvects of cost matrix M=(I-W)'(I-W)
fprintf(1,'-->Computing embedding.\n');
% M=eye(N,N); % use a sparse matrix with storage for 4KN nonzero elements
M = sparse(1:N,1:N,ones(1,N),N,N,4*K*N);
for ii=1:N
w = W(:,ii);
jj = neighborhood(:,ii);
M(ii,jj) = M(ii,jj) - w';
M(jj,ii) = M(jj,ii) - w;
M(jj,jj) = M(jj,jj) + w*w';
end;
% calculation of embedding
options.disp = 0;
options.isreal = 1;
options.issym = 1;
[Y,eigenvals] = eigs(M,d+1,0,options);
Y = Y(:,2:d+1)'*sqrt(N); % bottom evect is [1,1,1,1...] with eval 0
fprintf(1,'Done.\n');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% other possible regularizers for K>D
% C = C + tol*diag(diag(C)); % regularlization
% C = C + eye(K,K)*tol*trace(C)*K; % regularlization
{h}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
clc
clear
close all
format short
digits(5)
%% 设定维数
p = 8;
d = 2;
%% 读入数据,保存
D = dir('../data/*.csv');
D = struct2cell(D);%结构体不好调用,转成元胞数组来使用
csvs_name = D(1,:);
N = 0;%这个表示数据的个数
%csvs_name = csvs_name(5:6);
for csv_name = csvs_name %cpicName = 'a001.bmp'
N = N+1;
csvName = csv_name{1};
Data{N} = load(['../data/' csvName]);
end
%clear csv_name csvN csvName csvs_name D
%% 定义原空间基,生成模型函数,由模型函数通过拟合得到点的座标表示
%p = 15;%原空间维数
%%根据p自动生成模型函数
eval_poly = 'a(1)';
for i = 2:p
eval_poly = [eval_poly '+a(' num2str(i) ').*x.^' num2str(i-1)];
end
eval_poly = ['modelfun = @(a,x) x.^(0.5).*(1-x).^(0.5).*(' eval_poly ');'];
eval(eval_poly);
%modelfun = @(a,x) x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*sin(x)+a(3).*cos(x)+a(4).*1./x+a(5).*x+a(6).*x.^2);
% modelfun = @(a,x)(x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*x+a(3).*x.^2+...
% a(4).*x.^3))%+a(5).*x.^4+a(6)*x.^5))+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
% modelfun = @(a,x)((a(1)+a(2).*x.^2+a(3).*x.^2+...
% a(4).*x.^3+a(5).*x.^4+a(6)*x.^5+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
%%做一波拟合,求出系数,进行拟合,拟合结果为A
%%A中存的是数据点的座标表示
for k = 1:N
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%y = y./(x.*(1-x));%%%%%%%%如果将x(1-x)项挪到左边,拟合会出问题
a0 = ones(1,p);
a = nlinfit(x,y,modelfun,a0);
A(:,k) = a';
end
%clearvars -except A modelfun x y
%% 开始奇异值分解降维,得到新空间的原点和座标轴,座标表示
%%由奇异值分解做主成分分析,A的每一列为原空间下的系数,U的每一列为主成分
[p,N] = size(A);
%d = 5;%新空间维数
x0 = mean(A,2);%计算样本均值
A_shift = A - repmat(x0,1,N);%中心平移每个训练样本,A_shift为原数据点的平移表示
%%%%对于A_shift的补充处理
syms x;
base_vec_T = x.^(0.5).*(1-x).^(0.5).*x.^[0:p-1];
base_vec = conj((base_vec_T))';
W = int(base_vec*base_vec_T,[0,1]);
L_prime = chol(W);
L_prime_A_shift = L_prime*A_shift;
%%%%
[U,S,V] = svd(L_prime_A_shift);
B = L_prime\U;
if size(S,2) == 1
S_diag = S(1);
else
S_diag = diag(S);
end
R = cumsum(S_diag)./sum(S_diag);
Coord_new = B(:,1:d);
%% 新空间的座标轴和原点的函数表示
%%生成新的空间中的基函数,找到d个新空间基函数及原点座标
%%Coord_new x0中存的是新座标系,fi存的是新的函数空间的原点和座标轴
for k = 1:d;%取出第k个基函数
syms x;
c = B(:,k);
exp = modelfun(c,x);
exp = simplify(exp);%第k个基函数的表达式
f{k} = exp;
digits(2);
latex(vpa(exp,2));%写成latex表达式黏贴到解释器中
end
f0 = modelfun(x0,x);
f0 = simplify(f0);
latex(vpa(f0,2));
% for i = 1:d
% f_fun{i} = matlabFunction(f{i});
% end
% f0_fun = matlabFunction(f0);
%% 求原座标系中的投影后在原空间中的位置
%A_new_coord = Coord_new'*A_shift;%A_new_coord表示原数据点在新空间中的表示
syms x;
for k = 1:N
a = A_shift(:,k);
pk_f = modelfun(a,x);
for j = 1:d
A_new_coord(j,k) = int(pk_f.*f{j},0,1);
end
end
%%函数运算
for k = 1:N
A_shadow_f = f0;
for i = 1:d
A_shadow_f = A_shadow_f+f{i}*A_new_coord(i,k);
end
A_shadow_f = simplify(A_shadow_f);
A_shadow_fs{k} = A_shadow_f;
A_shadow_fs_fun{k} = matlabFunction(A_shadow_f);
end
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%座标运算,可以注释掉
% A_shadow_coord = Coord_new*A_new_coord+repmat(x0,1,N);%A_shadow_coord表示投影座标点在原座标系下的表示
% syms x;
% for k = 1:N
% a = A_shadow_coord(:,k);
% A_shadow_coord_f = modelfun(a,x);
% A_shadow_coord_fs{k} = simplify(A_shadow_coord_f);
% end
%
% %%不考虑舍入误差的情况下,可以证明座标运算和函数运算的得到的函数表达式是一样的,验证代码如下
% k=5;
% diff = A_shadow_coord_fs{k}-A_shadow_fs{k}
% diff = simplify(diff)
% digits(2);
% latex(vpa(diff,2))
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 画图和求误差
Errors = [];
NN = 1000;
h = 1/NN;
xx = linspace(0,1,NN+1);
close all;
for k = 1:N
%%原数据点
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%%拟合曲线
a = A(:,k);
data_fit_f = @(x) modelfun(a,x);
%%投影函数
A_shadow_f_fun = A_shadow_fs_fun{k};
%%原点函数
f0_fun = matlabFunction(f0);
%%开始画图
figure(k);
scatter(x,y,'.','MarkerEdgeColor','b',...
'MarkerFaceColor','c',...
'LineWidth',0.5);
hold on;
y_fit = data_fit_f(xx);
y_shadow = A_shadow_f_fun(xx);
y_f0 = f0_fun(xx);
plot(xx,y_fit,'g');
plot(xx,y_shadow,'black');
plot(xx,y_f0,'r');
legend('数据','拟合','投影','原点');
%%求拟合曲线和投影函数之间的L2误差
%Errors(end+1) = norm((y_fit-y_shadow),2);
Errors(end+1) = sum(abs(y_fit-y_shadow)*h);
end
Errors_mean = mean(Errors)
%% test
% close all;
% plot(xx,xx);
% hold on;
% plot(xx,xx.^9)
{i}
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%图片提取数据与清洗
function I_fresh = denoise( I )
% 去除噪声,填充空洞
[L,num] = bwlabel(~I,8);
stats = regionprops(L);
stats_cell = struct2cell(stats);
[~,maxind] = max([stats_cell{1,:}]);
Imp = ismember(L, maxind);
I_fresh = imfill(Imp,'holes');
I_fresh = ~I_fresh;
end
function [ coord,L ] = edge_extract( I )
% 提取边缘
[B,L] = bwboundaries(I,'noholes');
%imshow(I)
% figure;
% imshow(L)
coord = B{1};
L = bwperim(I);
end
function [Ia,Ib] = image_process( pic_name,plotflag)
% 图像分割,二值化处理
%pic_name = '1\65.png';
A = imread(pic_name);%读取到一张图片
[low_num,col_num,~] = size(A);
Aa = imcrop(A,[1,1,270-1,low_num-1]);%分割点定在了270
Ab = imcrop(A,[270,1,col_num-270,low_num-1]);
%thresh = graythresh(A);%自动确定二值化阈值
%L = bwperim(A);imshow(L)
Ia = im2bw(Aa,58/255); %对图像二值化处理
Ib = im2bw(Ab,58/255); %对图像二值化处理
if plotflag == 1
%if 0
figure(100);
subplot(2,2,1);imshow(Aa);
subplot(2,2,2);imshow(Ab);
subplot(2,2,3);imshow(Ia);
subplot(2,2,4);imshow(Ib);
end
end
function [ B ] = myrotate( A,O,angle )
%定义我的旋转函数,表示A当中的点,绕O点,逆时针旋转angle角度后的点
x0 = O(1);y0 = O(2);
x1s = A(:,1);
y1s = A(:,2);
x1new = (x1s - x0)*cos(angle) - (y1s - y0)*sin(angle) + x0 ;
y1new = (x1s - x0)*sin(angle) + (y1s - y0)*cos(angle) + y0 ;
B = [x1new y1new];
% myrotate([1 1],[2 1],-pi/4)
end
function [ Coordinates_normalized ] = normalize( Coordinates )
%此函数对于输入的二维座标,按照x轴向映射的【0,1】区间
% 对输入的座标点归一化
x = Coordinates(:,1);
%y = Coordinates(:,2);
xmax = max(x);
%xmin = min(x);%这个应该是等于0的
Coordinates_normalized = Coordinates./xmax;
end
function pic_extract(video_name,freq)
%视频中提取图像函数,video_name表示视频名称,freq表示每几帧提取一次
%video_name = '1';
VideoAd = VideoReader([video_name '.mp4']);%输入视频位置
numFrames = VideoAd.NumberOfFrames;% 帧的总数
videoF = VideoAd.FrameRate;%视频采集速率,每秒走几帧
videoD = VideoAd.Duration; %时间
%numname=3;%图片名称长度
%nz = strcat('%0',num2str(numname),'d');
T = 1*freq;%提取帧数间隔,这里设定每1秒提取一一帧
%T=1;%提取帧数间隔,这里设定每1秒提取一一帧
if ~exist(video_name,'dir')==1
mkdir(video_name);%生成文件夹存放图片
end
i=1;
for k = 1 :T: numFrames%? ? ?
numframe = read(VideoAd,k);%读取第几帧
%num=sprintf(nz,i);%i为保存图片的序号
dir_path = strcat(video_name,'\',num2str(i));
if ~exist(dir_path,'dir')==1
mkdir(dir_path);%生成文件夹存放图片
end
imwrite(numframe,strcat(video_name,'\',num2str(i),'\',num2str(i),'.png'),'png'); %写入图片
i=i+1;
end
end
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%% 处理左图的程序
clc
clear
addpath('../');%添加上层目录,方便调用函数
D = dir('./*.bmp');
D = struct2cell(D);%结构体不好调用,转成元胞数组来使用
pics_name = D(1,:);
for pic_name = pics_name %cpicName = 'a001.bmp'
picName = pic_name{1};
picN = strsplit(picName,'.');
picN = picN{1};
A = imread(picName);
imshow(A);
I = im2bw(A,100/255); %对图像二值化处理
I = denoise(I);
imshow(I);
[ coord,L ] = edge_extract( ~I );
imshow(L);
x = coord(:,2);
y = coord(:,1);
inds = find(y == max(y));
ind_max = max(inds);
ind_min = min(inds);
X0 = [max(y) (x(ind_min)+x(ind_max))/2 ];%使用矩阵座标,即ij座标
point_num = size(coord,1);
Coordinates = (repmat(X0,point_num,1) - coord);
Coord = normalize( Coordinates );%一个归一化处理
imwrite(L,[picN 'E.png']); %写入图片
csvwrite([picN '.csv'],Coord);
figure;
pic_std = plot(Coord(1:end,1),Coord(1:end,2),'r.');
saveas(pic_std,[picN 'STD.jpg']); %写入图片
end
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%% 处理右图的程序
clc
clear
addpath('../');%添加上层目录,方便调用函数
D = dir('./*.bmp');
D = struct2cell(D);%结构体不好调用,转成元胞数组来使用
pics_name = D(1,:);
for pic_name = pics_name %picName = 'b001.bmp'
picName = pic_name{1};
picN = strsplit(picName,'.');
picN = picN{1};
A = imread(picName);
imshow(A);
I = im2bw(A,60/255); %对图像二值化处理
I = denoise(I);
imshow(I);
[ coord,L ] = edge_extract( ~I );%绕一圈儿,回到原点
imshow(L);
x = coord(:,2);
y = coord(:,1);
inds = find(y == max(y));
ind_max = max(inds);
ind_min = min(inds);
X0 = [max(y) (x(ind_min)+x(ind_max))/2 ];%使用矩阵座标,即ij座标
%找到上顶点的索引,做旋转矫正
inds_up = find(y == min(y));
ind_up_max = max(inds_up);
ind_up_min = min(inds_up);
Y0 = [min(y) (x(ind_up_min)+x(ind_up_max))/2 ];
ang = -atan((X0(2)-Y0(2))/(X0(1)-Y0(1)));
if abs(ang) > 0.01%角度太小就不用转了吧
coord = myrotate( coord,X0,ang);
end
%可视化矫正结果,调试用,只能调试到这一步时用,再往下X0不动的
% if min(min(coord))<1
% coord = coord-min(min(coord))+1;
% end
% [low_num,col_num] = size(I);
% L_test = sparse(round(coord(:,1)),round(coord(:,2)),1,low_num+100,col_num+100);
% L_test = full(L_test);
% imshow(L_test)
% figure(99);
% scatter(coord(:,1),coord(:,2))
x = coord(:,2);
y = coord(:,1);
% inds = find(y == max(y));
% ind_max = max(inds);
% ind_min = min(inds);
% X0 = [max(y) (x(ind_min)+x(ind_max))/2 ];%使用新选的X0
inds_half = ((x<(X0(2)-1))&(y<=(X0(1))));
coord_half = coord(inds_half,:);
point_num = size(coord_half,1);
coord = coord_half;
Coordinates = (repmat(X0,point_num,1) - coord);
% test 可视化结果
%edge_rebuid = sparse(round(Coordinates(:,1))+10,round(Coordinates(:,2))+10,1,500,200);
%min(round(Coordinates(:,2))+1)
% imshow(full(edge_rebuid));
% figure;
% scatter(points_coord(:,1),points_coord(:,2))
Coord = normalize( Coordinates );%一个归一化处理
imwrite(L,[picN 'E.png']); %写入图片
csvwrite([picN '.csv'],Coord);
figure;
pic_std = plot(Coord(1:end,1),Coord(1:end,2),'r.');
saveas(pic_std,[picN 'STD.jpg']); %写入图片
% pause(2);
% scatter(Coord(:,1),Coord(:,2));
end
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%% 主成分分析
function [ coef ] = find_symbol_coef( exp,item )
%输入一个表达式,即一个项,提取项前面的系数
% author:lusong
%exp = Phi 很鲁棒
charexp=char(exp);
item=char(item);
indexItem=strfind(charexp,item); %获取存在item项的指标
indexPseudo=union(strfind(charexp,['(',item]),strfind(charexp,[item,'^'])); %获取伪指标
indexItem=setdiff(indexItem,indexPseudo); %获取真正的item指标
%循环计算各个item位置的系数
itemLen=length(item);
expLen=length(charexp);
coef=sym(0);
for i=1:length(indexItem)
index=indexItem(i); %计算当前item项的位置
cache=sym(1); %存储当前项的系数
if index~=1 && charexp(index-1)=='*'
indexFront=index-2; %初始化系数项的前指标
while indexFront~=1 && charexp(indexFront-1)~=' '
indexFront=indexFront-1;
end
cache=cache*sym(charexp(indexFront:index-2));
end
if index+itemLen~=expLen && charexp(index+1)=='*'
indexBack=index+2; %初始化系数项的后指标
while indexFront+itemLen~=expLen && charexp(indexBack+1)~=' '
indexBack=indexBack+1;
end
cache=cache*sym(charexp(index+2:indexBack));
end
coef=coef+cache;
end
end
clc;
clear;
close all;
syms x y t;
eta = 104;gamma = 20.9;rho = 964;
theta_e = degtorad(53);alpha = degtorad(15);g = 9.8;
num = 6;
a = sym('a',[num,1]);
adot = sym('adot',[num,1]);
%% Phi的计算
H = (x-a(1)).*(a(2)-x).*(a(3)+a(4)*x);
Y = (x-a(1))^0.*(a(2)-x).^0*(a(5)+a(6)*x);
h = H.*(1-(y./Y)^0.5);
HY = H.*Y;
HY_dot = conj(gradient(HY,a)')*adot;
HY_dot = simplify(HY_dot);
latex(HY_dot)
V = -1/(HY).*int(HY_dot,x,a(1),x);%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%这个积分算不出来,因为0.5次方的存在。
Y_dot = conj(gradient(Y,a)')*adot;
W = 1./Y*(Y_dot+V.*diff(Y,x));
%Phi_intvar = 3*eta*(V.^2+(y*W).^2)./h;
Phi_intvar = W.^2;
%Phi_intvar = simplify(Phi_intvar);
%latex(Phi_intvar)
%Phi_intvar_resy = int(Phi_intvar,y,-Y,Y);
%Phi = 0.5*(int(Phi_intvar_resy,x,a(1),a(2)));
Phi_intvar_resx= int(Phi_intvar,x,a(1),a(2));%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%这个积分算不出来,被积函数算不出来
Phi = 0.5*(int(Phi_intvar_resx,y,-Y,Y));
%% 提取Phi关于adot的系数
A = a*conj(a');
Phi = sum(sum(A.*(adot*conj(adot'))));
adot_multi_matrix = adot*conj(adot');
for i=1:num
for j=1:num
item = adot_multi_matrix(i,j);
xi(i,j) = find_symbol_coef(Phi,item);
end
end
xi = 2.*xi;
% item = adot(2)*adot(1);
% find_symbol_coef(Phi,item)
%% 势能函数
int_var = 0.5.*gamma.*theta_e.^2+0.5.*gamma.*(diff(h,x).^2+diff(h,y).^2);
remainder_term = 0.5.*rho.*g.*h^2.*sin(alpha)-rho.*g.*x.*h.*cos(alpha);
A_temp = int(int_var,y,-Y,Y);
A = int(A_temp,x,a(1),a(2))+remainder_term;%%%%%%%%%%积分也不好积
%% 求解DOEs
xi_inv = inv(xi);
odefun = @(t,a) xi\gradient(A);%%%改
a0 = ones(1,num);
[T,a_cal] = ode45(odefun,[1,1],a0);
%% 计算出来的结果以及画图
H_cal = subs(H,[a1 a2 a3 a4],[a_cal(1) a_cal(2) a_cal(3) a_cal(4)]);
Y_cal = subs(Y,[a1 a2 a5 a6],[a_cal(1) a_cal(2) a_cal(5) a_cal(6)]);
H_cal_fun = matlabFunction(H_cal,x);
xx = a(1):0.01:a(2);
plot(xx,H_cal_fun(xx));
clc
clear
close all
format short
digits(5)
%% 设定维数
p = 2;
d = 2;
%% 读入数据,保存
D = dir('../data/*.csv');%%%%%%%%%%%%%%%%%%%%%%%%
D = struct2cell(D);%结构体不好调用,转成元胞数组来使用
csvs_name = D(1,:);
N = 0;%这个表示数据的个数
%csvs_name = csvs_name(5:6);
for csv_name = csvs_name %cpicName = 'a001.bmp'
N = N+1;
csvName = csv_name{1};
Data{N} = load(['../data/' csvName]);%%%%%%%%%%%%%%%%%%%%%
end
%clear csv_name csvN csvName csvs_name D
%% 定义原空间基,生成模型函数,由模型函数通过拟合得到点的座标表示
%p = 15;%原空间维数
%%根据p自动生成模型函数
eval_poly = 'a(1)';
for i = 2:p
eval_poly = [eval_poly '+a(' num2str(i) ').*x.^' num2str(i-1)];
end
eval_poly = ['modelfun = @(a,x) x.^(0.5).*(1-x).^(0.5).*(' eval_poly ');'];
eval(eval_poly);
%modelfun = @(a,x) x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*sin(x)+a(3).*cos(x)+a(4).*1./x+a(5).*x+a(6).*x.^2);
% modelfun = @(a,x)(x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*x+a(3).*x.^2+...
% a(4).*x.^3))%+a(5).*x.^4+a(6)*x.^5))+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
% modelfun = @(a,x)((a(1)+a(2).*x.^2+a(3).*x.^2+...
% a(4).*x.^3+a(5).*x.^4+a(6)*x.^5+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
%%做一波拟合,求出系数,进行拟合,拟合结果为A
%%A中存的是数据点的座标表示
for k = 1:N
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%y = y./(x.*(1-x));%%%%%%%%如果将x(1-x)项挪到左边,拟合会出问题
a0 = ones(1,p);
a = nlinfit(x,y,modelfun,a0);
A(:,k) = a';
end
%clearvars -except A modelfun x y
%% 开始奇异值分解降维,得到新空间的原点和座标轴,座标表示
%%由奇异值分解做主成分分析,A的每一列为原空间下的系数,U的每一列为主成分
[p,N] = size(A);
%d = 5;%新空间维数
x0 = mean(A,2);%计算样本均值
A_shift = A - repmat(x0,1,N);%中心平移每个训练样本,A_shift为原数据点的平移表示
%%%%对于A_shift的补充处理
syms x;
base_vec_T = x.^(0.5).*(1-x).^(0.5).*x.^[0:p-1];
base_vec = conj((base_vec_T))';
W = int(base_vec*base_vec_T,[0,1]);
L_prime = chol(W);
L_prime_A_shift = L_prime*A_shift;
%%%%
[U,S,V] = svd(L_prime_A_shift);
B = L_prime\U;
if size(S,2) == 1
S_diag = S(1);
else
S_diag = diag(S);
end
R = cumsum(S_diag)./sum(S_diag);
Coord_new = B(:,1:d);
%% 新空间的座标轴和原点的函数表示
%%生成新的空间中的基函数,找到d个新空间基函数及原点座标
%%Coord_new x0中存的是新座标系,fi存的是新的函数空间的原点和座标轴
for k = 1:d;%取出第k个基函数
syms x;
c = B(:,k);
exp = modelfun(c,x);
exp = simplify(exp);%第k个基函数的表达式
f{k} = exp;
digits(2);
latex(vpa(exp,2));%写成latex表达式黏贴到解释器中
end
f0 = modelfun(x0,x);
f0 = simplify(f0);
latex(vpa(f0,2));
% for i = 1:d
% f_fun{i} = matlabFunction(f{i});
% end
% f0_fun = matlabFunction(f0);
%% 求原座标系中的投影后在原空间中的位置
%A_new_coord = Coord_new'*A_shift;%A_new_coord表示原数据点在新空间中的表示
syms x;
for k = 1:N
a = A_shift(:,k);
pk_f = modelfun(a,x);
for j = 1:d
A_new_coord(j,k) = int(pk_f.*f{j},0,1);
end
end
%%函数运算
for k = 1:N
A_shadow_f = f0;
for i = 1:d
A_shadow_f = A_shadow_f+f{i}*A_new_coord(i,k);
end
A_shadow_f = simplify(A_shadow_f);
A_shadow_fs{k} = A_shadow_f;
A_shadow_fs_fun{k} = matlabFunction(A_shadow_f);
end
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%座标运算,可以注释掉
% A_shadow_coord = Coord_new*A_new_coord+repmat(x0,1,N);%A_shadow_coord表示投影座标点在原座标系下的表示
% syms x;
% for k = 1:N
% a = A_shadow_coord(:,k);
% A_shadow_coord_f = modelfun(a,x);
% A_shadow_coord_fs{k} = simplify(A_shadow_coord_f);
% end
%
% %%不考虑舍入误差的情况下,可以证明座标运算和函数运算的得到的函数表达式是一样的,验证代码如下
% k=5;
% diff = A_shadow_coord_fs{k}-A_shadow_fs{k}
% diff = simplify(diff)
% digits(2);
% latex(vpa(diff,2))
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 画图和求误差
Errors = [];
NN = 1000;
h = 1/NN;
xx = linspace(0,1,NN+1);
close all;
for k = 1:N
%%原数据点
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%%拟合曲线
a = A(:,k);
data_fit_f = @(x) modelfun(a,x);
%%投影函数
A_shadow_f_fun = A_shadow_fs_fun{k};
%%原点函数
f0_fun = matlabFunction(f0);
%%开始画图
figure(k);
scatter(x,y,'.','MarkerEdgeColor','b',...
'MarkerFaceColor','c',...
'LineWidth',0.5);
hold on;
y_fit = data_fit_f(xx);
y_shadow = A_shadow_f_fun(xx);
y_f0 = f0_fun(xx);
plot(xx,y_fit,'g');
plot(xx,y_shadow,'black');
plot(xx,y_f0,'r');
legend('数据','拟合','投影','原点');
%%求拟合曲线和投影函数之间的L2误差
%Errors(end+1) = norm((y_fit-y_shadow),2);
Errors(end+1) = sum(abs(y_fit-y_shadow)*h);
end
Errors_mean = mean(Errors)
%% test
% close all;
% plot(xx,xx);
% hold on;
% plot(xx,xx.^9)
clc
clear
close all
format short
digits(5)
%% 设定维数
p = 2;
d = 1;
%% 读入数据,保存
D = dir('../data2/*.csv');%%%%%%%%%%%%%%%%%%%%%%%%
D = struct2cell(D);%结构体不好调用,转成元胞数组来使用
csvs_name = D(1,:);
N = 0;%这个表示数据的个数
%csvs_name = csvs_name(5:6);
for csv_name = csvs_name %cpicName = 'a001.bmp'
N = N+1;
csvName = csv_name{1};
Data{N} = load(['../data2/' csvName]);%%%%%%%%%%%%%%%%%%%%%
end
%clear csv_name csvN csvName csvs_name D
%% 定义原空间基,生成模型函数,由模型函数通过拟合得到点的座标表示
%p = 15;%原空间维数
%%根据p自动生成模型函数
eval_poly = 'a(1)';
for i = 2:p
eval_poly = [eval_poly '+a(' num2str(i) ').*x.^' num2str(i-1)];
end
eval_poly = ['modelfun = @(a,x) x.^(1).*(1-x).^(1).*(' eval_poly ');'];
eval(eval_poly);
%modelfun = @(a,x) x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*sin(x)+a(3).*cos(x)+a(4).*1./x+a(5).*x+a(6).*x.^2);
% modelfun = @(a,x)(x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*x+a(3).*x.^2+...
% a(4).*x.^3))%+a(5).*x.^4+a(6)*x.^5))+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
% modelfun = @(a,x)((a(1)+a(2).*x.^2+a(3).*x.^2+...
% a(4).*x.^3+a(5).*x.^4+a(6)*x.^5+...
% a(7)*x.^6+a(8).*x.^7+a(9).*x.^8+a(10).*x.^9));
%%做一波拟合,求出系数,进行拟合,拟合结果为A
%%A中存的是数据点的座标表示
for k = 1:N
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%y = y./(x.*(1-x));%%%%%%%%如果将x(1-x)项挪到左边,拟合会出问题
a0 = ones(1,p);
a = nlinfit(x,y,modelfun,a0);
A(:,k) = a';
end
%clearvars -except A modelfun x y
%% 开始奇异值分解降维,得到新空间的原点和座标轴,座标表示
%%由奇异值分解做主成分分析,A的每一列为原空间下的系数,U的每一列为主成分
[p,N] = size(A);
%d = 5;%新空间维数
x0 = mean(A,2);%计算样本均值
A_shift = A - repmat(x0,1,N);%中心平移每个训练样本,A_shift为原数据点的平移表示
%%%%对于A_shift的补充处理
syms x;
base_vec_T = x.^(1).*(1-x).^(1).*x.^[0:p-1];
base_vec = conj((base_vec_T))';
W = int(base_vec*base_vec_T,[0,1]);
L_prime = chol(W);
L_prime_A_shift = L_prime*A_shift;
%%%%
[U,S,V] = svd(L_prime_A_shift);
B = L_prime\U;
if size(S,2) == 1
S_diag = S(1);
else
S_diag = diag(S);
end
R = cumsum(S_diag)./sum(S_diag);
Coord_new = B(:,1:d);
%% 新空间的座标轴和原点的函数表示
%%生成新的空间中的基函数,找到d个新空间基函数及原点座标
%%Coord_new x0中存的是新座标系,fi存的是新的函数空间的原点和座标轴
for k = 1:d;%取出第k个基函数
syms x;
c = B(:,k);
exp = modelfun(c,x);
exp = simplify(exp);%第k个基函数的表达式
f{k} = exp;
digits(2);
latex(vpa(exp,2));%写成latex表达式黏贴到解释器中
end
f0 = modelfun(x0,x);
f0 = simplify(f0);
latex(vpa(f0,2));
% for i = 1:d
% f_fun{i} = matlabFunction(f{i});
% end
% f0_fun = matlabFunction(f0);
%% 求原座标系中的投影后在原空间中的位置
%A_new_coord = Coord_new'*A_shift;%A_new_coord表示原数据点在新空间中的表示
syms x;
for k = 1:N
a = A_shift(:,k);
pk_f = modelfun(a,x);
for j = 1:d
A_new_coord(j,k) = int(pk_f.*f{j},0,1);
end
end
%%函数运算
for k = 1:N
A_shadow_f = f0;
for i = 1:d
A_shadow_f = A_shadow_f+f{i}*A_new_coord(i,k);
end
A_shadow_f = simplify(A_shadow_f);
A_shadow_fs{k} = A_shadow_f;
A_shadow_fs_fun{k} = matlabFunction(A_shadow_f);
end
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%座标运算,可以注释掉
% A_shadow_coord = Coord_new*A_new_coord+repmat(x0,1,N);%A_shadow_coord表示投影座标点在原座标系下的表示
% syms x;
% for k = 1:N
% a = A_shadow_coord(:,k);
% A_shadow_coord_f = modelfun(a,x);
% A_shadow_coord_fs{k} = simplify(A_shadow_coord_f);
% end
%
% %%不考虑舍入误差的情况下,可以证明座标运算和函数运算的得到的函数表达式是一样的,验证代码如下
% k=5;
% diff = A_shadow_coord_fs{k}-A_shadow_fs{k}
% diff = simplify(diff)
% digits(2);
% latex(vpa(diff,2))
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 画图和求误差
Errors = [];
NN = 1000;
h = 1/NN;
xx = linspace(0,1,NN+1);
close all;
for k = 1:N
%%原数据点
data = Data{k};
data(:,2) = abs(data(:,2));%取绝对值
x = data(:,1);
y = data(:,2);
%%拟合曲线
a = A(:,k);
data_fit_f = @(x) modelfun(a,x);
%%投影函数
A_shadow_f_fun = A_shadow_fs_fun{k};
%%原点函数
f0_fun = matlabFunction(f0);
%%开始画图
figure(k);
scatter(x,y,'.','MarkerEdgeColor','b',...
'MarkerFaceColor','c',...
'LineWidth',0.5);
hold on;
y_fit = data_fit_f(xx);
y_shadow = A_shadow_f_fun(xx);
y_f0 = f0_fun(xx);
plot(xx,y_fit,'g');
plot(xx,y_shadow,'black');
plot(xx,y_f0,'r');
legend('数据','拟合','投影','原点');
%%求拟合曲线和投影函数之间的L2误差
%Errors(end+1) = norm((y_fit-y_shadow),2);
Errors(end+1) = sum(abs(y_fit-y_shadow)*h);
end
Errors_mean = mean(Errors)
%% test
% close all;
% plot(xx,xx);
% hold on;
% plot(xx,xx.^9)
\begin{lstlisting}[language=Matlab,frame=shadowbox]
%% 最小二乘
clc
clear
D = dir('data/*.csv');
D = struct2cell(D);
names = D(1,:);
data = [];
for name = names
name = name{1};
data = [data;load(['data/' name])];
end
x = data(:,1);
y = data(:,2);
%modelfun = @(a,x)(x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*x+a(6)*x*4+a(3).*x.^2+a(4).*x.^3+a(5).*x.^5))%+a(6)*x.*4));
modelfun = @(a,x)(x.^(0.5).*(1-x).^(0.5).*(a(1)+a(2).*x.*100+a(3).*x.^2+a(4).*x.^3+a(5).*x.^4+a(6)*x.^5));
a0 = ones(1,6)*100;
modelfun(a0,0)
modelfun(a0,1)
a = nlinfit(x,y,modelfun,a0)
a(abs(a)<2) = 0
plot(x,modelfun(a,x))