函數型數據主成分分析(FPCA)

本文主要介紹了以下幾個方面的內容:簡單介紹了經典的主成分分析方法,包括其數學推導,算法步驟,和幾個實際算例;簡單介紹了其它的數據降維方法,譬如局部線性嵌入以及它的簡單算例;更近一步,我們介紹了函數型主成分分析方法(FPCA),包括其基本思想、數學推導、算法描述等,最爲重要的是,我們將該方法和本領域進行結合,有了一些新的思考。

前言

“維數災難"帶來的直接結果就是很多低維空間行之有效的算法在高維空間中變得不可計算,爲此,我們需要進行降維。在另一個方面,數據偏平化的情況下,降維有助於我們抓住數據的主要結構,過濾可能的誤差帶來的影響,使模型更加真實。另外,在某些情況下,降維可用於可視化。數據降維的方法有很多,比如說基於"最小化投影誤差”(最大化類內方法)的主成分分析方法(PCA),以及基於保持拓撲結構不變(高維空間中是鄰居,到了地位空間中還是鄰居)的局部線性嵌入(LLE)等方法。

在多元統計分析中,主成分分析(Principal Components Analysis,PCA)是一種統計分析、簡化數據集的方法。它利用正交變換來對一系列可能相關的變量的觀測值進行線性變換,從而投影爲一系列線性不相關變量的值,這些不相關變量稱爲主成分(Principal Components)。具體地,主成分可以看做一個線性方程,其包含一系列線性係數來指示投影方向。PCA對原始數據的正則化或預處理敏感(相對縮放)。PCA本質上尋求的是數據點在低秩空間中的一個表示。

高維數據,意味着數據需要多於兩個或三個維度來表示,一般很難被解釋。一種簡化的方法是假設數據嵌在高維空間的一個非線性流形上。如果這個流形維數足夠低,那麼數據可以在低維空間中被可視化。局部線性嵌入(Locally Linear Embedding,LLE)關注於降維時保持樣本局部的線性特徵,由於LLE在降維時保持了樣本的局部特徵,它廣泛的用於圖像圖像識別,高維數據可視化等領域。

有了降維和主成分分析,我們做PDE的就會思考,既然可以對Rn\mathbb{R}^n空間中的數據做降維,那麼函數作爲一組基函數的線性組合,如果將基函數看作一些座標系中的一個個座標軸,是否也可以對函數空間中的"數據"做降維呢?答案是肯定的。函數型(數據)主成分分析(Functional Principal Components analysis)可以視爲是傳統的主成分分析的一種推廣。類比於PCA,它希望能將高維函數空間中的函數放到低維空間中去表示,而使得被表示的數據集損失最小。更通俗地說,就是希望用更少的基函數來表示某個已知基函數的函數空間的一堆函數,新空間的基函數用舊空間的基函數來線性表出。那麼,我們就需要定義函數之間的距離,函數空間的內積等等。

主成分分析(PCA)

數據降維簡介

在機器學習和統計學領域,降維是指在某些限定條件下,降低隨機變量個數,得到一組"不相關"主變量的過程。
降維可進一步細分爲變量選擇和特徵提取兩大方法。除了考慮"維數災難"的問題,降維還有一些本質的原因。目前大部分降維算法處理向量表達的數據,也有一些降維算法處理高階張量表達的數據。之所以使用降維後的數據表示是因爲在原始的高維空間中,包含有冗餘信息以及噪音信息,在實際應用例如圖像識別中造成了誤差,降低了準確率,通過降維,我們希望減少冗餘信息所造成的誤差,提高識別(或其他應用)的精度,又或者希望通過降維算法來尋找數據內部的本質結構特徵。目前比較流行的降維算法有主成分分析、線性判別分析、局部線性嵌入和拉普拉斯特徵映射等等。

PCA算法的原理解釋

所謂的主成分分析,不過是在高維的空間中尋找一個低維的正交座標系,比如說在三維空間中尋找一個二維的直角座標系。那麼這個二維的直角座標系就會構成一個平面,將三維空間中的各個點在這個二維平面上做投影,就得到了各個點在二維空間中的一個表示,由此數據點就從三維降成了二維。

這個過程的關鍵在於,我們如何選取這個低維的座標系,即座標系原點在哪?各個軸朝哪個方向?一個原則就是使得各個點到到這個平面的距離平方和達到最小。由此,通過簡單地數學推導,就能得到原點的表達公式和座標系的各個基向量的表達公式。

PCA算法的數學推導

我們假設輸入爲p維的N個對象,XX表示如下圖所示的一個矩陣:
在這裏插入圖片描述
通過PCA降維,將其降爲d維的N個對象,假設爲YY,同前,每列表示一個對象,每行表示一個特徵:
在這裏插入圖片描述

我們要將所有點投影到新的座標系中去,無非是尋找新座標系的座標原點和各個座標軸。

我們假設WW的每一列爲新的座標系中單位正交的座標軸表示,x0x_0爲新座標系的原點(相對於原座標系)。
那麼,我們要做的就是找到一個合適的WWx0x_0,使其極小化所有點到新的座標平面的距離平方和。
容易知道,每一個點到新座標系的距離平方爲(其中X=(x0,W)\underline X = (x_0,W)表示的是位置參數):
DsX(x,X)=(xx0i=1dwiT(xx0)wi)T(xx0i=1dwiT(xx0)wi)\operatorname{Ds}_{X}(x, \underline{X})=\left(x-x_{0}-\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)^{T}\left(x-x_{0}-\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)
對其進行化簡,可得:
DsX(x,X)=(xx0i=1dwiT(xx0)wi)T(xx0i=1dwiT(xx0)wi)=(xx0)T(xx0)(i=1dwiT(xx0)wi)T(xx0)(xx0)Ti=1dwiT(xx0)wi+(i=1dwiT(xx0)wi)Ti=1dwiT(xx0)wi\begin{array}{l}{D s_{X}(x, \underline{X})=\left(x-x_{0}-\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)^{T}\left(x-x_{0}-\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)} \\ {=\left(x-x_{0}\right)^{T}\left(x-x_{0}\right)-\left(\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)^{T}\left(x-x_{0}\right)} \\ {-\left(x-x_{0}\right)^{T} \sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}+\left(\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}\right)^{T} \sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right) w_{i}}\end{array}
進而有,
DsX(x,X)=(xx0)T(xx0)i=1dwiT(xx0)(xx0)Twi\operatorname{Ds}_{X}(x, \underline{X})=\left(x-x_{0}\right)^{T}\left(x-x_{0}\right)-\sum_{i=1}^{d} w_{i}^{T}\left(x-x_{0}\right)\left(x-x_{0}\right)^{T} w_{i}
讓所有點到投影點距離平方和最小,即求解約束優化問題:
minXkDsX(xk,X)=k(xkx0)T(xkx0)i=1dwiTk(xkx0)(xkx0)TwiwiTwj=δijδij=1,i=jδij=0,ij\begin{array}{l}{\min _{\underline{X}} \sum_{k} D s_{X}\left(x_{k}, \underline{X}\right)=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)} \\ {-\sum_{i=1}^{d} w_{i}^{T} \sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T} w_{i}} \\ {w_{i}^{T} w_{j}=\delta_{i j} \quad \delta_{i j}=1, \quad i=j} \\ {\delta_{i j}=0, \quad i \neq j}\end{array}
我們藉助拉格朗日乘子法來求解此約束優化問題:
L=k(xkx0)T(xkx0)i=1dwiTk(xkx0)(xkx0)Twii=1dλi(wiTwi1)L=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)-\sum_{i=1}^{d} w_{i}^{T} \sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T} w_{i}-\sum_{i=1}^{d} \lambda_{i}\left(w_{i}^{T} w_{i}-1\right)
Lx0=2(Ipi=1dwiwiT)k(xkx0)Lwi=2k(xkx0)(xkx0)Twi2λiwi\begin{array}{l}{\frac{\partial L}{\partial x_{0}}=-2\left(I_{p}-\sum_{i=1}^{d} w_{i} w_{i}^{T}\right) \sum_{k}\left(x_{k}-x_{0}\right)} \\ {\frac{\partial L}{\partial w_{i}}=2 \sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T} w_{i}-2 \lambda_{i} w_{i}}\end{array}
由兩個偏導爲0,可以得到:
x0=kxkNk(xkx0)(xkx0)Twi=λiwi\begin{array}{l}{x_{0}=\sum_{k} \frac{x_{k}}{N}} \\ {\sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T} w_{i}=\lambda_{i} w_{i}}\end{array}
因爲半正定矩陣的特徵值非負,所以,原最小化損失函數可進行轉化:
minXkDsX(xk,X)=k(xkx0)T(xkx0)i=1dwiTk(xkx0)(xkx0)Twi=k(xkx0)T(xkx0)i=1dλiwiTwi=k(xkx0)T(xkx0)i=1dλi\begin{array}{l}{\min _{\underline{X}} \sum_{k} D s_{X}\left(x_{k}, \underline{X}\right)} \\ {=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)-\sum_{i=1}^{d} w_{i}^{T} \sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T} w_{i}} \\ {=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)-\sum_{i=1}^{d} \lambda_{i} w_{i}^{T} w_{i}} \\ {=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)-\sum_{i=1}^{d} \lambda_{i}}\end{array}
我們利用矩陣的性質,要想最小化距離平方和,有:
minXkDsX(xk,X)=k(xkx0)T(xkx0)i=1dλi\min _{\underline{X}} \sum_{k} \operatorname{Ds}_{X}\left(x_{k}, \underline{X}\right)=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)-\sum_{i=1}^{d} \lambda_{i}
ΣX=k(xkx0)(xkx0)T\Sigma_{X}=\sum_{k}\left(x_{k}-x_{0}\right)\left(x_{k}-x_{0}\right)^{T}p×pp\times p的矩陣。有性質:
tr(ΣX)=k(xkx0)T(xkx0)=i=1pλi\operatorname{tr}\left(\Sigma_{X}\right)=\sum_{k}\left(x_{k}-x_{0}\right)^{T}\left(x_{k}-x_{0}\right)=\sum_{i=1}^{p} \lambda_{i}
則有,
minXkDsX(xk,X)=i=1pλii=1dλi=i=d+1pλi\min _{\underline{X}} \sum_{k} \operatorname{Ds}_{X}\left(x_{k}, \underline{X}\right)=\sum_{i=1}^{p} \lambda_{i}-\sum_{i=1}^{d} \lambda_{i}=\sum_{i=d+1}^{p} \lambda_{i}
由此我們可以看到,要得到極小值,我們只要計算XXTXX^T矩陣的前d個最大特徵值,是投影后樣本具有最小損失的特點。那麼此時的WW就是XXTXX^T矩陣前d個最大特徵值對應的特徵向量。
不難知道,對於XXTXX^T的特徵分解: XXT=UΛUTXX^T = U\Lambda U^T
這裏的U就是前天提到的奇異值分解的U。同理,雖然我們這裏沒有用到VV,但其實奇異值分解的VV正式XTXX^TX的特徵值分解的特徵矩陣。
爲了比較XXTXX^T特徵分解和XX進行奇異值分解的消耗,寫了一段小程序,並使用matlab探查功能進行比較如下:
在這裏插入圖片描述

這個比較事實上沒有太大的意義。所用的代碼如附錄。

PCA算法簡單描述

假設XX是一個m*n矩陣,表示n個對象的m個特徵表示數據,即每一列表示一個對象,每一行表示一個特徵。我們希望將特徵降爲d維,d遠小於m。輸出結果爲YY,一個d*n的矩陣。

  • X=[x1,x2...xn]X=[x_1,x_2...x_n],計算每個對象點的平均值x0=1ni=1nxix_0 = \frac{1}{n}\sum\limits _{i=1}^nx_i

  • Xx0:=[x1x0,x2x0...xnx0]X-x_0 : = [x_1-x_0,x_2-x_0...x_n-x_0]做奇異值分解:Xx0=UΛVTX-x_0 = U\Lambda V^T

  • x0x_0即爲新座標系的原點,UU的前d列即爲去中心化後的新的座標系,不妨記爲WW。那麼,所有點在新座標系下的表示爲:Y=WT(Xx0)Y=W^T*(X-x_0)。同樣地,要將新的投影點yy還原到原座標系中,可以寫爲:x0+Wyx_0+W*y

下面以基於矩陣的視角寫出PCA算法的算法流程,輸入爲矩陣p*N矩陣X,輸出爲d*N矩陣Y。矩陣的每一列都表示一個對象,每一行都表示對象的一個特徵表示。

在這裏插入圖片描述

PCA算例一

假設小明和小紅有身高和體重兩個特徵(實際操作數據要進行預處理,這裏不做),如下表:

在這裏插入圖片描述
那麼此時X=[178 165;70 65]X = [178 ~165; 70 ~65],現在試圖通過PCA降維,將身高和體重合併爲一個特徵。走一遍上面的過程,可得:

Xx0=UΛVTX-x_0 = U\Lambda V^T

其中,

那麼,有

那就是說,最後數據可降維爲:

在這裏插入圖片描述
這個問題MATLAB計算的小程序在附錄。

PCA算例二

這是一個對於人臉數據進行降維的例子,人臉數據是我從網上找的。MATLAB源代碼見附錄。
選取了2000x1680的數據集進行了測試,選取降維後維數爲20,其降維前後的圖像(降維後的圖像指的是投影點還原到原空間對應的座標值重構出的圖像)如下所示(選取第一個點爲代表):
在這裏插入圖片描述
我們使用別人製作的降維工具箱"drtoolbox"重新進行計算並和我的程序結果進行比較。工具箱的使用代碼見附錄。結果如下:
在這裏插入圖片描述
當然,我們也可以比較我的程序和工具箱程序的誤差的大小,比如L2L_2誤差。都很簡單,暫且不提。

其他數據降維方法

其他的數據降維方法還有很多,比如說線性判別分析,拉普拉斯特徵映射等等,我這裏就簡單介紹一下局部線性嵌入。

當數據具備某些非線性結構,如流形結構時,我們希望降維後的數據仍然保持這些結構。那麼就提出了LLE降維算法。LLE(Locally linear embedding):在數據降維後仍然保留原始高維數據的拓撲結構,這種拓撲結構表現爲數據點的局部鄰接關係。

此算法我們首先要尋求每個數據點的k個最近鄰,然後將當前數據點用k個最近鄰線性表出,那麼就有相對的權重係數。
我們希望數據在降維後數據點之間依然能保持這種線性表出的關係,並且在滿足另外一些約束條件的前提下,我們很容易求得降維後的數據。
具體原理和公式網絡上有很多人整理得很好,這裏不提了。

下面是LLE算法的算法流程,輸入爲矩陣p*N矩陣X,輸出爲d*N矩陣Y。矩陣的每一列都表示一個對象,每一行都表示對象的一個特徵表示。
在這裏插入圖片描述
源代碼見附錄。

選取了409×698的圖像數據集進行了測試,選取降維後維數爲2,選取最近鄰個數k=12k=12,實驗後的部分結果如下:
在這裏插入圖片描述
我們使用別人製作的降維工具箱"drtoolbox"重新進行計算並和我的程序結果進行比較。工具箱的使用代碼見附錄。

降維後的部分數據截圖如下:
在這裏插入圖片描述
爲了比較性能,找個一個別人寫的LEE算法,算是網絡版本,代碼在附錄。"網絡版"的數據結果和我的版本的結果是一樣的。我們開啓Matlab的探查功能來比較耗時,結果如圖。
在這裏插入圖片描述

函數型數據主成分分析

Idea的萌生

前一段時間我在做一個流體力學上的東西(雖然現在已經不做這個方向了),其中比較關鍵的步驟就是需要用一個帶時間變量的多項式公式,來刻畫一個物理過程。這個多項式的各個項前面的係數是未知的,由物理規律來決定。我們希望從一些物理實驗數據中來通過一些機器學習的手段來學到多項式各個項前面的係數。

這個問題本質的困難在於,我們不知道那些函數項(基函數)是我們需要的。事實上,只要知道了多項式包含哪些項,是可以通過一些物理原理求得前面的係數的。一個基本的想法就是選足夠多的基函數,使得函數空間足夠大而包含真值。但是,函數空間太大會帶來使用物理原理求係數時的計算困難增大。所以,我們希望能找一個原來大的函數空間的一個子空間,使得用這個子空間,就能夠基本刻畫原來的物理過程。再用物理原理來求得以子空間基函數爲各個項的多項式係數。

仔細一想,這不正是函數空間的PCA嗎?如果把每一個函數看做一個數據點,把各個基函數看做是組成座標系的座標軸,那麼"函數點"在高維函數空間中的表示,就可以通過類似於主成分分析的技巧,變成在低維函數空間中的表示。只要有了能表示刻畫整個物理過程的各個數據點的低維空間,那麼刻畫物理過程的多項式的項(即低維空間的基函數)也就明確了,剩下的事情也就自然而然了。

FPCA簡介和理論推導

函數型主成分分析(FPCA,Functional Principal Components Analysis)是傳統的PCA的一種推廣。考慮我們已經從數據中得到擬合曲線xi(s),sT,i=1,,nx_{i}(s), s \in \mathcal{T}, i=1, \cdots, n,所謂的第一主成分,就是我們希望能找到一個模爲1的函數β(s)\beta(s),使得{xi}\{x_i\}β\beta上的投影(L2L_2內積){ξi}\{\xi _i\}的方差達到最大,方差最大其實也就體現{xi}\{x_i\}整體到β\beta的距離達到最小。β\beta一般就叫做權重函數(可以理解爲"座標軸"單位長度量)。

我們管各個函數到β\beta上的投影叫做觀測曲線的主成分得分:
ξi=Tβ(s)xi(s)ds,i=1,,n\xi_{i}=\int_{\mathcal{T}} \beta(s) x_{i}(s) d s, \quad i=1, \cdots, n故而,求解第一個主成分就變成了求解一個優化問題:
max1ni=1nξi2=max1ni=1n(Tβ(s)xi(s)ds)2 s.t. β2=Tβ(s)β(s)ds=1\begin{aligned} \max \frac{1}{n} \sum_{i=1}^{n} \xi_{i}^{2} &=\max \frac{1}{n} \sum_{i=1}^{n}\left(\int_{\mathcal{T}} \beta(s) x_{i}(s) d s\right)^{2} \\ \text { s.t. } &\|\beta\|^{2}=\int_{T} \beta(s) \beta(s) d s=1 \end{aligned}求解這個優化問題,我們就得到了第一主成分β1(s)\beta^1(s)
kk主成分無非就是在滿足和前面k1k-1個主成分權重函數垂直的基礎上,求解上述優化問題而已,即求解
max1ni=1nξi2=max1ni=1n(Tβ(s)xi(s)ds)2 s.t. β2=Tβ(s)β(s)ds=1Tβ(s)βl(s)ds=0,l=1,,k1\begin{array}{l}{\max \frac{1}{n} \sum_{i=1}^{n} \xi_{i}^{2}=\max \frac{1}{n} \sum_{i=1}^{n}\left(\int_{\mathcal{T}} \beta(s) x_{i}(s) d s\right)^{2}} \\ {\text { s.t. }\|\beta\|^{2}=\int_{T} \beta(s) \beta(s) d s=1} \\ {\int_{T} \beta(s) \beta^{l}(s) d s=0, l=1, \cdots, k-1}\end{array}
這個優化問題的解可以表述如下。記協方差函數:
v(s,t)=1n1i=1n(xi(s)x(s))(xi(t)x(t))v(s, t)=\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{i}(s)-\overline{x}(s)\right)\left(x_{i}(t)-\overline{x}(t)\right)
那麼權重函數滿足特徵方程:
Tv(s,t)β(t)dt=λβ(s)\int_{\mathcal{T}} v(s, t) \beta(t) d t=\lambda \beta(s)
定義積分變換: Vβ(s)=Tv(s,t)β(t)dtV \beta(s)=\int_{\mathcal{T}} v(s, t) \beta(t) d t
這裏的VV稱爲協方差算子,它將函數β\beta變成一個函數。那麼,我們有:
Vβ(s)=λβ(s)V \beta(s)=\lambda \beta(s)
我們也類比PCA,使用特徵值的累積貢獻率來衡量主成分所佔比例:
FVE=i=1Kλi/i=1n1λi\mathrm{FVE}=\sum_{i=1}^{K} \lambda_{i} / \sum_{i=1}^{n-1} \lambda_{i}這裏之所以對λ\lambda只累計到nn是因爲協方差算子VV的秩爲樣本數量減一個,則非零特徵根的個數最多爲n1n-1個。
由上述已知,我們求解主成分最後歸結爲求解一個特徵值問題。
求解這個問題,目前比較流行的有三種方法:

  • 對函數進行SVD離散化

  • 對函數進行基函數展開

  • 運用一般性的數值積分方法

我們最後需要的是特徵函數,爲了避免插值而帶來更大的誤差,我選用對基函數進行展開的方法。下面簡單介紹一個對函數進行基函數展開的基本思路。
我們的樣本基函數xix_i可以通過基函數展開,如下:
Xi(s)=k=1KcikΦk(s),i=1,2,,NX_{i}(s)=\sum_{k=1}^{K} c_{i k} \Phi_{k}(s), i=1,2, \ldots, N 我們記
X=(x1,x2,,xN),Φ=(Φ1,,Φk),C=(cik)N×KX=\left(x_{1}, x_{2}, \ldots, x_{N}\right)^{\prime}, \Phi=\left(\Phi_{1}, \ldots, \Phi_{k}\right)^{\prime}, C=\left(c_{i k}\right)_{N \times K}
那麼樣本函數就可以寫爲等價的矩陣形式X=CΦX=C \Phi。那麼協方差函數就可以寫爲(假設已經標準化):
v(s,t)=1n1Φ(s)CCΦ(t)v(s, t)=\frac{1}{n-1} \Phi^{\prime}(s) C^{\prime} C \Phi(t)
定義K階對稱矩陣 W=ΦΦW=\int \Phi \Phi^{\prime}
當選擇正交基的時候,比如說正交傅里葉基,這就是一個單位矩陣。關於這個基如何選取,我們後面還會詳談。
同樣地,將特徵函數進行展開:
β(s)=k=1KbkΦk(s)=Φ(s)b\beta(s)=\sum_{k=1}^{K} b_{k} \Phi_{k}(s)=\Phi^{\prime}(s) b
將其代入 Tv(s,t)β(t)dt=λβ(s)\int_{\mathcal{T}} v(s, t) \beta(t) d t =\lambda \beta(s)
就可以得到(N=n1N=n-1):
1NΦ(s)CCWb=λΦ(s)b\frac{1}{N} \Phi^{\prime}(s) C^{\prime} C W b=\lambda \Phi^{\prime}(s) b
進一步能得到1NCCWb=λb\frac{1}{N} C^{\prime} C W b=\lambda b,由特徵向量正交和單位長度的約束要求,有bkWbk=1,bkWbm=0,kmb_{k}^{\prime} W b_{k}=1, b_{k}^{\prime} W b_{m}=0,k \neq m
WW做cholesky分解,可得W=LLW=LL'
定義u=Lbu=L'b,那麼上述問題就變成了對稱矩陣的代數特徵值問題:
1NLCCLu=λu\frac{1}{N} L' C^{\prime} C L u=\lambda u
據此可以求得uu,進而求得bb,最後求得特徵函數β\beta

常用的基函數有傅里葉基函數和B樣條基函數,傅里葉基函數適用於週期性函數數據,B樣條基函數適用於非週期函數數據,當然,也可以用多項式基函數。
B樣條基函數的遞歸定義爲:
Bj,0(x)={1,tjx<tj+10,elseBi,k(x)=xtiti+ktiBi,k1(x)+ti+k+1xti+k+1ti+1Bi+1,k1(x),k>0\begin{array}{c}{B_{j, 0}(x)=\left\{\begin{array}{l}{1, t_{j} \leq x<t_{j+1}} \\ {0, \text {else}}\end{array}\right.} \\ {B_{i, k}(x)=\frac{x-t_{i}}{t_{i+k}-t_{i}} B_{i, k-1}(x)+\frac{t_{i+k+1}-x}{t_{i+k+1}-t_{i+1}} B_{i+1, k-1}(x), k>0}\end{array}
附錄中有一段簡單的以多項式爲基的MATLAB代碼。

FPCA和PCA的區別和聯繫

如上所述,可以看出,如果所選的基函數是正交的,本質上和PCA的以擬合係數爲座標點的函數空間PCA推廣是實際上是一樣的。若基函數不是正交的,無非就是在此基礎上對要求特徵值的矩陣得多乘一個W=ΦΦW=\int \Phi \Phi^{\prime},再求特徵向量,以及進行WW意義下對特徵向量進行單位化而已(不單位化也沒事,只不過權重函數β\beta不再是模長爲1的而已,WW意義下的單位話也就意味着讓新的基函數模長爲1)。這個也非常容易理解,因爲在從函數的元(primal)表示左乘一個質量矩陣就到了到它的對偶(dual)表示,而在基函數不正交的情況下,我們應該在對偶空間中再進行它的主成分分析降維,即各個函數的向量表示應該爲這個函數和各個基函數的內積。同理,在對偶框架下得到的新的基函數的向量表示也是在對偶空間下的,應該左乘一個質量矩陣才能回到元空間中去。

基於FPCA的模型約化

Onsager原理簡介

Onsager基本原理是基於物理規律的一個原理,利用它不難得到,如果刻畫物理過程的模型方程有哪些項知道了,也就是基函數知道了,那麼我們可以通過這個原理求得各個項前面的係數。
定義勢能函數(自由能): A(a)A(a) 定義能量耗散函數:
Φ(a˙,a)=12i,jζij(a)a˙ia˙j\Phi(\dot{a}, a)=\frac{1}{2} \sum_{i, j} \zeta_{i j}(a) \dot{a}_{i} \dot{a}_{j}
那麼系統隨時間演化由最小化以下函數得到:
R(a˙,a)=Φ(a˙,a)+iAaia˙iR(\dot{a}, a)=\Phi(\dot{a}, a)+\sum_{i} \frac{\partial A}{\partial a_{i}} \dot{a}_{i}
最小化RR,可以得到:
Φa˙i+Aai=0 or jζij(a)a˙j=Aai\frac{\partial \Phi}{\partial \dot{a}_{i}}+\frac{\partial A}{\partial a_{i}}=0 \quad \text { or } \quad \sum_{j} \zeta_{i j}(a) \dot{a}_{j}=-\frac{\partial A}{\partial a_{i}}
這就是我們要求解的ODE系統。

簡單例子:斜板液滴滑動

問題描述

考慮一個液滴在斜板上從靜止開始下滑,如圖。
在這裏插入圖片描述
從正面或者側面拍攝到的圖案大概如圖。
在這裏插入圖片描述
我們現在想要刻畫這個液滴的狀態,即在每一時刻液滴的俯視形狀以及側視高度。
我們可以用一個方程來描述這個過程:
h(x,y,t)=H(x,t)[1(yY(x,t))2]h(x, y, t)=H(x, t)\left[1-\left(\frac{y}{Y(x, t)}\right)^{2}\right]
其中xx爲平行平板沿着液滴運動的方向,yy爲平行平板垂直於液滴運動的方向,tt爲時刻,hh爲垂直於平板距離平板的一個高度。這裏面的HYH、Y是兩個函數,分別刻畫了俯視的形狀和側視的形狀。事實上,取h=0h=0,可以得到y=Y(x,t)y=Y(x,t)描述了俯視圖(垂直於板)的形狀(一半),取y=0y=0,得到h=H(x,t)h=H(x,t),體現的是側視圖。再者,若給定了xx值,高度隨着yy是呈現出拋物的變化。因此,這個公式看起來不無道理。
接下來,我們對H,YH,Y做一個簡單的假定:
H(x,t)=(xa1(t))(a2(t)x)(a3(t)+a4(t)x)Y(x,t)=(xa1(t))12(a2(t)x)12(a5(t)+a6(t)x)\begin{array}{c}{H(x, t)=\left(x-a_{1}(t)\right)\left(a_{2}(t)-x\right)\left(a_{3}(t)+a_{4}(t) x\right)} \\ {Y(x, t)=\left(x-a_{1}(t)\right)^{\frac{1}{2}}\left(a_{2}(t)-x\right)^{\frac{1}{2}}\left(a_{5}(t)+a_{6}(t) x\right)}\end{array}
容易想到,這裏的a1(t),a2(t)a_1(t),a_2(t)表示的是液滴的前後端點(採用歐拉座標系),因爲H,YH,Y在兩端點處的值爲零。

原理的應用

我們希望能通過上面提到的Onsager原理來確定這裏的係數aia_i
固定時刻的液滴體積:
Ω=a1a2dxYYdyh(x,y,t)\Omega=\int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y h(x, y, t)
因爲體積是守恆量,所以問題的自由度個數就變成了5。 勢能函數定義爲:
A(a)=a1a2dxYYdy[12γθe2+12γ[(xh)2+(yh)2]+12ρgh2sinαρgxhcosα]\begin{aligned} A(a)=& \int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y\left[\frac{1}{2} \gamma \theta_{e}^{2}+\frac{1}{2} \gamma\left[\left(\partial_{x} h\right)^{2}+\left(\partial_{y} h\right)^{2}\right]\right.\\ &+\frac{1}{2} \rho g h^{2} \sin \alpha-\rho g x h \cos \alpha ] \end{aligned}
這裏的γ\gamma表示液滴的表面張力,ρ\rho表示密度,θe\theta_e是平衡態下的接觸角大小,gg是重力加速度,α\alpha是前面提到的斜面角。我也不知道勢能函數爲什麼能寫成這樣,需要一些物理的分析。
可以把hh的表達式代入到這個勢能函數的表達式中。我們還需要知道能量耗散函數Φ\Phi。由滑潤近似,能量耗散函數可以寫成關於速度的變量:
Φ[vx,vy]=12a1a2dxYYdy3ηh(vx2+vy2)\Phi\left[v_{x}, v_{y}\right]=\frac{1}{2} \int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y \frac{3 \eta}{h}\left(v_{x}^{2}+v_{y}^{2}\right)
這裏的vx,vyv_x,v_y表示兩個方向上的速度,η\eta表示流體的粘性。但是我們想要的耗散函數是關於a˙\dot a
的,所以要想辦法替換掉速度。 由體積守恆,我們有:
h˙=x(vxh)y(vyh)\dot{h}=-\partial_{x}\left(v_{x} h\right)-\partial_{y}\left(v_{y} h\right)
hh的表達式代入上式,可得:
(1y2Y2)(H˙+x(vxH)+Hyvy)+2HyY3(yY˙+yvxxYYvy)=0\begin{array}{c}{\left(1-\frac{y^{2}}{Y^{2}}\right)\left(\dot{H}+\partial_{x}\left(v_{x} H\right)+H \partial_{y} v_{y}\right)} \\ {+\frac{2 H y}{Y^{3}}\left(y \dot{Y}+y v_{x} \partial_{x} Y-Y v_{y}\right)=0}\end{array}
這個約束滿足的一個充分條件是:
H˙+x(vxH)+Hyvy=0yY˙+yvxxYYvy=0\begin{array}{l}{\dot{H}+\partial_{x}\left(v_{x} H\right)+H \partial_{y} v_{y}=0} \\ {y \dot{Y}+y v_{x} \partial_{x} Y-Y v_{y}=0}\end{array}
一個如下所示的速度場能夠滿足這樣的條件:
vx(x,y,t)=V(x,t),vy(x,y,t)=W(x,t)yv_{x}(x, y, t)=V(x, t), \quad v_{y}(x, y, t)=W(x, t) y
其中,V,WV,W的表達爲:
V(x,t)=1HYa1x(H˙Y+HY˙)dxW=1Y(Y˙+VxY)\begin{aligned} V(x, t) &=-\frac{1}{H Y} \int_{a_{1}}^{x}(\dot{H} Y+H \dot{Y}) d x \\ W &=\frac{1}{Y}\left(\dot{Y}+V \partial_{x} Y\right) \end{aligned}
那麼,我們得到的能量耗散函數其實是:
Φ[a˙,a]=12a1a2dxYYdy3ηh(V2+y2W2)\Phi\left[\dot a, a\right]=\frac{1}{2} \int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y \frac{3 \eta}{h}\left(V^{2}+{y}^{2}W^2\right)
我們把aa看成常量,由於H˙,Y˙\dot H,\dot Ya˙\dot a的線性組合,意味着V,WV,W也是,那麼Φ\Phi就是a˙\dot a的二次函數,不妨記爲:
Φ(a˙)=12i,jζija˙ia˙j\Phi(\dot{a})=\frac{1}{2} \sum_{i, j} \zeta_{i j} \dot{a}_{i} \dot{a}_{j}
這裏的ξij\xi_{ij}aa的函數。
這下有了勢能函數和能量耗散函數,我們可以得到關於aia_i的發展方程爲:
j=16ζija˙j+Aai=0\sum_{j=1}^{6} \zeta_{i j} \dot{a}_{j}+\frac{\partial A}{\partial a_{i}}=0
求解之,可得aa

算法步驟

總結一下上述的計算過程,就是:

  • 能量耗散函數:
    Φ[a˙,a]=12a1a2dxYYdy3ηh(V2+y2W2)\Phi\left[\dot a, a\right]=\frac{1}{2} \int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y \frac{3 \eta}{h}\left(V^{2}+{y}^{2}W^2\right)
    其中,
    V(x,t)=1HYa1x(H˙Y+HY˙)dxW=1Y(Y˙+VxY)\begin{aligned} V(x, t) &=-\frac{1}{H Y} \int_{a_{1}}^{x}(\dot{H} Y+H \dot{Y}) d x \\ W &=\frac{1}{Y}\left(\dot{Y}+V \partial_{x} Y\right) \end{aligned}
    h(x,y,t)=H(x,t)[1(yY(x,t))2]h(x, y, t)=H(x, t)\left[1-\left(\frac{y}{Y(x, t)}\right)^{2}\right]
    H(x,t)=(xa1(t))(a2(t)x)(a3(t)+a4(t)x)Y(x,t)=(xa1(t))12(a2(t)x)12(a5(t)+a6(t)x)\begin{array}{c}{H(x, t)=\left(x-a_{1}(t)\right)\left(a_{2}(t)-x\right)\left(a_{3}(t)+a_{4}(t) x\right)} \\ {Y(x, t)=\left(x-a_{1}(t)\right)^{\frac{1}{2}}\left(a_{2}(t)-x\right)^{\frac{1}{2}}\left(a_{5}(t)+a_{6}(t) x\right)}\end{array}

  • 由此,我們計算出Φ(a˙)\Phi(\dot a)表達式,並提取前面的線性組合的係數:
    Φ(a˙)=12i,jζija˙ia˙j\Phi(\dot{a})=\frac{1}{2} \sum_{i, j} \zeta_{i j} \dot{a}_{i} \dot{a}_{j}

  • 勢能函數:
    A(a)=a1a2dxYYdy[12γθe2+12γ[(xh)2+(yh)2]+12ρgh2sinαρgxhcosα]\begin{aligned} A(a)=& \int_{a_{1}}^{a_{2}} d x \int_{-Y}^{Y} d y\left[\frac{1}{2} \gamma \theta_{e}^{2}+\frac{1}{2} \gamma\left[\left(\partial_{x} h\right)^{2}+\left(\partial_{y} h\right)^{2}\right]\right.\\ &+\frac{1}{2} \rho g h^{2} \sin \alpha-\rho g x h \cos \alpha ] \end{aligned}

  • 求解ODE方程組(數值解),得出aa
    j=16ζija˙j+Aai=0\sum_{j=1}^{6} \zeta_{i j} \dot{a}_{j}+\frac{\partial A}{\partial a_{i}}=0

數值實驗

所用的參數如下:
η=104cP,ρ=964kgm3\eta=104 \mathrm{cP}, \rho=964 \mathrm{kg} \mathrm{m}^{-3}
γ=20.9mNm1,\gamma=20.9 \mathrm{mNm}^{-1}, θe=53\theta_{e}=53^{\circ}
Ω=6.3mm3\Omega = 6.3 \mathrm{mm}^{3} α=15,25,45\alpha=15^{\circ},25^\circ,45^\circ

下面有一些數值結果如圖。
在這裏插入圖片描述
所用的程序比較冗長,就不往本文後面貼了。

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))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章