跳到主要內容

R|R 最佳化求解

趁著找工作之餘,來記錄一下碩士班期間撰寫論文時用到的一些 R 語言的函數(function)。以下並不會詳細陳列語法如何撰寫,因為我認為這些內容,還是直接去看官方文件最實在。我的重點會放在有哪函數工具可以使用,以及主要差異在哪裡?

#標準最佳化

我的碩士論文主題為「生產與存貨最佳化模型」,它是 EPQ 模型的一種延伸,簡單來說就是透過建構一個數學方程式來表示買賣雙方之間的總存貨成本。誠如本文標題所言,模型的最終目的,當然就是透過求解該數學方程式的最佳解、與取得模型當中的最小化成本,以及相對應的最佳生產週期。

傳統的 EPQ 模型,是針對方程式的特定變數進行一次偏微分,再令微分後的方程式等號右邊為零以求取該方程式的根;並且再對方程二次偏微分,從方程式的結果大於零或小於零來判斷,將一階微分求取出來的根帶入原方程式之後會是最小值還是最大值。這套流程也是最常見的方程式最佳化求解的做法之一。

方程式推導的部分,無論是人為進行、或者是透過能夠進行符號運算的軟體都好。而由於我的碩士論文模型參數符號較多且雜,於是,我透過 Wolfram|Alpha 先進行符號運算。Wolfram|Alpha 是功能強大的數學及符號運算軟體,免付費的網頁版即可進行複雜的符號運算。透過 Wolfram|Alpha 取得一階微分後的方程式,再來就是求取方程式的根。

#根的求解

對於一般較簡單的線性方程式的根的求解,R 語言的基礎套件 {stats} 當中,便有 uniroot 這項函數可以求解方程式的根。但我的碩士論文模型是屬於非線性方程,雖然透過 uniroot 一樣能獲取到一個解,但是所求取出來的根,離我們理想中的方程式最小值,仍有些微差距。

而使用 R 語言求解非線性方程式的根,就可以使用 {rootSolve} 套件當中的 multiroot 函數來達成,其回傳的結果也十分簡潔,除了求解到的根之外,還會包含將根帶入之後的方程式的值、迭代次數。

#最佳化函數

上面提到的都是針對方程式的根的求解。但該流程主要是我們採用了一次偏微分的最佳化流程,且已取得一階微分後的方程式。若是要直接對原方程式求解最佳值(包含最大值與最小值),則可以使用內建於 {stats} 基礎套件當中的 optimize 這項函數。optimize 的應用非常簡潔且直觀,只要帶入欲求解的方程式,並給定最佳解的範圍即可。回傳的值包含在給定範圍內的最佳解、以及對應的方程式的變數數值。

然而,如同 uniroot 一樣,optimize 是針對一次方程式(One Dimensional)設計的最佳化函數,若是要對多次方程式(Multi-Dimensional)的方程式進行最佳化求解,則可以使用 {nleqslv} 這項套件,以及其同名的函數 nleqslv。nleqslv在使用上也非常簡單,而且其可以根據使用者的需求來調整要採用 "Newton" 方法、抑或是"Broyden"方法來搜尋最佳解的值、還有相關細部條件設定等等。對於高次方程式的最佳化求解、以及熟悉最佳化演算法理論的使用者而言,nleqslv 是一項好用的工具。

如果 nleqslv 還無法滿足您的需求。那麼您可以在考慮使用 {BurStMisc} 套件當中 genopt 函數,其是一個基於遺傳演算法、以及模擬退火法的最佳化函數。其函數的參數設定較多,其運算時所需要的時間明顯較久、回傳的資訊量相當多,使用者需要再一一去找尋自己所需要的結果,同樣是適合熟悉最佳化演算法理論較的使用者。

至於,哪一套最佳化的 package 是最好的?這當然看情況,以及看使用者需求。如果你的方程式沒有太複雜,其實使用基礎套件的 optimize 就可以獲得良好的結果。
以我自己的論文而言,我使用標準最佳化流程並搭配 {rootSolve} 套件當中的 multiroot 函數,所求出來的結果是最優的,比起 {nleqslv} 或者 {BurStMisc} 所求出來的解都還要好(但這當中的誤差,只有小數點的幾位數)。
參考資源: