1. 程式人生 > >[C#] 使用 Excel 和 Math.Net 進行曲線擬合和資料預測

[C#] 使用 Excel 和 Math.Net 進行曲線擬合和資料預測

以前在工作中遇到了一個數據錯誤的問題,順便寫下 用 [Math.Net](https://www.mathdotnet.com/) 解決的思路。 ## 1. 錯誤的資料 ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103132349601-1590932660.png) 上圖是同一組探測器在同一天採集到的 19 次資料,總體來說重複性不錯,但很明顯最後 8 個探測器出了問題,導致採集到的資料在最後八個點一片混亂。即使把其中看起來最好的一組資料拿出來使用多項式擬合,也可以看出最後幾個點沒有落在擬合曲線上(只擬合最後 14 個點): ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103150114506-421520061.png) 雖然我知道這是硬體問題,但是**遇到事情不能坐以待斃**,軟體方面也許可以做些什麼。既然我從上圖中得知出了最後幾個點之外,其它資料都在擬合曲線上,那我可以使用前面幾個點的擬合結果預測後面幾個點並替換掉出錯的資料,從而得到一組看起來正常的資料。 ## 2. 曲線擬合與資料預測 曲線擬合(curve fitting)是指選擇適當的曲線型別來擬合觀測資料,以便觀察兩組資料之間的內在聯絡,瞭解資料之間的變化趨勢。 在資料分析時,我們有時需要通過已有資料來預測未來資料。在一些複雜的資料模型中,資料維度很多,資料之間的關係很複雜,我們可能會用到深度學習的演算法。但是在一些簡單的資料模型中,資料之間有很明顯的相關性,那我們就可以使用簡單的曲線擬合來預測未來的資料。 這些工作都可以使用 Excel 完成,先來嘗試一下。把某組資料最後14個點(只選取峰值右邊的14個點是因為容易計算)放進Excel中,插入一個散點圖,右鍵點選其中的藍色散點,選擇`新增趨勢線`: ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103150823211-708970034.png) 然後在右側出現的`設定趨勢線格式`中選擇`多項式`,階數為 3,勾選`顯示公式`: ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103132425872-1484095861.png) 可以看到,曲線圖中出現了一條虛線的曲線,並顯示了對應的公式為 y = 6E-07x^3^ + 0.0002x^2^ - 0.0072x + 0.0637: ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103132451456-662217764.png) 如果需要預測資料,可以修改`前推`數字以得到後面幾個週期的資料。 ## 3. 使用 Math.Net 進行曲線擬合 當然我不可能對每一條資料都扔進 Excel 裡進行擬合。在 C# 中我們可以使用 [Math.Net](https://www.mathdotnet.com/) 進行非線性擬合。 [Math.Net](https://www.mathdotnet.com/) 是一個開源專案,旨在構建和維護涵蓋基礎數學的工具箱,以滿足 .Net 開發人員的高階需求和日常需求。其中 [Math.NET Numerics](https://numerics.mathdotnet.com/) 旨在為科學、工程和日常使用中的數值計算提供方法和演算法。涵蓋的主題包括特殊函式,線性代數,概率模型,隨機數,插值,積分變換等等。 要使用 [Math.NET Numerics](https://numerics.mathdotnet.com/),首先安裝它的 Nuget 包: ``` Install-Package MathNet.Numerics ``` [Math.NET Numerics](https://numerics.mathdotnet.com/) 提供了 `Fit.Polynomial` 函式用作多項式擬合,如以下程式碼所示,其中 `X` 是 X 軸的陣列, `Y` 是 Y 軸的陣列, 函式的第三個引數是多項式的階數,這裡用 2 作為階數。 ``` CS double[] X = Enumerable.Range(1, 6).Select(r =>
(double)r).ToArray(); double[] Y = values.ToArray(); double[] parameters = Fit.Polynomial(X, Y, 2); ``` 返回的結果是最佳擬合引數的陣列 `[p0,p1,p2,…,pk]`,將其帶入公式 p0 + p1×x + p2×x^2^ + ... + pk×x^k^ 即可算出對應的擬合數據。完整的程式碼如下,在這個示例裡,我只需要用倒數第9到14個數據,通過 `Fit.Polynomial` 獲得一個多項式的方程 ( f(x) = p0 + p1×x + p2×x^2^ ),然後用這個方程計算出後面 8 個點的資料替換原本出錯的資料: ``` CS double[] X = Enumerable.Range(1, 6).Select(r =>
(double)r).ToArray(); double[] Y = values.ToArray(); double[] parameters = Fit.Polynomial(X, Y, 2); List result = new List(); for (int i = 1; i < 15; i++) { result.Add(parameters[0] + parameters[1] * i + parameters[2] * i * i ); } for (int i = 0; i < 8; i++) { data[data.Count - 1 - i] = result[result.Count - 1 - i]; } ``` ![](https://img2020.cnblogs.com/blog/38937/202101/38937-20210103132504808-1972362365.png) 替換後的結果如上所示,整體符合前面資料的趨勢,使用這組資料進行運算也能得到很好的結果。 ## 4. 最後 [Math.Net](https://www.mathdotnet.com/) 是一個強大的專案,這篇文章只介紹了它所有功能的冰山一角。想了解更多可以參考官方文件,或參考部落格園上的文章,例如: [【目錄】開源Math.NET基礎數學類庫使用總目錄 - 資料之巔 - 部落格園](https://www.cnblogs.com/asxinyu/p/Bolg_Category_For_MathNet.html) ## 5. 參考 [Math.NET Numerics](https://numerics.mathdotnet.com/) [Curve Fitting Linear Regression](https://numerics.mathdotnet.com/Regression.html) [【目錄】開源Math.NET基礎數學類庫使用總目錄 - 資料之巔 - 部落格園](https://www.cnblogs.com/asxinyu/p/Bolg_Category_For_MathNet.html) [資料預測與曲線擬合 - 知乎](https://zhuanlan.zhihu.com/p/95277637) ## 6. 原始碼