教程 從頭開始:如何用 Python 實現帶隨機梯度下降的線性回歸

2021-02-20 機器之心

選自machinelearningmastery

作者:Jason Brownlee

參與:linjing、吳攀

許多機器學習算法的核心是優化。優化算法用於在機器學習中為給定訓練集找出合理的模型參數設置。機器學習最常見的優化算法是隨機梯度下降(SGD:stochastic gradient descent)。

本教程將指導大家用 Python 實現隨機梯度下降對線性回歸算法的優化。通過本教程的學習,你將了解到:

如何用隨機梯度下降估計線性回歸係數

如何對多元線性回歸做預測

如何用帶隨機梯度下降的線性回歸算法對新數據做預測

說明

本文將對線性回歸、隨即梯度下降方法以及本教程所使用的葡萄酒品質數據集做一個集中闡釋。

多元線性回歸

線性回歸是一種用於預測真實值的方法。讓人困惑的是,這些需要預測真實值的問題被稱為回歸問題(regression problems)。

線性回歸是一種用直線對輸入輸出值進行建模的方法。在超過二維的空間裡,這條直線被想像成一個平面或者超平面(hyperplane)。預測即是通過對輸入值的組合對輸出值進行預判。

y = b0 + b1 * x1 + b2 * x2 + ...

係數 (b) 用於對每個輸入屬性 (x) 進行加權,而學習算法的目的正是尋找一組能導出好的預測值 (y) 的係數。這些係數可以使用隨機梯度下降的方法找到。

隨機梯度下降

梯度下降(Gradient Descent)是遵循成本函數的梯度來最小化一個函數的過程。這個過程涉及到對成本形式以及其衍生形式的認知,使得我們可以從已知的給定點朝既定方向移動。比如向下朝最小值移動。

在機器學習中,我們可以利用隨機梯度下降的方法來最小化訓練模型中的誤差,即每次迭代時完成一次評估和更新。

這種優化算法的工作原理是模型每看到一個訓練實例,就對其作出預測,並重複迭代該過程到一定的次數。這個流程可以用於找出能導致訓練數據最小誤差的模型的係數。用機器學習的術語來講,就是每次迭代過程都用如下等式更新係數(b)。

 b = b - learning_rate * error * x

其中 b 是係數或者被優化的權重,learing_rate 需手動設定(如 0.01),error 是取決於權重的訓練數據模型的預測誤差,x 是輸入值。

葡萄酒品質數據集

開發了具有梯度下降的線性回歸算法之後,我們可以將其運用到一個關於葡萄酒品質的數據集當中。這個數據集囊括了 4898 種白葡萄酒的測量標準,包括酸度和 ph 值。目的是用這些客觀標準來預測葡萄酒的品質,分為 0 到 10 級。

下表給出了 5 個數據樣本。

7,0.27,0.36,20.7,0.045,45,170,1.001,3,0.45,8.8,6

6.3,0.3,0.34,1.6,0.049,14,132,0.994,3.3,0.49,9.5,6

8.1,0.28,0.4,6.9,0.05,30,97,0.9951,3.26,0.44,10.1,6

7.2,0.23,0.32,8.5,0.058,47,186,0.9956,3.19,0.4,9.9,6

7.2,0.23,0.32,8.5,0.058,47,186,0.9956,3.19,0.4,9.9,6

所有數據需歸一化為 0-1 之間的值。每種屬性標準單位不同,因而有不同的縮放尺度。通過預測該歸一化數據集的平均值(零規則算法),達到了 0.148 的基準方均根差(RMSE)。

該數據集詳情請參閱 UCI Machine Learning Repository:http://archive.ics.uci.edu/ml/datasets/Wine+Quality

下載該數據集並將其保存到當前工作目錄,文件名為 winequality-white.csv。(注意:文件開頭的頭信息需去除,用作分隔符的 『;』 需改為符合 CSV 格式的 『,』。)

教程

本教程分為三個部分:

1. 預測

2. 估計係數

3. 葡萄酒品質預測

這將能讓你了解在你自己的預測建模問題上實現和應用帶有隨機梯度下降的線性回歸的基礎。

1. 預測

首先建立一個用於預測的函數。這將用於對隨機梯度下降的候選係數的評估,且模型確定之後也需要這個函數。我們會在測試集或者新的數據上用該函數來進行預測。

函數 predict() 如下所示,用於預測給定了一組係數的行的輸出值。

第一個係數始終為截距,也稱為偏差或 b0,因其相對獨立且不與特定的輸入值相關。

我們可以用一個小的數據集對這個函數進行測試。

x, y

1, 1

2, 3

4, 3

3, 2

5, 5

下圖是一小部分數據:

線性回歸的部分轉換數據

我們也可用之前準備好的係數為這個數據集做預測。predict() 函數測試如下。

單個輸入值 (x) 和兩個係數(b0 和 b1)。用於建模該問題的預測方程為:

y = b0 + b1 * x

或者,手動選擇特定係數:

y = 0.4 + 0.8 * x

運行此函數,我們將得到一個相當接近預測值的輸出值(y)。

Expected=1.000, Predicted=1.200

Expected=3.000, Predicted=2.000

Expected=3.000, Predicted=3.600

Expected=2.000, Predicted=2.800

Expected=5.000, Predicted=4.400

現在我們可以用隨機梯度下降來優化我們的係數值了。

2. 估計係數


我們可以使用隨機梯度下降來為我們的訓練數據估計係數值。隨機階梯下降需要兩個設定參數:

這兩個值和數據集都是函數的參數。我們的這個函數將執行三個遍歷循環:

1. 單次 epoch 循環

2. 單次 epoch 中訓練集中的每行循環

3. 單次 epoch 中每個係數循環並為每一行更新它

可以看到,每次 epoch,我們都會更新數據集裡每行的係數。係數的更新是基於模型生成的誤差。該誤差被算作候選係數的預測值和預期輸出值之間的差。

error = prediction - expected

有一個係數用於加權每一個輸入屬性,這些屬性將以連續的方式進行更新,比如

b1(t+1) = b1(t) - learning_rate * error(t) * x1(t)

列表開始的特殊係數,也被稱為截距(intercept)或偏差(bias),也以類似的方式更新,但因其不與特定輸入值相關,所以無輸入值。

b0(t+1) = b0(t) - learning_rate * error(t)

現在我們把所有東西組合在一起。coefficients_sgd() 函數正是用隨機梯度下降來計算一個訓練集的係數值,下面即是該函數:

此外,我們追蹤每個 epoch 的方差(正值)總和從而在循環之後得到一個好的結果。

我們用 0.001 的學習速率訓練該模型 50 次,即把整個訓練數據集的係數曝光 50 次。運行一個 epoch 系統就將該次循環中的和方差(sum squared error)和以及最終係數集合 print 一次:

>epoch=45, lrate=0.001, error=2.650

>epoch=46, lrate=0.001, error=2.627

>epoch=47, lrate=0.001, error=2.607

>epoch=48, lrate=0.001, error=2.589

>epoch=49, lrate=0.001, error=2.573

[0.22998234937311363, 0.8017220304137576]

可以看到誤差是如何在歷次 epoch 中持續降低的。或許我們可以增加訓練次數(epoch)或者每個 epoch 中的係數總量(調高學習速率)。

嘗試一下看你能得到什麼結果。

現在,我們將這個算法用到實際的數據當中。

3. 葡萄酒品質預測

我們將使用隨機階梯下降的方法為葡萄酒品質數據集訓練一個線性回歸模型。本示例假定一個名為 winequality—white.csv 的 csv 文件副本已經存在於當前工作目錄。

首先加載該數據集,將字符串轉換成數字,並將輸出列從字符串轉換成數值 0 和 1. 這個過程是通過輔助函數 load_csv()、str_column_to_float() 以及 dataset_minmax() 和 normalize_dataset() 來分別實現的。

我們將通過 K 次交叉驗證來預估得到的學習模型在未知數據上的表現。這就意味著我們將創建並評估 K 個模型並預估這 K 個模型的平均誤差。輔助函數 cross_validation_split()、rmse_metric() 和 evaluate_algorithm() 用於求導根均方差以及評估每一個生成的模型。

我們用之前創建的函數 predict()、coefficients_sgd() 以及 linear_regression_sgd() 來訓練模型。完整代碼如下:

# Linear Regression With Stochastic Gradient Descent for Wine Quality

from random import seed

from random import randrange

from csv import reader

from math import sqrt

# Load a CSV file

def load_csv(filename):

dataset = list()

with open(filename, 'r') as file:

csv_reader = reader(file)

for row in csv_reader:

if not row:

continue

dataset.append(row)

return dataset

# Convert string column to float

def str_column_to_float(dataset, column):

for row in dataset:

row[column] = float(row[column].strip())

# Find the min and max values for each column

def dataset_minmax(dataset):

minmax = list()

for i in range(len(dataset[0])):

col_values = [row[i] for row in dataset]

value_min = min(col_values)

value_max = max(col_values)

minmax.append([value_min, value_max])

return minmax

# Rescale dataset columns to the range 0-1

def normalize_dataset(dataset, minmax):

for row in dataset:

for i in range(len(row)):

row[i] = (row[i] - minmax[i][0]) / (minmax[i][1] - minmax[i][0])

# Split a dataset into k folds

def cross_validation_split(dataset, n_folds):

dataset_split = list()

dataset_copy = list(dataset)

fold_size = len(dataset) / n_folds

for i in range(n_folds):

fold = list()

while len(fold) < fold_size:

index = randrange(len(dataset_copy))

fold.append(dataset_copy.pop(index))

dataset_split.append(fold)

return dataset_split

# Calculate root mean squared error

def rmse_metric(actual, predicted):

sum_error = 0.0

for i in range(len(actual)):

prediction_error = predicted[i] - actual[i]

sum_error += (prediction_error ** 2)

mean_error = sum_error / float(len(actual))

return sqrt(mean_error)

# Evaluate an algorithm using a cross validation split

def evaluate_algorithm(dataset, algorithm, n_folds, *args):

folds = cross_validation_split(dataset, n_folds)

scores = list()

for fold in folds:

train_set = list(folds)

train_set.remove(fold)

train_set = sum(train_set, [])

test_set = list()

for row in fold:

row_copy = list(row)

test_set.append(row_copy)

row_copy[-1] = None

predicted = algorithm(train_set, test_set, *args)

actual = [row[-1] for row in fold]

rmse = rmse_metric(actual, predicted)

scores.append(rmse)

return scores

# Make a prediction with coefficients

def predict(row, coefficients):

yhat = coefficients[0]

for i in range(len(row)-1):

yhat += coefficients[i + 1] * row[i]

return yhat

# Estimate linear regression coefficients using stochastic gradient descent

def coefficients_sgd(train, l_rate, n_epoch):

coef = [0.0 for i in range(len(train[0]))]

for epoch in range(n_epoch):

for row in train:

yhat = predict(row, coef)

error = yhat - row[-1]

coef[0] = coef[0] - l_rate * error

for i in range(len(row)-1):

coef[i + 1] = coef[i + 1] - l_rate * error * row[i]

# print(l_rate, n_epoch, error)

return coef

# Linear Regression Algorithm With Stochastic Gradient Descent

def linear_regression_sgd(train, test, l_rate, n_epoch):

predictions = list()

coef = coefficients_sgd(train, l_rate, n_epoch)

for row in test:

yhat = predict(row, coef)

predictions.append(yhat)

return(predictions)

# Linear Regression on wine quality dataset

seed(1)

# load and prepare data

filename = 'winequality-white.csv'

dataset = load_csv(filename)

for i in range(len(dataset[0])):

str_column_to_float(dataset, i)

# normalize

minmax = dataset_minmax(dataset)

normalize_dataset(dataset, minmax)

# evaluate algorithm

n_folds = 5

l_rate = 0.01

n_epoch = 50

scores = evaluate_algorithm(dataset, linear_regression_sgd, n_folds, l_rate, n_epoch)

print('Scores: %s' % scores)

print('Mean RMSE: %.3f' % (sum(scores)/float(len(scores))))

一個等於 5 的 k 值被用於交叉驗證,給每次迭代 4898/5 = 979.6(低於 1000 都行)條記錄來進行評估。對一個小實驗選擇了 0.01 的學習率和 50 訓練 epoch.

你可以嘗試你自己的配置,看你能否超過我的分數。

運行這個樣本,為 5 次交叉驗證的每一次 print 一個分數,然後 print 平均均方根誤差(RMSE)。我們可以看到(在歸一化的數據集上)該 RMSE 為 0.126。如果我們只是預測平均值的話(使用 Zero Rule Algorithm),那麼這個結果就低於基準值 0.148。

Scores: [0.12259834231519767, 0.12733924130891316, 0.12610773846663892, 0.1289950071681572, 0.1272180783291014]

Mean RMSE: 0.126

擴展

這裡給出了一些擴展練習,你可以思考並嘗試解決它們:

調整該實例。調整其學習率、epoch 的數量甚至原始數據處理和準備的方法,以期能提高終結果。

批量進行隨機梯度下降。改變隨機梯度下降算法使其在每個 epoch 上累積更新,且僅在 epoch 結束時批量更新係數。

額外的回歸問題。應用該技術來解決 UCI 機器學習庫中的其它回歸問題。

你會探索這些擴展任務嗎?

回顧總結

本教程介紹了如何用 Python 實現帶有隨機梯度下降的多元線性回歸算法。其中包括:

如何對多元線性回歸問題做預測

如何優化用於隨機梯度下降的係數設置

如何將該方法用於實際的回歸預測模型問題

©本文為機器之心編譯,轉載請聯繫本公眾號獲得授權

✄---

加入機器之心(全職記者/實習生):hr@almosthuman.cn

投稿或尋求報導:editor@almosthuman.cn

廣告&商務合作:bd@almosthuman.cn

相關焦點

  • 教程 從頭開始:用Python實現帶隨機梯度下降的線性回歸
    機器學習最常見的優化算法是隨機梯度下降(SGD:stochastic gradient descent)。本教程將指導大家用 Python 實現隨機梯度下降對線性回歸算法的優化。通過本教程的學習,你將了解到:如何用隨機梯度下降估計線性回歸係數如何對多元線性回歸做預測如何用帶隨機梯度下降的線性回歸算法對新數據做預測說明本文將對線性回歸、隨即梯度下降方法以及本教程所使用的葡萄酒品質數據集做一個集中闡釋。
  • 從頭開始:用Python實現帶隨機梯度下降的Logistic回歸
    logistic 回歸是一種著名的二元分類問題的線性分類算法。它容易實現、易於理解,並在各類問題上有不錯的效果,即使該方法的原假設與數據有違背時。在本教程中,你將了解如何在 Python 中實現隨機梯度下降的 logistic 回歸算法。
  • Python機器學習算法入門之梯度下降法實現線性回歸
    從下圖看,最小二乘法所做的是通過數學推導直接計算得到最低點;而梯度下降法所做的是從圖中的任意一點開始,逐步找到圖的最低點。2. 多元線性回歸模型        從機器學習的角度來說,以上的數據只有一個feature,所以用一元線性回歸模型即可。這裡我們將一元線性模型的結論一般化,即推廣到多元線性回歸模型。
  • 【機器學習】梯度下降的Python實現
    你將真正了解這些超參數的作用、在背後發生的情況以及如何處理使用此算法可能遇到的問題,而不是玩弄超參數並希望獲得最佳結果。然而,梯度下降並不局限於一種算法。另外兩種流行的梯度下降(隨機和小批量梯度下降)建立在主要算法的基礎上,你可能會看到比普通批量梯度下降更多的算法。
  • 梯度下降—Python實現
    雖然理論對於深入理解手頭的算法至關重要,但梯度下降的實際編碼及其不同的「變體」可能是一項困難的任務。為了完成這項任務,本文的格式如下:簡要概述每種算法的作用算法的代碼對規範不明確部分的進一步解釋我們將使用著名的波士頓住房數據集,它是預先內置在scikit learn中的。我們還將從頭開始構建一個線性模型。首先做一些基本的導入。
  • 線性回歸和梯度下降的初學者教程
    假設有一個虛擬的數據集包含多對變量,即每位母親和她女兒的身高:通過這個數據集,我們如何預測另一位身高為63的母親的女兒的身高?方法是用線性回歸。首先找到最佳擬合線,然後用這條直線做預測。線性回歸是尋找數據集的最佳擬合線,這條線可以用來做預測。如何找到最佳擬合線?
  • 基於梯度下降算法的線性回歸擬合(附python/matlab/julia代碼)
    梯度下降法就是每次都尋找梯度的反方向,這樣就能到達局部的最低點。  那為什麼按照梯度的反方向能到達局部的最低點呢?這個問題直觀上很容易看出來,但嚴禁起見,我們還是給出數學證明。對於連續可微函數f(x),從某個隨機點出發,想找到局部最低點,可以通過構造一個序列
  • 機器學習之多元線性回歸模型梯度下降公式與代碼實現(篇二)
    上一篇我們介紹了線性回歸的概述和最小二乘的介紹,對簡單的一元線性方程模型手推了公式和python代碼的實現。機器學習之線性回歸模型詳細手推公式與代碼實現(篇一)今天這一篇來介紹多元線性回歸模型多元線性回歸模型介紹在回歸分析中,如果有兩個或兩個以上的自變量,就稱為多元回歸
  • 機器學習——梯度下降、梯度下降的線性回歸算法
    梯度下降背後的思想是:開始時我們隨機選擇一個參數的組合(θo, θ1, ......, θn),計算代價函數,然後我們尋找下一個能讓代價函數值下降最多的參數組合。想像一下你正站立在山的這一點上,站立在你想像的公園這座紅色山上,在梯度下降算法中,我們要做的就是旋轉360度,看看我們的周圍,並問自己要在某個方向上,用小碎步儘快下山。這些小碎步需要朝什麼方向?如果我們站在山坡上的這一點,你看一下周圍,你會發現最佳的下山方向,你再看看周圍,然後再一次想想,我應該從什麼方向邁著小碎步下山?
  • 機器學習基礎:線性回歸和梯度下降的初學者教程
    考慮到另一位母親的身高為63,我們如何預測她女兒的身高?方法是用線性回歸。「計算最佳擬合線的梯度下降法:」在梯度下降中,你從一條隨機線開始。然後一點一點地改變直線的參數(即斜率和y軸截距),以得到最佳擬合的直線。你怎麼知道你什麼時候到達最合適的位置?
  • 【機器學習基礎】線性回歸和梯度下降的初學者教程
    考慮到另一位母親的身高為63,我們如何預測她女兒的身高?方法是用線性回歸。「計算最佳擬合線的梯度下降法:」在梯度下降中,你從一條隨機線開始。然後一點一點地改變直線的參數(即斜率和y軸截距),以得到最佳擬合的直線。你怎麼知道你什麼時候到達最合適的位置?
  • 線性回歸的求解:矩陣方程和梯度下降、數學推導及NumPy實現
    比一元線性回歸更為複雜的是,多元線性回歸最優解不是一條直線,是一個多維空間中的超平面,訓練數據散落在超平面的兩側。用圖像直觀來看,損失函數沿著梯度下降的過程如下所示。迭代過程最終收斂在了最小值附近,此時,梯度或者說導數接近0。
  • 基礎| 機器學習入門必備:如何用Python從頭實現感知器算法
    在本教程中,你將了解到如何利用 Python 從頭開始實現感知器算法。在完成本教程後,你將學會:如何訓練感知器的網絡權重如何利用感知器做出預測如何對於現實世界的分類問題實現感知器算法讓我們開始吧。概述本節簡要介紹了感知器算法和 Sonar 數據集,我們將會在後面應用。
  • 文科生都能看懂的機器學習教程:梯度下降、線性回歸、邏輯回歸
    那些神秘拗口的概念,比如邏輯回歸、梯度下降到底是什麼?j  一個23歲的藥物學專業的學生說,當他去參加機器學習培訓課程的時候,感覺自己就家裡那位不懂現代科技的奶奶。  於是一名叫Audrey Lorberfeld的畢業生,試圖將大眾與機器學習之間的鴻溝,親手填補上。於是有了這個系列文章。  本系列第一講:梯度下降、線性回歸和邏輯回歸。
  • 線性回歸與梯度下降
    Cost Function代價函數是線性回歸中的一個應用,在線性回歸中,要解決的一個問題就是最小化問題。假設在一元線性回歸中,在一個訓練集中,我們需要找到一條直線能和該訓練集中的點最接近。關於 梯度 和 偏導數 的關係在上面梯度下降算法中,我們一直用的是偏導數進行討論的,可能會有人有疑問,偏導數和梯度有啥關係?1.
  • 理解凸性:為什麼梯度下降適用於線性回歸
    在機器學習中我們總會遇到線性回歸問題,但是為什麼我們可以用梯度下降算法來求解線性回歸成本函數呢?凸性理論可以讓我們更容易理解這個問題。凸性首先,通過凸集和凸函數定義凸度。現在我們對凸集和凸函數有了一些直覺和理解,讓我們轉向線性回歸,看看凸性在哪裡起作用。線性回歸回顧假設在n維空間中有m個數據樣本。每個樣本都有n個映射到單個輸出值的特性。我們可以訪問輸入和輸出數據,但是我們想弄清楚輸入數據和輸出數據之間是否存在線性關係。這就是線性回歸模型的用處。
  • python機器學習--線性回歸
    python機器學習--線性回歸線性回歸是最簡單的機器學習模型,其形式簡單,易於實現,同時也是很多機器學習模型的基礎。對於一個給定的訓練集數據,線性回歸的目的就是找到一個與這些數據最吻合的線性函數。在這裡插入圖片描述由於模型的訓練目標為找到使得損失函數最小化的w,經過一系列變換解得使損失函數達到最小值的w為:在這裡插入圖片描述此時求得的w即為最優模型參數OLS線性回歸的代碼實現#OLS線性回歸import numpy as npimport pandas as pdimport seaborn as snsimport
  • 從零開始學PyTorch:一文學會線性回歸、邏輯回歸及圖像分類
    今天為大家帶來一份非常詳盡的PyTorch教程。本文共分3大部分:安裝PyTorch和Jupyter Notebook用PyTorch實現線性回歸使用邏輯回歸實現圖像分類文章超長,秉承用代碼搞定一切的原則,內含大量代碼,建議收藏,並分享給你喜歡的人。同時如果有什麼疑問,也歡迎留言告知我們。
  • 2018AI學習清單丨150個最好的機器學習和Python教程
    線性回歸分析簡介(duke.edu)http://people.duke.edu/~rnau/regintro.htm 線性回歸 (ufldl.stanford.edu)http://ufldl.stanford.edu/tutorial/supervised
  • 機器學習 101:一文帶你讀懂梯度下降
    到目前為止,我們還不清楚如何邁出這一步!而這就是梯度的用武之地。 正如可汗學院的這段視頻所述,梯度獲取了一個多變量函數的所有偏導數。讓我們一步步來看看它是如何工作的。用更簡單的話來說,導數是一個函數在某一點的變化率或斜率。