A. python 求解線性方程
問題有問題吧,不過我把應該做的過程給你。跡卜
# 結果
r = []
# 步長
step = 0.00000000001
# 初始化x
x = step
while x < 10:
# 計算y
y = 0.5 * (10 - x)
# 判斷符合條件的x, y
if y - x - 0.1 >= 0 and x - y - 0.5 >= 0:
r.append((x, y))
x += step
結果
設置步長,步長姿鏈穗越小越精準。
先把方程轉換一下 10*x+20*y=100 -> y = 0.5 * (10 - x)
題中,y >喚念 0, 所以 10 - x > 0, 所以 x < 10, 遍歷 0 < x < 10。記錄所有符合條件的x,y
B. 萬字教你如何用 Python 實現線性規劃
想像一下,您有一個線性方程組和不等式系統。這樣的系統通常有許多可能的解決方案。線性規劃是一組數學和計算工具,可讓您找到該系統的特定解,該解對應於某些其他線性函數的最大值或最小值。
混合整數線性規劃是 線性規劃 的擴展。它處理至少一個變數採用離散整數而不是連續值的問題。盡管乍一看混合整數問題與連續變數問題相似,但它們在靈活性和精度方面具有顯著優勢。
整數變數對於正確表示自然用整數表示的數量很重要,例如生產的飛機數量或服務的客戶數量。
一種特別重要的整數變數是 二進制變數 。它只能取 零 或 一 的值,在做出是或否的決定時很有用,例如是否應該建造工廠或者是否應該打開或關閉機器。您還可以使用它們來模擬邏輯約束。
線性規劃是一種基本的優化技術,已在科學和數學密集型領域使用了數十年。它精確、相對快速,適用於一系列實際應用。
混合整數線性規劃允許您克服線性規劃的許多限制。您可以使用分段線性函數近似非線性函數、使用半連續變數、模型邏輯約束等。它是一種計算密集型工具,但計算機硬體和軟體的進步使其每天都更加適用。
通常,當人們試圖制定和解決優化問題時,第一個問題是他們是否可以應用線性規劃或混合整數線性規劃。
以下文章說明了線性規劃和混合整數線性規劃的一些用例:
隨著計算機能力的增強、演算法的改進以及更多用戶友好的軟體解決方案的出現,線性規劃,尤其是混合整數線性規劃的重要性隨著時間的推移而增加。
解決線性規劃問題的基本方法稱為,它有多種變體。另一種流行的方法是。
混合整數線性規劃問題可以通過更復雜且計算量更大的方法來解決,例如,它在幕後使用線性規劃。這種方法的一些變體是,它涉及使用 切割平面 ,以及。
有幾種適用於線性規劃和混合整數線性規劃的合適且眾所周知的 Python 工具。其中一些是開源的,而另一些是專有的。您是否需要免費或付費工具取決於問題的規模和復雜性,以及對速度和靈活性的需求。
值得一提的是,幾乎所有廣泛使用的線性規劃和混合整數線性規劃庫都是以 Fortran 或 C 或 C++ 原生和編寫的。這是因為線性規劃需要對(通常很大)矩陣進行計算密集型工作。此類庫稱為求解器。Python 工具只是求解器的包裝器。
Python 適合圍繞本機庫構建包裝器,因為它可以很好地與 C/C++ 配合使用。對於本教程,您不需要任何 C/C++(或 Fortran),但如果您想了解有關此酷功能的更多信息,請查看以下資源:
基本上,當您定義和求解模型時,您使用 Python 函數或方法調用低級庫,該庫執行實際優化工作並將解決方案返回給您的 Python 對象。
幾個免費的 Python 庫專門用於與線性或混合整數線性規劃求解器交互:
在本教程中,您將使用SciPy和PuLP來定義和解決線性規劃問題。
在本節中,您將看到線性規劃問題的兩個示例:
您將在下一節中使用 Python 來解決這兩個問題。
考慮以下線性規劃問題:
你需要找到X和Ÿ使得紅色,藍色和黃色的不平等,以及不平等X 0和ÿ 0,是滿意的。同時,您的解決方案必須對應於z的最大可能值。
您需要找到的自變數(在本例中為 x 和 y )稱為 決策變數 。要最大化或最小化的決策變數的函數(在本例中為 z) 稱為 目標函數 、 成本函數 或僅稱為 目標 。您需要滿足的 不等式 稱為 不等式約束 。您還可以在稱為 等式約束 的約束中使用方程。
這是您如何可視化問題的方法:
紅線代表的功能2 X + Ý = 20,和它上面的紅色區域示出了紅色不等式不滿足。同樣,藍線是函數 4 x + 5 y = 10,藍色區域被禁止,因為它違反了藍色不等式。黃線是 x + 2 y = 2,其下方的黃色區域是黃色不等式無效的地方。
如果您忽略紅色、藍色和黃色區域,則僅保留灰色區域。灰色區域的每個點都滿足所有約束,是問題的潛在解決方案。該區域稱為 可行域 ,其點為 可行解 。在這種情況下,有無數可行的解決方案。
您想最大化z。對應於最大z的可行解是 最優解 。如果您嘗試最小化目標函數,那麼最佳解決方案將對應於其可行的最小值。
請注意,z是線性的。你可以把它想像成一個三維空間中的平面。這就是為什麼最優解必須在可行區域的 頂點 或角上的原因。在這種情況下,最佳解決方案是紅線和藍線相交的點,稍後您將看到。
有時,可行區域的整個邊緣,甚至整個區域,都可以對應相同的z值。在這種情況下,您有許多最佳解決方案。
您現在已准備好使用綠色顯示的附加等式約束來擴展問題:
方程式 x + 5 y = 15,以綠色書寫,是新的。這是一個等式約束。您可以通過向上一張圖像添加相應的綠線來將其可視化:
現在的解決方案必須滿足綠色等式,因此可行區域不再是整個灰色區域。它是綠線從與藍線的交點到與紅線的交點穿過灰色區域的部分。後一點是解決方案。
如果插入x的所有值都必須是整數的要求,那麼就會得到一個混合整數線性規劃問題,可行解的集合又會發生變化:
您不再有綠線,只有沿線的x值為整數的點。可行解是灰色背景上的綠點,此時最優解離紅線最近。
這三個例子說明了 可行的線性規劃問題 ,因為它們具有有界可行區域和有限解。
如果沒有解,線性規劃問題是 不可行的 。當沒有解決方案可以同時滿足所有約束時,通常會發生這種情況。
例如,考慮如果添加約束x + y 1會發生什麼。那麼至少有一個決策變數(x或y)必須是負數。這與給定的約束x 0 和y 0相沖突。這樣的系統沒有可行的解決方案,因此稱為不可行的。
另一個示例是添加與綠線平行的第二個等式約束。這兩行沒有共同點,因此不會有滿足這兩個約束的解決方案。
一個線性規劃問題是 無界的 ,如果它的可行區域是無界,將溶液不是有限。這意味著您的變數中至少有一個不受約束,可以達到正無窮大或負無窮大,從而使目標也無限大。
例如,假設您採用上面的初始問題並刪除紅色和黃色約束。從問題中刪除約束稱為 放鬆 問題。在這種情況下,x和y不會在正側有界。您可以將它們增加到正無窮大,從而產生無限大的z值。
在前面的部分中,您研究了一個與任何實際應用程序無關的抽象線性規劃問題。在本小節中,您將找到與製造業資源分配相關的更具體和實用的優化問題。
假設一家工廠生產四種不同的產品,第一種產品的日產量為x ₁,第二種產品的產量為x 2,依此類推。目標是確定每種產品的利潤最大化日產量,同時牢記以下條件:
數學模型可以這樣定義:
目標函數(利潤)在條件 1 中定義。人力約束遵循條件 2。對原材料 A 和 B 的約束可以從條件 3 和條件 4 中通過對每種產品的原材料需求求和得出。
最後,產品數量不能為負,因此所有決策變數必須大於或等於零。
與前面的示例不同,您無法方便地將其可視化,因為它有四個決策變數。但是,無論問題的維度如何,原理都是相同的。
在本教程中,您將使用兩個Python 包來解決上述線性規劃問題:
SciPy 設置起來很簡單。安裝後,您將擁有開始所需的一切。它的子包 scipy.optimize 可用於線性和非線性優化。
PuLP 允許您選擇求解器並以更自然的方式表述問題。PuLP 使用的默認求解器是COIN-OR Branch and Cut Solver (CBC)。它連接到用於線性鬆弛的COIN-OR 線性規劃求解器 (CLP)和用於切割生成的COIN-OR 切割生成器庫 (CGL)。
另一個偉大的開源求解器是GNU 線性規劃工具包 (GLPK)。一些著名且非常強大的商業和專有解決方案是Gurobi、CPLEX和XPRESS。
除了在定義問題時提供靈活性和運行各種求解器的能力外,PuLP 使用起來不如 Pyomo 或 CVXOPT 等替代方案復雜,後者需要更多的時間和精力來掌握。
要學習本教程,您需要安裝 SciPy 和 PuLP。下面的示例使用 SciPy 1.4.1 版和 PuLP 2.1 版。
您可以使用pip以下方法安裝兩者:
您可能需要運行pulptest或sudo pulptest啟用 PuLP 的默認求解器,尤其是在您使用 Linux 或 Mac 時:
或者,您可以下載、安裝和使用 GLPK。它是免費和開源的,適用於 Windows、MacOS 和 Linux。在本教程的後面部分,您將看到如何將 GLPK(除了 CBC)與 PuLP 一起使用。
在 Windows 上,您可以下載檔案並運行安裝文件。
在 MacOS 上,您可以使用 Homebrew:
在 Debian 和 Ubuntu 上,使用apt來安裝glpk和glpk-utils:
在Fedora,使用dnf具有glpk-utils:
您可能還會發現conda對安裝 GLPK 很有用:
安裝完成後,可以查看GLPK的版本:
有關詳細信息,請參閱 GLPK 關於使用Windows 可執行文件和Linux 軟體包進行安裝的教程。
在本節中,您將學習如何使用 SciPy優化和求根庫進行線性規劃。
要使用 SciPy 定義和解決優化問題,您需要導入scipy.optimize.linprog():
現在您已經linprog()導入,您可以開始優化。
讓我們首先解決上面的線性規劃問題:
linprog()僅解決最小化(而非最大化)問題,並且不允許具有大於或等於符號 ( ) 的不等式約束。要解決這些問題,您需要在開始優化之前修改您的問題:
引入這些更改後,您將獲得一個新系統:
該系統與原始系統等效,並且將具有相同的解決方案。應用這些更改的唯一原因是克服 SciPy 與問題表述相關的局限性。
下一步是定義輸入值:
您將上述系統中的值放入適當的列表、元組或NumPy 數組中:
注意:請注意行和列的順序!
約束左側和右側的行順序必須相同。每一行代表一個約束。
來自目標函數和約束左側的系數的順序必須匹配。每列對應一個決策變數。
下一步是以與系數相同的順序定義每個變數的界限。在這種情況下,它們都在零和正無窮大之間:
此語句是多餘的,因為linprog()默認情況下採用這些邊界(零到正無窮大)。
註:相反的float("inf"),你可以使用math.inf,numpy.inf或scipy.inf。
最後,是時候優化和解決您感興趣的問題了。你可以這樣做linprog():
參數c是指來自目標函數的系數。A_ub和b_ub分別與不等式約束左邊和右邊的系數有關。同樣,A_eq並b_eq參考等式約束。您可以使用bounds提供決策變數的下限和上限。
您可以使用該參數method來定義要使用的線性規劃方法。有以下三種選擇:
linprog() 返回具有以下屬性的數據結構:
您可以分別訪問這些值:
這就是您獲得優化結果的方式。您還可以以圖形方式顯示它們:
如前所述,線性規劃問題的最優解位於可行區域的頂點。在這種情況下,可行區域只是藍線和紅線之間的綠線部分。最優解是代表綠線和紅線交點的綠色方塊。
如果要排除相等(綠色)約束,只需刪除參數A_eq並b_eq從linprog()調用中刪除:
解決方案與前一種情況不同。你可以在圖表上看到:
在這個例子中,最優解是紅色和藍色約束相交的可行(灰色)區域的紫色頂點。其他頂點,如黃色頂點,具有更高的目標函數值。
您可以使用 SciPy 來解決前面部分所述的資源分配問題:
和前面的例子一樣,你需要從上面的問題中提取必要的向量和矩陣,將它們作為參數傳遞給.linprog(),然後得到結果:
結果告訴您最大利潤是1900並且對應於x ₁ = 5 和x ₃ = 45。在給定條件下生產第二和第四個產品是沒有利潤的。您可以在這里得出幾個有趣的結論:
opt.statusis0和opt.successis True,說明優化問題成功求解,最優可行解。
SciPy 的線性規劃功能主要用於較小的問題。對於更大和更復雜的問題,您可能會發現其他庫更適合,原因如下:
幸運的是,Python 生態系統為線性編程提供了幾種替代解決方案,這些解決方案對於更大的問題非常有用。其中之一是 PuLP,您將在下一節中看到它的實際應用。
PuLP 具有比 SciPy 更方便的線性編程 API。您不必在數學上修改您的問題或使用向量和矩陣。一切都更干凈,更不容易出錯。
像往常一樣,您首先導入您需要的內容:
現在您已經導入了 PuLP,您可以解決您的問題。
您現在將使用 PuLP 解決此系統:
第一步是初始化一個實例LpProblem來表示你的模型:
您可以使用該sense參數來選擇是執行最小化(LpMinimize或1,這是默認值)還是最大化(LpMaximize或-1)。這個選擇會影響你的問題的結果。
一旦有了模型,就可以將決策變數定義為LpVariable類的實例:
您需要提供下限,lowBound=0因為默認值為負無窮大。該參數upBound定義了上限,但您可以在此處省略它,因為它默認為正無窮大。
可選參數cat定義決策變數的類別。如果您使用的是連續變數,則可以使用默認值"Continuous"。
您可以使用變數x和y創建表示線性表達式和約束的其他 PuLP 對象:
當您將決策變數與標量相乘或構建多個決策變數的線性組合時,您會得到一個pulp.LpAffineExpression代表線性表達式的實例。
注意:您可以增加或減少變數或表達式,你可以乘他們常數,因為紙漿類實現一些Python的特殊方法,即模擬數字類型一樣__add__(),__sub__()和__mul__()。這些方法用於像定製運營商的行為+,-和*。
類似地,您可以將線性表達式、變數和標量與運算符 ==、=以獲取表示模型線性約束的紙漿.LpConstraint實例。
註:也有可能與豐富的比較方法來構建的約束.__eq__(),.__le__()以及.__ge__()定義了運營商的行為==,=。
考慮到這一點,下一步是創建約束和目標函數並將它們分配給您的模型。您不需要創建列表或矩陣。只需編寫 Python 表達式並使用+=運算符將它們附加到模型中:
在上面的代碼中,您定義了包含約束及其名稱的元組。LpProblem允許您通過將約束指定為元組來向模型添加約束。第一個元素是一個LpConstraint實例。第二個元素是該約束的可讀名稱。
設置目標函數非常相似:
或者,您可以使用更短的符號:
現在您已經添加了目標函數並定義了模型。
注意:您可以使用運算符將 約束或目標附加到模型中,+=因為它的類LpProblem實現了特殊方法.__iadd__(),該方法用於指定 的行為+=。
對於較大的問題,lpSum()與列表或其他序列一起使用通常比重復+運算符更方便。例如,您可以使用以下語句將目標函數添加到模型中:
它產生與前一條語句相同的結果。
您現在可以看到此模型的完整定義:
模型的字元串表示包含所有相關數據:變數、約束、目標及其名稱。
注意:字元串表示是通過定義特殊方法構建的.__repr__()。有關 的更多詳細信息.__repr__(),請查看Pythonic OOP 字元串轉換:__repr__vs__str__ .
最後,您已准備好解決問題。你可以通過調用.solve()你的模型對象來做到這一點。如果要使用默認求解器 (CBC),則不需要傳遞任何參數:
.solve()調用底層求解器,修改model對象,並返回解決方案的整數狀態,1如果找到了最優解。有關其餘狀態代碼,請參閱LpStatus[]。
你可以得到優化結果作為 的屬性model。該函數value()和相應的方法.value()返回屬性的實際值:
model.objective持有目標函數model.constraints的值,包含鬆弛變數的值,以及對象x和y具有決策變數的最優值。model.variables()返回一個包含決策變數的列表:
如您所見,此列表包含使用 的構造函數創建的確切對象LpVariable。
結果與您使用 SciPy 獲得的結果大致相同。
注意:注意這個方法.solve()——它會改變對象的狀態,x並且y!
您可以通過調用查看使用了哪個求解器.solver:
輸出通知您求解器是 CBC。您沒有指定求解器,因此 PuLP 調用了默認求解器。
如果要運行不同的求解器,則可以將其指定為 的參數.solve()。例如,如果您想使用 GLPK 並且已經安裝了它,那麼您可以solver=GLPK(msg=False)在最後一行使用。請記住,您還需要導入它:
現在你已經導入了 GLPK,你可以在裡面使用它.solve():
該msg參數用於顯示來自求解器的信息。msg=False禁用顯示此信息。如果要包含信息,則只需省略msg或設置msg=True。
您的模型已定義並求解,因此您可以按照與前一種情況相同的方式檢查結果:
使用 GLPK 得到的結果與使用 SciPy 和 CBC 得到的結果幾乎相同。
一起來看看這次用的是哪個求解器:
正如您在上面用突出顯示的語句定義的那樣model.solve(solver=GLPK(msg=False)),求解器是 GLPK。
您還可以使用 PuLP 來解決混合整數線性規劃問題。要定義整數或二進制變數,只需傳遞cat="Integer"或cat="Binary"到LpVariable。其他一切都保持不變:
在本例中,您有一個整數變數並獲得與之前不同的結果:
Nowx是一個整數,如模型中所指定。(從技術上講,它保存一個小數點後為零的浮點值。)這一事實改變了整個解決方案。讓我們在圖表上展示這一點:
如您所見,最佳解決方案是灰色背景上最右邊的綠點。這是兩者的最大價值的可行的解決方案x和y,給它的最大目標函數值。
GLPK 也能夠解決此類問題。
現在你可以使用 PuLP 來解決上面的資源分配問題:
定義和解決問題的方法與前面的示例相同:
在這種情況下,您使用字典 x來存儲所有決策變數。這種方法很方便,因為字典可以將決策變數的名稱或索引存儲為鍵,將相應的LpVariable對象存儲為值。列表或元組的LpVariable實例可以是有用的。
上面的代碼產生以下結果:
如您所見,該解決方案與使用 SciPy 獲得的解決方案一致。最有利可圖的解決方案是每天生產5.0第一件產品和45.0第三件產品。
讓我們把這個問題變得更復雜和有趣。假設由於機器問題,工廠無法同時生產第一種和第三種產品。在這種情況下,最有利可圖的解決方案是什麼?
現在您有另一個邏輯約束:如果x ₁ 為正數,則x ₃ 必須為零,反之亦然。這是二元決策變數非常有用的地方。您將使用兩個二元決策變數y ₁ 和y ₃,它們將表示是否生成了第一個或第三個產品:
除了突出顯示的行之外,代碼與前面的示例非常相似。以下是差異:
這是解決方案:
事實證明,最佳方法是排除第一種產品而只生產第三種產品。
就像有許多資源可以幫助您學習線性規劃和混合整數線性規劃一樣,還有許多具有 Python 包裝器的求解器可用。這是部分列表:
其中一些庫,如 Gurobi,包括他們自己的 Python 包裝器。其他人使用外部包裝器。例如,您看到可以使用 PuLP 訪問 CBC 和 GLPK。
您現在知道什麼是線性規劃以及如何使用 Python 解決線性規劃問題。您還了解到 Python 線性編程庫只是本機求解器的包裝器。當求解器完成其工作時,包裝器返回解決方案狀態、決策變數值、鬆弛變數、目標函數等。
C. python多元線性回歸怎麼計算
1、什麼是多元線性回歸模型?
當y值的影響因素不唯一時,採用多元線性回歸模型。
y =y=β0+β1x1+β2x2+...+βnxn
例如商品的銷售額可能不電視廣告投入,收音機廣告投入,報紙廣告投入有關系,可以有 sales =β0+β1*TV+β2* radio+β3*newspaper.
2、使用pandas來讀取數據
pandas 是一個用於數據探索、數據分析和數據處理的python庫
[python]view plain
importpandasaspd
[html]view plain
<prename="code"class="python">#
data=pd.read_csv('/home/lulei/Advertising.csv')
#displaythefirst5rows
data.head()
上面代碼的運行結果:
上面顯示的結果類似一個電子表格,這個結構稱為Pandas的數據幀(data frame),類型全稱:pandas.core.frame.DataFrame.
pandas的兩個主要數據結構:Series和DataFrame:
Series類似於一維數組,它有一組數據以及一組與之相關的數據標簽(即索引)組成。
DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型。DataFrame既有行索引也有列索引,它可以被看做由Series組成的字典。
[python]view plain
#displaythelast5rows
data.tail()
只顯示結果的末尾5行
[html]view plain
#checktheshapeoftheDataFrame(rows,colums)
data.shape
查看DataFrame的形狀,注意第一列的叫索引,和資料庫某個表中的第一列類似。
(200,4)
3、分析數據
特徵:
TV:對於一個給定市場中單一產品,用於電視上的廣告費用(以千為單位)
Radio:在廣播媒體上投資的廣告費用
Newspaper:用於報紙媒體的廣告費用
響應:
Sales:對應產品的銷量
在這個案例中,我們通過不同的廣告投入,預測產品銷量。因為響應變數是一個連續的值,所以這個問題是一個回歸問題。數據集一共有200個觀測值,每一組觀測對應一個市場的情況。
注意:這里推薦使用的是seaborn包。網上說這個包的數據可視化效果比較好看。其實seaborn也應該屬於matplotlib的內部包。只是需要再次的單獨安裝。
[python]view plain
importseabornassns
importmatplotlib.pyplotasplt
#ots
sns.pairplot(data,x_vars=['TV','Radio','Newspaper'],y_vars='Sales',size=7,aspect=0.8)
plt.show()#注意必須加上這一句,否則無法顯示。
[html]view plain
這里選擇TV、Radio、Newspaper作為特徵,Sales作為觀測值
[html]view plain
返回的結果:
[python]view plain
sns.pairplot(data,x_vars=['TV','Radio','Newspaper'],y_vars='Sales',size=7,aspect=0.8,kind='reg')
plt.show()
結果顯示如下:
4、線性回歸模型
優點:快速;沒有調節參數;可輕易解釋;可理解。
缺點:相比其他復雜一些的模型,其預測准確率不是太高,因為它假設特徵和響應之間存在確定的線性關系,這種假設對於非線性的關系,線性回歸模型顯然不能很好的對這種數據建模。
線性模型表達式:y=β0+β1x1+β2x2+...+βnxn其中
y是響應
β0是截距
β1是x1的系數,以此類推
在這個案例中:y=β0+β1∗TV+β2∗Radio+...+βn∗Newspaper
(1)、使用pandas來構建X(特徵向量)和y(標簽列)
scikit-learn要求X是一個特徵矩陣,y是一個NumPy向量。
pandas構建在NumPy之上。
因此,X可以是pandas的DataFrame,y可以是pandas的Series,scikit-learn可以理解這種結構。
[python]view plain
#
feature_cols=['TV','Radio','Newspaper']
#
X=data[feature_cols]
#
X=data[['TV','Radio','Newspaper']]
#printthefirst5rows
printX.head()
#checkthetypeandshapeofX
printtype(X)
printX.shape
輸出結果如下:
[python]view plain
#selectaSeriesfromtheDataFrame
y=data['Sales']
#
y=data.Sales
#printthefirst5values
printy.head()
輸出的結果如下:
(2)、構建訓練集與測試集
[html]view plain
<prename="code"class="python"><spanstyle="font-size:14px;">##構造訓練集和測試集
fromsklearn.cross_validationimporttrain_test_split#這里是引用了交叉驗證
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=1)
#default split is 75% for training and 25% for testing
[html]view plain
printX_train.shape
printy_train.shape
printX_test.shape
printy_test.shape
輸出結果如下:
註:上面的結果是由train_test_spilit()得到的,但是我不知道為什麼我的版本的sklearn包中居然報錯:
處理方法:1、我後來重新安裝sklearn包。再一次調用時就沒有錯誤了。
2、自己寫函數來認為的隨機構造訓練集和測試集。(這個代碼我會在最後附上。)
(3)sklearn的線性回歸
[html]view plain
fromsklearn.linear_modelimportLinearRegression
linreg=LinearRegression()
model=linreg.fit(X_train,y_train)
printmodel
printlinreg.intercept_
printlinreg.coef_
輸出的結果如下:
[html]view plain
#
zip(feature_cols,linreg.coef_)
輸出如下:
y=2.668+0.0464∗TV+0.192∗Radio-0.00349∗Newspaper
如何解釋各個特徵對應的系數的意義?
對於給定了Radio和Newspaper的廣告投入,如果在TV廣告上每多投入1個單位,對應銷量將增加0.0466個單位。就是加入其它兩個媒體投入固定,在TV廣告上每增加1000美元(因為單位是1000美元),銷量將增加46.6(因為單位是1000)。但是大家注意這里的newspaper的系數居然是負數,所以我們可以考慮不使用newspaper這個特徵。這是後話,後面會提到的。
(4)、預測
[python]view plain
y_pred=linreg.predict(X_test)
printy_pred
[python]view plain
printtype(y_pred)
輸出結果如下:
5、回歸問題的評價測度
(1) 評價測度
對於分類問題,評價測度是准確率,但這種方法不適用於回歸問題。我們使用針對連續數值的評價測度(evaluation metrics)。
這里介紹3種常用的針對線性回歸的測度。
1)平均絕對誤差(Mean Absolute Error, MAE)
(2)均方誤差(Mean Squared Error, MSE)
(3)均方根誤差(Root Mean Squared Error, RMSE)
這里我使用RMES。
[python]view plain
<prename="code"class="python">#計算Sales預測的RMSE
printtype(y_pred),type(y_test)
printlen(y_pred),len(y_test)
printy_pred.shape,y_test.shape
fromsklearnimportmetrics
importnumpyasnp
sum_mean=0
foriinrange(len(y_pred)):
sum_mean+=(y_pred[i]-y_test.values[i])**2
sum_erro=np.sqrt(sum_mean/50)
#calculateRMSEbyhand
print"RMSEbyhand:",sum_erro
最後的結果如下:
(2)做ROC曲線
[python]view plain
importmatplotlib.pyplotasplt
plt.figure()
plt.plot(range(len(y_pred)),y_pred,'b',label="predict")
plt.plot(range(len(y_pred)),y_test,'r',label="test")
plt.legend(loc="upperright")#顯示圖中的標簽
plt.xlabel("thenumberofsales")
plt.ylabel('valueofsales')
plt.show()
顯示結果如下:(紅色的線是真實的值曲線,藍色的是預測值曲線)
直到這里整個的一次多元線性回歸的預測就結束了。
6、改進特徵的選擇
在之前展示的數據中,我們看到Newspaper和銷量之間的線性關系竟是負關系(不用驚訝,這是隨機特徵抽樣的結果。換一批抽樣的數據就可能為正了),現在我們移除這個特徵,看看線性回歸預測的結果的RMSE如何?
依然使用我上面的代碼,但只需修改下面代碼中的一句即可:
[python]view plain
#
feature_cols=['TV','Radio','Newspaper']
#
X=data[feature_cols]
#
#X=data[['TV','Radio','Newspaper']]#只需修改這里即可<prename="code"class="python"style="font-size:15px;line-height:35px;">X=data[['TV','Radio']]#去掉newspaper其他的代碼不變
# print the first 5 rowsprint X.head()# check the type and shape of Xprint type(X)print X.shape
最後的到的系數與測度如下:
LinearRegression(_X=True, fit_intercept=True, normalize=False)
然後再次使用ROC曲線來觀測曲線的整體情況。我們在將Newspaper這個特徵移除之後,得到RMSE變小了,說明Newspaper特徵可能不適合作為預測銷量的特徵,於是,我們得到了新的模型。我們還可以通過不同的特徵組合得到新的模型,看看最終的誤差是如何的。
備註:
之前我提到了這種錯誤:
註:上面的結果是由train_test_spilit()得到的,但是我不知道為什麼我的版本的sklearn包中居然報錯:
處理方法:1、我後來重新安裝sklearn包。再一次調用時就沒有錯誤了。
2、自己寫函數來認為的隨機構造訓練集和測試集。(這個代碼我會在最後附上。)
這里我給出我自己寫的函數:
D. 使用Python的線性回歸問題,怎麼解決
本文中,我們將進行大量的編程——但在這之前,我們先介紹一下我們今天要解決的實例問題。
1) 預測房子價格
閃電俠是一部由劇作家/製片人Greg Berlanti、Andrew Kreisberg和Geoff Johns創作,由CW電視台播放的美國電視連續劇。它基於DC漫畫角色閃電俠(Barry Allen),一個具有超人速度移動能力的裝扮奇特的打擊犯罪的超級英雄,這個角色是由Robert Kanigher、John Broome和Carmine Infantino創作。它是綠箭俠的衍生作品,存在於同一世界。該劇集的試播篇由Berlanti、Kreisberg和Johns寫作,David Nutter執導。該劇集於2014年10月7日在北美首映,成為CW電視台收視率最高的電視節目。
綠箭俠是一部由劇作家/製片人 Greg Berlanti、Marc Guggenheim和Andrew Kreisberg創作的電視連續劇。它基於DC漫畫角色綠箭俠,一個由Mort Weisinger和George Papp創作的裝扮奇特的犯罪打擊戰士。它於2012年10月10日在北美首映,與2012年末開始全球播出。主要拍攝於Vancouver、British Columbia、Canada,該系列講述了億萬花花公子Oliver Queen,由Stephen Amell扮演,被困在敵人的島嶼上五年之後,回到家鄉打擊犯罪和腐敗,成為一名武器是弓箭的神秘義務警員。不像漫畫書中,Queen最初沒有使用化名」綠箭俠「。
由於這兩個節目並列為我最喜愛的電視節目頭銜,我一直想知道哪個節目更受其他人歡迎——誰會最終贏得這場收視率之戰。 所以讓我們寫一個程序來預測哪個電視節目會有更多觀眾。 我們需要一個數據集,給出每一集的觀眾。幸運地,我從維基網路上得到了這個數據,並整理成一個.csv文件。它如下所示。
閃電俠
閃電俠美國觀眾數
綠箭俠
綠箭俠美國觀眾數
1 4.83 1 2.84
2 4.27 2 2.32
3 3.59 3 2.55
4 3.53 4 2.49
5 3.46 5 2.73
6 3.73 6 2.6
7 3.47 7 2.64
8 4.34 8 3.92
9 4.66 9 3.06
觀眾數以百萬為單位。
解決問題的步驟:
首先我們需要把數據轉換為X_parameters和Y_parameters,不過這里我們有兩個X_parameters和Y_parameters。因此,把他們命名為flash_x_parameter、flash_y_parameter、arrow_x_parameter、arrow_y_parameter吧。然後我們需要把數據擬合為兩個不同的線性回歸模型——先是閃電俠,然後是綠箭俠。 接著我們需要預測兩個電視節目下一集的觀眾數量。 然後我們可以比較結果,推測哪個節目會有更多觀眾。
步驟1
導入我們的程序包:
Python
1
2
3
4
5
6
7
# Required Packages
import csv
import sys
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn import datasets, linear_model
步驟2
寫一個函數,把我們的數據集作為輸入,返回flash_x_parameter、flash_y_parameter、arrow_x_parameter、arrow_y_parameter values。
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
# Function to get data
def get_data(file_name):
data = pd.read_csv(file_name)
flash_x_parameter = []
flash_y_parameter = []
arrow_x_parameter = []
arrow_y_parameter = []
for x1,y1,x2,y2 in zip(data['flash_episode_number'],data['flash_us_viewers'],data['arrow_episode_number'],data['arrow_us_viewers']):
flash_x_parameter.append([float(x1)])
flash_y_parameter.append(float(y1))
arrow_x_parameter.append([float(x2)])
arrow_y_parameter.append(float(y2))
return flash_x_parameter,flash_y_parameter,arrow_x_parameter,arrow_y_parameter
現在我們有了我們的參數,來寫一個函數,用上面這些參數作為輸入,給出一個輸出,預測哪個節目會有更多觀眾。
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Function to know which Tv show will have more viewers
def more_viewers(x1,y1,x2,y2):
regr1 = linear_model.LinearRegression()
regr1.fit(x1, y1)
predicted_value1 = regr1.predict(9)
print predicted_value1
regr2 = linear_model.LinearRegression()
regr2.fit(x2, y2)
predicted_value2 = regr2.predict(9)
#print predicted_value1
#print predicted_value2
if predicted_value1 > predicted_value2:
print "The Flash Tv Show will have more viewers for next week"
else:
print "Arrow Tv Show will have more viewers for next week"
把所有東西寫在一個文件中。打開你的編輯器,把它命名為prediction.py,復制下面的代碼到prediction.py中。
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Required Packages
import csv
import sys
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn import datasets, linear_model
# Function to get data
def get_data(file_name):
data = pd.read_csv(file_name)
flash_x_parameter = []
flash_y_parameter = []
arrow_x_parameter = []
arrow_y_parameter = []
for x1,y1,x2,y2 in zip(data['flash_episode_number'],data['flash_us_viewers'],data['arrow_episode_number'],data['arrow_us_viewers']):
flash_x_parameter.append([float(x1)])
flash_y_parameter.append(float(y1))
arrow_x_parameter.append([float(x2)])
arrow_y_parameter.append(float(y2))
return flash_x_parameter,flash_y_parameter,arrow_x_parameter,arrow_y_parameter
# Function to know which Tv show will have more viewers
def more_viewers(x1,y1,x2,y2):
regr1 = linear_model.LinearRegression()
regr1.fit(x1, y1)
predicted_value1 = regr1.predict(9)
print predicted_value1
regr2 = linear_model.LinearRegression()
regr2.fit(x2, y2)
predicted_value2 = regr2.predict(9)
#print predicted_value1
#print predicted_value2
if predicted_value1 > predicted_value2:
print "The Flash Tv Show will have more viewers for next week"
else:
print "Arrow Tv Show will have more viewers for next week"
x1,y1,x2,y2 = get_data('input_data.csv')
#print x1,y1,x2,y2
more_viewers(x1,y1,x2,y2)
可能你能猜出哪個節目會有更多觀眾——但運行一下這個程序看看你猜的對不對。
3) 替換數據集中的缺失值
有時候,我們會遇到需要分析包含有缺失值的數據的情況。有些人會把這些缺失值捨去,接著分析;有些人會用最大值、最小值或平均值替換他們。平均值是三者中最好的,但可以用線性回歸來有效地替換那些缺失值。
這種方法差不多像這樣進行。
首先我們找到我們要替換那一列里的缺失值,並找出缺失值依賴於其他列的哪些數據。把缺失值那一列作為Y_parameters,把缺失值更依賴的那些列作為X_parameters,並把這些數據擬合為線性回歸模型。現在就可以用缺失值更依賴的那些列預測缺失的那一列。
一旦這個過程完成了,我們就得到了沒有任何缺失值的數據,供我們自由地分析數據。
為了練習,我會把這個問題留給你,所以請從網上獲取一些缺失值數據,解決這個問題。一旦你完成了請留下你的評論。我很想看看你的結果。
個人小筆記:
我想分享我個人的數據挖掘經歷。記得在我的數據挖掘引論課程上,教師開始很慢,解釋了一些數據挖掘可以應用的領域以及一些基本概念。然後突然地,難度迅速上升。這令我的一些同學感到非常沮喪,被這個課程嚇到,終於扼殺了他們對數據挖掘的興趣。所以我想避免在我的博客文章中這樣做。我想讓事情更輕松隨意。因此我嘗試用有趣的例子,來使讀者更舒服地學習,而不是感到無聊或被嚇到。
謝謝讀到這里——請在評論框里留下你的問題或建議,我很樂意回復你。
E. python時間序列模型預測為什麼時一條直線
python時間序列模型預測時一條直線是因為是線性模型的原因。線性模型也稱作趨勢模型,它表示一個時間序列可以用一條直線來表示。它的基本等式:以一個公司的銷售總額為例,一開始的初始是5000,每隔一個時間步長增加2500。指數平滑法是時間序列分析方法中的一種。它是一種用於預測未來發展趨勢的建模演算法。它有三種不同形式:一次指數平滑法、二次指數平滑法、及三次指數平滑法。三種指數平滑法都要更新上一時間步長的計算結果,並使用當前時間步長的數據中包含的新信息。通過混合新信息和舊信息來實現。
F. python解決jacob迭代法求解線性方程組
題主好. 經典的 Jacobi 迭代演算法如下:
設 A = D - E, 則 x = D^{-1}*b + D^{-1}*E*x = C + T*x
可以參考如下代碼(復制代碼後請注意縮進):
import numpy as np
def linalg_solve_jacobi(A, b, x0, max_it, tol=1.0e-7):
# 判斷 A, b 的維數是否正確
if A.shape[0]!=A.shape[1] or A.shape[0]!= b.shape[0]:
raise Exception('A must be square or A and b must be compatible!')
D = np.diag(A)
# 判斷對角元素是否含零
if np.amin(np.absolute(D)) < 1e-14:
raise Exception('Diagonal elements of A must not be zeros!')
# 設置初始迭代步數為0
n = 0
#
# Jacobi 演算法:
# 設 A = D - E, 則 x = D^{-1}*b + D^{-1}*E*x = C + T*x
#
invD = np.diag(1.0/D) # invD is inv(D)
C = np.dot(invD,b) # C is inv(D)*b
T = np.dot(invD, np.diag(D)-A) # T is inv(D)*E
while n < max_it:
x = C + np.dot(T, x0)
if np.linalg.norm(x-x0)<tol:
break
x0[:] = x
n+=1
# 如果超過最大迭代步數, 迭代失敗
if n>max_it:
raise Exception('Failed to converge within {} steps!'.format(max_it))
# 成功, 返回
return x, n
if __name__ == "__main__":
A = np.array([[10, -1, 2, 0],[-1, 11, -1, 3],
[2, -1, 10, -1], [0, 3, -1, 8]], dtype=np.float64)
b = np.array([6, 25, -11, 15], dtype=np.float64)
x0 = np.array([0,0,0,0], dtype=np.float64)
max_it = 100
tol = 1.0e-7
x,n=linalg_solve_jacobi(A, b, x0, max_it, tol)
print(x,n)
G. 根號a-+5的最小值和a的值
梯度下降是非常常用的優化演算法。作為機器學習的基礎知識,這是一個必須要掌握的演算法。藉助本文,讓我們來一起詳細了解一下這個演算法。
前言
本文的代碼可以到我的Github上獲取:
https://github.com/paulQuei/gradient_descent
本文的演算法示例通過Python語言實現,在實現中使用到了numpy和matplotlib。如果你不熟悉這兩個工具,請自行在網上搜索教程。
關於優化
大多數學習演算法都涉及某種形式的優化。優化指的是改變x以最小化或者最大化某個函數的任務。
我們通常以最小化指代大多數最優化問題。最大化可經由最小化來實現。
我們把要最小化或最大化的函數成為目標函數(objective function)或准則(criterion)。
我們通常使用一個上標*表示最小化或最大化函數的x值,記做這樣:
[x^* = arg; min; f(x)]
優化本身是一個非常大的話題。如果有興趣,可以通過《數值優化》和《運籌學》的書籍進行學習。
模型與假設函數
所有的模型都是錯誤的,但其中有些是有用的。– George Edward Pelham Box
模型是我們對要分析的數據的一種假設,它是為解決某個具體問題從數據中學習到的,因此它是機器學習最核心的概念。
針對一個問題,通常有大量的模型可以選擇。
本文不會深入討論這方面的內容,關於各種模型請參閱機器學習的相關書籍。本文僅以最簡單的線性模型為基礎來討論梯度下降演算法。
這里我們先介紹一下在監督學習(supervised learning)中常見的三個符號:
m,描述訓練樣本的數量
x,描述輸入變數或特徵
y,描述輸出變數或者叫目標值
訓練集會包含很多的樣本,我們用 表示其中第i個樣本。
x是數據樣本的特徵,y是其目標值。例如,在預測房價的模型中,x是房子的各種信息,例如:面積,樓層,位置等等,y是房子的價格。在圖像識別的任務中,x是圖形的所有像素點數據,y是圖像中包含的目標對象。
我們是希望尋找一個函數,將x映射到y,這個函數要足夠的好,以至於能夠預測對應的y。由於歷史原因,這個函數叫做假設函數(hypothesis function)。
學習的過程如下圖所示。即:首先根據已有的數據(稱之為訓練集)訓練我們的演算法模型,然後根據模型的假設函數來進行新數據的預測。
線性模型(linear model)正如其名稱那樣:是希望通過一個直線的形式來描述模式。線性模型的假設函數如下所示:
[h_{ heta}(x) = heta_{0} + heta_{1} * x]
這個公式對於大家來說應該都是非常簡單的。如果把它繪制出來,其實就是一條直線。
下圖是一個具體的例子,即: 的圖形:
在實際的機器學習工程中,你會擁有大量的數據。這些數據會來自於某個數據源。它們存儲在csv文件中,或者以其他的形式打包。
但是本文作為演示使用,我們通過一些簡單的代碼自動生成了需要的數據。為了便於計算,演示的數據量也很小。
import numpy as np
max_x = 10
data_size = 10
theta_0 = 5
theta_1 = 2
def get_data:
x = np.linspace(1, max_x, data_size)
noise = np.random.normal(0, 0.2, len(x))
y = theta_0 + theta_1 * x + noise
return x, y
這段代碼很簡單,我們生成了x范圍是 [1, 10] 整數的10條數據。對應的y是以線性模型的形式計算得到,其函數是:。現實中的數據常常受到各種因素的干擾,所以對於y我們故意加上了一些高斯雜訊。因此最終的y值為比原先會有輕微的偏離。
最後我們的數據如下所示:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [6.66, 9.11, 11.08, 12.67, 15.12, 16.76, 18.75, 21.35, 22.77, 24.56]
我們可以把這10條數據繪制出來這樣就有一個直觀的了解了,如下圖所示:
雖然演示用的數據是我們通過公式計算得到的。但在實際的工程中,模型的參數是需要我們通過數據學習到的。所以下文我們假設我們不知道這里線性模式的兩個參數是什麼,而是通過演算法的形式求得。
最後再跟已知的參數進行對比以驗證我們的演算法是否正確。
有了上面的數據,我們可以嘗試畫一條直線來描述我們的模型。
例如,像下面這樣畫一條水平的直線:
很顯然,這條水平線離數據太遠了,非常的不匹配。
那我們可以再畫一條斜線。
我們初次畫的斜線可能也不貼切,它可能像下面這樣:
最後我們通過不斷嘗試,找到了最終最合適的那條,如下所示:
梯度下降演算法的計算過程,就和這種本能式的試探是類似的,它就是不停的迭代,一步步的接近最終的結果。
代價函數
上面我們嘗試了幾次通過一條直線來擬合(fitting)已有的數據。
二維平面上的一條直線可以通過兩個參數唯一的確定,兩個參數的確定也即模型的確定。那如何描述模型與數據的擬合程度呢?答案就是代價函數。
代價函數(cost function)描述了學習到的模型與實際結果的偏差程度。以上面的三幅圖為例,最後一幅圖中的紅線相比第一條水平的綠線,其偏離程度(代價)應該是更小的。
很顯然,我們希望我們的假設函數與數據盡可能的貼近,也就是說:希望代價函數的結果盡可能的小。這就涉及到結果的優化,而梯度下降就是尋找最小值的方法之一。
對於每一個樣本,假設函數會依據計算出一個估算值,我們常常用來表示。即 。
很自然的,我們會想到,通過下面這個公式來描述我們的模型與實際值的偏差程度:
[(h_ heta(x^i) - y^i)^2 = (widehat{y}^{i} - y^i)^2 = ( heta_{0} + heta_{1} * x^{i} - y^{i})^2]
請注意, 是實際數據的值, 是我們的模型的估算值。前者對應了上圖中的離散點的y坐標,後者對應了離散點在直線上投影點的y坐標。
每一條數據都會存在一個偏差值,而代價函數就是對所有樣本的偏差求平均值,其計算公式如下所示:
[L( heta) = frac {1}{m} sum_{i=1}^{m}(h_ heta(x^i) - y^i)^2 = frac {1}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i})^2]
當損失函數的結果越小,則意味著通過我們的假設函數估算出的結果與真實值越接近。這也就是為什麼我們要最小化損失函數的原因。
藉助上面這個公式,我們可以寫一個函數來實現代價函數:
def cost_function(x, y, t0, t1):
cost_sum = 0
for i in range(len(x)):
cost_item = np.power(t0 + t1 * x[i] - y[i], 2)
cost_sum += cost_item
return cost_sum / len(x)
這個函數的代碼應該不用多做解釋,它就是根據上面的完成計算。
我們可以嘗試選取不同的 和 組合來計算代價函數的值,然後將結果繪制出來:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
theta_0 = 5
theta_1 = 2
def draw_cost(x, y):
fig = plt.figure(figsize=(10, 8))
ax = fig.gca(projection='3d')
scatter_count = 100
radius = 1
t0_range = np.linspace(theta_0 - radius, theta_0 + radius, scatter_count)
t1_range = np.linspace(theta_1 - radius, theta_1 + radius, scatter_count)
cost = np.zeros((len(t0_range), len(t1_range)))
for a in range(len(t0_range)):
for b in range(len(t1_range)):
cost[a][b] = cost_function(x, y, t0_range[a], t1_range[b])
t0, t1 = np.meshgrid(t0_range, t1_range)
ax.set_xlabel('theta_0')
ax.set_ylabel('theta_1')
ax.plot_surface(t0, t1, cost, cmap=cm.hsv)
在這段代碼中,我們對 和 各自指定了一個范圍進行100次的采樣,然後以不同的 組合對來計算代價函數的值。
如果我們將所有點的代價函數值繪制出來,其結果如下圖所示:
從這個圖形中我們可以看出,當 越接近 [5, 2]時其結果(偏差)越小。相反,離得越遠,結果越大。
直觀解釋
從上面這幅圖中我們可以看出,代價函數在不同的位置結果大小不同。
從三維的角度來看,這就和地面的高低起伏一樣。最高的地方就好像是山頂。
而我們的目標就是:從任意一點作為起點,能夠快速尋找到一條路徑並以此到達圖形最低點(代價值最小)的位置。
而梯度下降的演算法過程就和我們從山頂想要快速下山的做法是一樣的。
在生活中,我們很自然會想到沿著最陡峭的路往下行是下山速度最快的。如下面這幅圖所示:
針對這幅圖,細心的讀者可能很快就會有很多的疑問,例如:
對於一個函數,怎麼確定下行的方向?
每一步該往前走多遠?
有沒有可能停留在半山腰的平台上?
這些問題也就是本文接下來要討論的內容。
演算法描述
梯度下降演算法最開始的一點就是需要確定下降的方向,即:梯度。
我們常常用 來表示梯度。
對於一個二維空間的曲線來說,梯度就是其切線的方向。如下圖所示:
而對於更高維空間的函數來說,梯度由所有變數的偏導數決定。
其表達式如下所示:
[ abla f({ heta}) = ( frac{partial f({ heta})}{partial heta_1} , frac{partial f({ heta})}{partial heta_2} , ... , frac{partial f({ heta})}{partial heta_n} )]
在機器學習中,我們主要是用梯度下降演算法來最小化代價函數,記做:
[ heta ^* = arg min L( heta)]
其中,L是代價函數,是參數。
梯度下降演算法的主體邏輯很簡單,就是沿著梯度的方向一直下降,直到參數收斂為止。
記做:
[ heta ^{k + 1}_i = heta^{k}_i - lambda abla f( heta^{k})]
這里有幾點需要說明:
收斂是指函數的變化率很小。具體選擇多少合適需要根據具體的項目來確定。在演示項目中我們可以選擇0.01或者0.001這樣的值。不同的值將影響演算法的迭代次數,因為在梯度下降的最後,我們會越來越接近平坦的地方,這個時候函數的變化率也越來越小。如果選擇一個很小的值,將可能導致演算法迭代次數暴增。
公式中的 稱作步長,也稱作學習率(learning rate)。它決定了每一步往前走多遠,關於這個值我們會在下文中詳細講解。你可以暫時人為它是一個類似0.01或0.001的固定值。
在具體的項目,我們不會讓演算法無休止的運行下去,所以通常會設置一個迭代次數的最大上限。
線性回歸的梯度下降
有了上面的知識,我們可以回到線性模型代價函數的梯度下降演算法實現了。
首先,根據代價函數我們可以得到梯度向量如下:
[ abla f({ heta}) = (frac{partial L( heta)}{ partial heta_{0}}, frac{ partial L( heta)}{ partial heta_{1}}) = (frac {2}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) , frac {2}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) x^{i})]
接著,將每個偏導數帶入迭代的公式中,得到:
[ heta_{0} := heta_{0} - lambda frac{partial L( heta_{0})}{ partial heta_{0}} = heta_{0} - frac {2 lambda }{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) heta_{1} := heta_{1} - lambda frac{partial L( heta_{1})}{ partial heta_{1}} = heta_{1} - frac {2 lambda }{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) x^{i}]
由此就可以通過代碼實現我們的梯度下降演算法了,演算法邏輯並不復雜:
learning_rate = 0.01
def gradient_descent(x, y):
t0 = 10
t1 = 10
delta = 0.001
for times in range(1000):
sum1 = 0
sum2 = 0
for i in range(len(x)):
sum1 += (t0 + t1 * x[i] - y[i])
sum2 += (t0 + t1 * x[i] - y[i]) * x[i]
t0_ = t0 - 2 * learning_rate * sum1 / len(x)
t1_ = t1 - 2 * learning_rate * sum2 / len(x)
print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))
if (abs(t0 - t0_) < delta and abs(t1 - t1_) < delta):
print('Gradient descent finish')
return t0_, t1_
t0 = t0_
t1 = t1_
print('Gradient descent too many times')
return t0, t1
這段代碼說明如下:
我們隨機選擇了 都為10作為起點
設置最多迭代1000次
收斂的范圍設為0.001
學習步長設為0.01
如果我們將演算法迭代過程中求得的線性模式繪制出來,可以得到下面這幅動態圖:
最後演算法得到的結果如下:
Times: 657, gradient: [5.196562662718697, 1.952931052920264]
Times: 658, gradient: [5.195558390180733, 1.9530753071808193]
Times: 659, gradient: [5.194558335124868, 1.9532189556399233]
Times: 660, gradient: [5.193562479839619, 1.9533620008416623]
Gradient descent finish
從輸出中可以看出,演算法迭代了660次就收斂了。這時的結果[5.193562479839619, 1.9533620008416623],這已經比較接近目標值 [5, 2]了。如果需要更高的精度,可以將delta的值調的更小,當然,此時會需要更多的迭代次數。
高維擴展
雖然我們舉的例子是二維的,但是對於更高維的情況也是類似的。同樣是根據迭代的公式進行運算即可:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - frac{2lambda}{m} sum_{i=1}^{m}(h_ heta(x^{k})-y^k)x_i^k]
這里的下標i表示第i個參數,上標k表示第k個數據。
梯度下降家族BGD
在上面的內容中我們看到,演算法的每一次迭代都需要把所有樣本進行遍歷處理。這種做法稱為之Batch Gradient Descent,簡稱BGD。作為演示示例只有10條數據,這是沒有問題的。
但在實際的項目中,數據集的數量可能是幾百萬幾千萬條,這時候每一步迭代的計算量就會非常的大了。
於是就有了下面兩個變種。
SGD
Stochastic Gradient Descent,簡稱SGD,這種演算法是每次從樣本集中僅僅選擇一個樣本來進行計算。很顯然,這樣做演算法在每一步的計算量一下就少了很多。
其演算法公式如下:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - lambda(h_ heta(x^k)-y^k)x_i^k]
當然,減少演算法計算量也是有代價的,那就是:演算法結果會強依賴於隨機取到的數據情況,這可能會導致演算法的最終結果不太令人滿意。
MBGD
以上兩種做法其實是兩個極端,一個是每次用到了所有數據,另一個是每次只用一個數據。
我們自然就會想到兩者取其中的方法:每次選擇一小部分數據進行迭代。這樣既避免了數據集過大導致每次迭代計算量過大的問題,也避免了單個數據對演算法的影響。
這種演算法稱之為Mini-batch Gradient Descent,簡稱MBGD。
其演算法公式如下:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - frac{2lambda}{m} sum_{i=a}^{a + b}(h_ heta(x^k)-y^k)x_i^k]
當然,我們可以認為SGD是Mini-batch為1的特例。
針對上面提到的演算法變種,該如何選擇呢?
下面是Andrew Ng給出的建議:
如果樣本數量較小(例如小於等於2000),選擇BGD即可。
如果樣本數量很大,選擇 來進行MBGD,例如:64,128,256,512。
下表是 Optimization for Deep Learning 中對三種演算法的對比
方法准確性更新速度內存佔用在線學習BGD好慢高否SGD好(with annealing)快低是MBGD好中等中等是
演算法優化
式7是演算法的基本形式,在這個基礎上有很多人進行了更多的研究。接下來我們介紹幾種梯度下降演算法的優化方法。
Momentum
Momentum是動量的意思。這個演算法的思想就是藉助了動力學的模型:每次演算法的迭代會使用到上一次的速度作為依據。
演算法的公式如下:
[v^t = gamma v^{t - 1} + lambda abla f( heta) heta = heta - v_t]
對比式7可以看出,這個演算法的主要區別就是引入了,並且,每個時刻的受前一個時刻的影響。
從形式上看,動量演算法引入了變數 v 充當速度角色——它代表參數在參數空間移動的方向和速率。速度被設為負梯度的指數衰減平均。名稱動量來自物理類比,根據牛頓運動定律,負梯度是移動參數空間中粒子的力。動量在物理學上定義為質量乘以速度。在動量學習演算法中,我們假設是單位質量,因此速度向量 v 也可以看作是粒子的動量。
對於可以取值0,而是一個常量,設為0.9是一個比較好的選擇。
下圖是momentum演算法的效果對比:
對原來的演算法稍加修改就可以增加動量效果:
def gradient_descent_with_momentum(x, y):
t0 = 10
t1 = 10
delta = 0.001
v0 = 0
v1 = 0
gamma = 0.9
for times in range(1000):
sum1 = 0
sum2 = 0
for i in range(len(x)):
sum1 += (t0 + t1 * x[i] - y[i])
sum2 += (t0 + t1 * x[i] - y[i]) * x[i]
v0 = gamma * v0 + 2 * learning_rate * sum1 / len(x)
v1 = gamma * v1 + 2 * learning_rate * sum2 / len(x)
t0_ = t0 - v0
t1_ = t1 - v1
print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))
if (abs(t0 - t0_) < delta and abs(t1 - t1_) < delta):
print('Gradient descent finish')
return t0_, t1_
t0 = t0_
t1 = t1_
print('Gradient descent too many times')
return t0, t1
以下是該演算法的輸出:
Times: 125, gradient: [4.955453758569991, 2.000005017897775]
Times: 126, gradient: [4.955309381126545, 1.9956928964532015]
Times: 127, gradient: [4.9542964317327005, 1.9855674828684156]
Times: 128, gradient: [4.9536358220657, 1.9781180992510465]
Times: 129, gradient: [4.95412496254411, 1.9788858350530971]
Gradient descent finish
從結果可以看出,改進的演算法只用了129次迭代就收斂了。速度比原來660次快了很多。
同樣的,我們可以把演算法計算的過程做成動態圖:
對比原始的演算法過程可以看出,改進演算法最大的區別是:在尋找目標值時會在最終結果上下跳動,但是越往後跳動的幅度越小,這也就是動量所產生的效果。
Learning Rate 優化
至此,你可能還是好奇該如何設定學習率的值。
事實上,這個值的選取需要一定的經驗或者反復嘗試才能確定。
關鍵在於,這個值的選取不能過大也不能過小。
如果這個值過小,會導致每一次迭代的步長很小,其結果就是演算法需要迭代非常多的次數。
那麼,如果這個值過大會怎麼樣呢?其結果就是:演算法可能在結果的周圍來回震盪,卻落不到目標的點上。下面這幅圖描述了這個現象:
事實上,學習率的取值未必一定要是一個常數,關於這個值的設定有很多的研究。
下面是比較常見的一些改進演算法。
AdaGrad
AdaGrad是Adaptive Gradient的簡寫,該演算法會為每個參數設定不同的學習率。它使用歷史梯度的平方和作為基礎來進行計算。
其演算法公式如下:
[ heta_i = heta_i - frac{lambda}{sqrt{G_t + epsilon}} abla f( heta)]
對比式7,這里的改動就在於分號下面的根號。
根號中有兩個符號,第二個符號比較好理解,它就是為了避免除0而人為引入的一個很小的常數,例如可以設為:0.001。
第一個符號的表達式展開如下:
[G_t = sum_{i = 1}^{t} abla f( heta){i} abla f( heta){i}^{T}]
這個值其實是歷史中每次梯度的平方的累加和。
AdaGrad演算法能夠在訓練中自動的對learning rate進行調整,對於出現頻率較低參數採用較大的學習率;相反,對於出現頻率較高的參數採用較小的學習率。因此,Adagrad非常適合處理稀疏數據。
但該演算法的缺點是它可能導致學習率非常小以至於演算法收斂非常的慢。
關於這個演算法的直觀解釋可以看李宏毅教授的視頻課程:ML Lecture 3-1: Gradient Descent。
RMSProp
RMS是Root Mean Square的簡寫。RMSProp是AI教父Geoff Hinton提出的一種自適應學習率方法。AdaGrad會累加之前所有的梯度平方,而RMSProp僅僅是計算對應的平均值,因此可緩解Adagrad演算法學習率下降較快的問題。
該演算法的公式如下:
[E[ abla f( heta_{i})^2]^{t} = gamma E[ abla f( heta_{i})^2]^{t - 1} + (1-gamma)( abla f( heta_{i})^{t})^{2} heta_i = heta_i - frac{lambda}{sqrt{E[g^2]^{t+1} + epsilon}} abla f( heta_{i})]
類似的,是為了避免除0而引入。 是衰退參數,通常設為0.9。
這里的 是t時刻梯度平方的平均值。
Adam
Adam是Adaptive Moment Estimation的簡寫。它利用梯度的一階矩估計和二階矩估計動態調整每個參數的學習率。
Adam的優點主要在於經過偏置校正後,每一次迭代學習率都有個確定范圍,使得參數比較平穩。
該演算法公式如下:
[m^{t} = eta_{1} m^{t-1} + (1-eta_{1}) abla f( heta) v^{t} = eta_{2} v^{t-1} + (1-eta_{2}) abla f( heta)^2 widehat{m}^{t} = frac{m^{t}}{1 - eta^{t}_1} widehat{v}^{t} = frac{v^{t}}{1 - eta^{t}_2} heta = heta - frac{lambda}{sqrt{widehat{v}^{t}} + epsilon}widehat{m}^{t}]
,分別是對梯度的一階矩估計和二階矩估計。, 是對,的校正,這樣可以近似為對期望的無偏估計。
Adam演算法的提出者建議 默認值為0.9,默認值為0.999,默認值為 。
在實際應用中 ,Adam較為常用,它可以比較快地得到一個預估結果。
優化小結
這里我們列舉了幾種優化演算法。它們很難說哪種最好,不同的演算法適合於不同的場景。在實際的工程中,可能需要逐個嘗試一下才能確定選擇哪一個,這個過程也是目前現階段AI項目要經歷的工序之一。
實際上,該方面的研究遠不止於此,如果有興趣,可以繼續閱讀 《Sebastian Ruder: An overview of gradient descent optimization algorithms》 這篇論文或者 Optimization for Deep Learning 這個Slides進行更多的研究。
由於篇幅所限,這里不再繼續展開了。
演算法限制
梯度下降演算法存在一定的限制。首先,它要求函數必須是可微分的,對於不可微的函數,無法使用這種方法。
除此之外,在某些情況下,使用梯度下降演算法在接近極值點的時候可能收斂速度很慢,或者產生Z字形的震盪。這一點需要通過調整學習率來迴避。
另外,梯度下降還會遇到下面兩類問題。
局部最小值
局部最小值(Local Minima)指的是,我們找到的最小值僅僅是一個區域內的最小值,而並非全局的。由於演算法的起點是隨意取的,以下面這個圖形為例,我們很容易落到局部最小值的點裡面。
這就是好像你從上頂往下走,你第一次走到的平台未必是山腳,它有可能只是半山腰的一個平台的而已。
演算法的起點決定了演算法收斂的速度以及是否會落到局部最小值上。
壞消息是,目前似乎沒有特別好的方法來確定選取那個點作為起點是比較好的,這就有一點看運氣的成分了。多次嘗試不同的隨機點或許是一個比較好的方法,這也就是為什麼做演算法的優化這項工作是特別消耗時間的了。
但好消息是:
對於凸函數或者凹函數來說,不存在局部極值的問題。其局部極值一定是全局極值。
最近的一些研究表明,某些局部極值並沒有想像中的那麼糟糕,它們已經非常的接近全局極值所帶來的結果了。
鞍點
除了Local Minima,在梯度下降的過程中,還有可能遇到另外一種情況,即:鞍點(Saddle Point)。鞍點指的是我們找到點某個點確實是梯度為0,但它卻不是函數的極值,它的周圍既有比它小的值,也有比它大的值。這就好像馬鞍一樣。
如下圖所示:
多類隨機函數表現出以下性質:在低維空間中,局部極值很普遍。但在高維空間中,局部極值比較少見,而鞍點則很常見。
不過對於鞍點,可以通過數學方法Hessian矩陣來確定。關於這點,這里就不再展開了,有興趣的讀者可以以這里提供的幾個鏈接繼續探索。
參考資料與推薦讀物
Wikipeida: Gradient descent
Sebastian Ruder: An overview of gradient descent optimization algorithms
吳恩達:機器學習
吳恩達:深度學習
Peter Flach:機器學習
李宏毅 - ML Lecture 3-1: Gradient Descent
PDF: 李宏毅 - Gradient Descent
Intro to optimization in deep learning: Gradient Descent
Intro to optimization in deep learning: Momentum, RMSProp and Adam
Stochastic Gradient Descent – Mini-batch and more
劉建平Pinard - 梯度下降(Gradient Descent)小結
多元函數的偏導數、方向導數、梯度以及微分之間的關系思考
[Machine Learning] 梯度下降法的三種形式BGD、SGD以及MBGD
H. 如何用Python進行線性回歸以及誤差分析
數據挖掘中的預測問題通常分為2類:回歸與分類。
簡單的說回歸就是預測數值,而分類是給數據打上標簽歸類。
本文講述如何用Python進行基本的數據擬合,以及如何對擬合結果的誤差進行分析。
本例中使用一個2次函數加上隨機的擾動來生成500個點,然後嘗試用1、2、100次方的多項式對該數據進行擬合。
擬合的目的是使得根據訓練數據能夠擬合出一個多項式函數,這個函數能夠很好的擬合現有數據,並且能對未知的數據進行預測。
代碼如下:
importmatplotlib.pyplot as plt
importnumpy as np
importscipy as sp
fromscipy.statsimportnorm
fromsklearn.pipelineimportPipeline
fromsklearn.linear_modelimportLinearRegression
fromsklearn.
fromsklearnimportlinear_model
''''' 數據生成 '''
x = np.arange(0,1,0.002)
y = norm.rvs(0, size=500, scale=0.1)
y = y + x**2
''''' 均方誤差根 '''
defrmse(y_test, y):
returnsp.sqrt(sp.mean((y_test - y) **2))
''''' 與均值相比的優秀程度,介於[0~1]。0表示不如均值。1表示完美預測.這個版本的實現是參考scikit-learn官網文檔 '''
defR2(y_test, y_true):
return1- ((y_test - y_true)**2).sum() / ((y_true - y_true.mean())**2).sum()
''''' 這是Conway&White《機器學習使用案例解析》里的版本 '''
defR22(y_test, y_true):
y_mean = np.array(y_true)
y_mean[:] = y_mean.mean()
return1- rmse(y_test, y_true) / rmse(y_mean, y_true)
plt.scatter(x, y, s=5)
degree = [1,2,100]
y_test = []
y_test = np.array(y_test)
fordindegree:
clf = Pipeline([('poly', PolynomialFeatures(degree=d)),
('linear', LinearRegression(fit_intercept=False))])
clf.fit(x[:, np.newaxis], y)
y_test = clf.predict(x[:, np.newaxis])
print(clf.named_steps['linear'].coef_)
print('rmse=%.2f, R2=%.2f, R22=%.2f, clf.score=%.2f'%
(rmse(y_test, y),
R2(y_test, y),
R22(y_test, y),
clf.score(x[:, np.newaxis], y)))
plt.plot(x, y_test, linewidth=2)
plt.grid()
plt.legend(['1','2','100'], loc='upper left')
plt.show()
該程序運行的顯示結果如下:
[ 0. 0.75873781]
rmse=0.15, R2=0.78, R22=0.53, clf.score=0.78
[ 0. 0.35936882 0.52392172]
rmse=0.11, R2=0.87, R22=0.64, clf.score=0.87
[ 0.00000000e+00 2.63903249e-01 3.14973328e-01 2.43389461e-01
1.67075328e-01 1.10674280e-01 7.30672237e-02 4.88605804e-02
......
3.70018540e-11 2.93631291e-11 2.32992690e-11 1.84860002e-11
1.46657377e-11]
rmse=0.10, R2=0.90, R22=0.68, clf.score=0.90
I. 馬科維茨有效前沿python求出每個點的配置比例
1.馬科維茨有效前沿中每個點的配置比例可以通過求解其凸組合來確定。這需要解決一個線性規劃問題,目標是最大化有效前沿上的點到要優化的點的距離,約束條件是各點的權重和為1,且每個權重大於等於0。通過求解該線性規劃問題,可以得到每個點在有效前沿上的配置比例。
2.深入分析
2.1 根據馬科維茨有效前沿的定義,其上每個點可以由多個極點通過凸組合得到。配置比例就是各極點在該凸組合中所佔的權重。這些權重滿足二次型約束:w1+w2+...+wn=1,wi≥0,i=1,2,...,n。
2.2 求解配置比例的關鍵在於構建一個線性規劃模型。目標函數設為maximizeρ,其中ρ代表有效前沿上點到要優化的點的歐幾里得距離。約束條件為wi≥0,w1+w2+...+wn=1。通過求解該線性規劃問題,可以得到最優的權重配置,這些權重值即為各極點在有效前沿點上的配置比例。
2.3 上述線性規劃問題可以通過python中的凸優化庫cvxopt來求解。要先構建線性規劃問題的矩陣形式,再使用cvxopt.solvers.lp這個函數進行求解。函數輸入為目標函數矩陣、約束矩陣和變數下界上界,輸出為最優化權重向量,這即為所求的配置比例。
2.4 求解配置比例需要先確定馬科維茨有效前沿,這需要使用極小化方法來尋找要優化的目標函數的極小點。常用方法有梯度下降法、Newton法以及interior point method等。通過這些方臘禪法可以找到目標函數的所有極小點,構建出有效前沿,這為後續的配置比例計算提供了必要的條件。
3.建議
3.1 在馬科維茨有效前沿的計算中,應採用既定的優化方法,如牛頓法,來確保找到全局最優解。這有助於構建出完備的有效前沿,為後續配置比例計算提供准確的計算基礎。
3.2 線性規劃建模時,目標函數和約束條件應表達清晰准確。各矩陣應事先規范化,以避免由於數據量級差異導致的計算誤差。
3.3 凸優化庫的選擇上,推薦使用經過驗證的優化庫,如cvxopt。這類庫運算速度較快,且可以直接求解various 類型的凸規劃問題,避免由於演算法實現帶來的誤差。
3.4 配置比例的計算結果還需要進行正確性驗證。可以通過計算有效前沿上各點的凸組合,與原有效前沿點的坐標進行比較,看其誤差是否在可接受范圍內。這一驗證過程是保山畢證最終計算結逗局芹果正確的必要步驟。
J. python 線性模型
因變數是你自己確定的,一般主成分得分是作為自變數的,叫主成分回歸分析