從我對整個職業生涯的規劃出發,我不只想作一些高質量的應用(軟件工程的角度),還想作一些激動人心的應用,因此我但願能在機器學習的方向走,儘管我在大學粗淺的學了些皮毛,但若是要把機器學習做爲職業發展的話這些還差得遠,因此我開始寫了這個系列的文章。python
我但願經過這個系列能對機器學習領域的知識點作一個總結,因此對於Machine Learning這個部分,個人目標是寫出能讓高中生看得懂。git
這篇文章的主角是線性迴歸,也就是LR(Linear Regression)。不太高中生確定不知道迴歸是什麼吧?我如今前言裏面簡單介紹一下。github
迴歸(Regression)問題是機器學習裏面很大的一塊。算法
統計學中,迴歸分析(regression analysis)指的是肯定兩種或兩種以上變量間相互依賴的定量關係的一種統計分析方法。迴歸分析按照涉及的變量的多少,分爲一元迴歸和多元迴歸分析;按照因變量的多少,可分爲簡單迴歸分析和多重回歸分析;按照自變量和因變量之間的關係類型,可分爲線性迴歸分析和非線性迴歸分析。編程
不玩定義,直接上例子,設想一下這樣的場景: 若是我如今有了一組(身高, 體重)的數據集,能夠令身高爲x值,體重爲y值將其畫在紙上,就和下圖同樣。 windows
那麼如今問題來了,假設我身高爲1.8m,能不能預測出個人體重?這就是迴歸要解決的問題,我但願獲得一個函數,我輸入個人身高以後他可以幫我預測出個人體重。在這個例子裏,我假設身高和體重的關係是線性關係,因此假設模型是y=kx+b這種一次函數,爲了肯定變量k和b,我須要利用以前的數據去學習出這兩個參數。機器學習
儘管上面的例子偏差很大。由於體重的函數確定不僅僅由身高這一個特徵(feature)決定,並且即便只有身高一個特徵,最佳函數也極可能不是一次函數。函數
一般,這類預測問題能夠用迴歸(regression)模型進行解決,迴歸模型定義了輸入與輸出的關係,輸入即現有知識,而輸出則爲預測。post
一個預測問題在迴歸模型下的解決步驟爲:學習
kaggle上有個給萌新練習的比賽(competition),關於泰坦尼克號的。
主要內容就是給出幾千我的的我的信息(性別、年齡,船艙登記,登船口等信息)以及他們是否存活的數據,而後給出一些測試數據,即上面說的我的信息,讓你去預測他們是否會存活下來。
有興趣能夠了解一下: kaggle-titanic
這篇博客主要講的是線性迴歸(Linear regression),通過前言後你們也知道了,迴歸裏面用到的函數有多種多樣的,這個須要開發者本身去選擇,此次先介紹最簡單的線性迴歸(Linear regression)。
從數學上來講,給定由d個屬性描述的示例x=(x1;x2;...;xd)
,其中xi
是x在第i個屬性上的取值,線性模型試圖學得一個經過屬性的線性組合來進行預測的函數,即
什麼,你說你是高中生不知道這個T是什麼?去看看矩陣或向量的轉置吧。固然你還得去看看矩陣的乘法,畢竟這裏有個1行n列的矩陣和一個n行一列的矩陣相乘
好了,如今咱們知道了線性迴歸模型的基本形式了,那麼咱們如今的任務就是要去學習出這個w
向量和b這些參數的值,有了這個值咱們才能去作預測。
通常來講,咱們會給w和b一個初始值,而後咱們去修正這些值來讓這些值符合預期,那麼咱們怎麼去修正這些值呢?咱們須要一個損失函數(loss function),這個函數用來指明個人預測值和訓練數據實際值的差異。
那麼這個損失函數(loss function)是什麼,以及咱們怎麼用它來修正咱們的參數w和b,看下面。
這裏我只講一個梯度降低法,若是之後有須要我會再回來補充。
不知道你們知不知道啓發式搜索(Heuristically Search)?
啓發式搜索(Heuristically Search)又稱爲有信息搜索(Informed Search),它是利用問題擁有的啓發信息來引導搜索,達到減小搜索範圍、下降問題複雜度的目的,這種利用啓發信息的搜索過程稱爲啓發式搜索。——百度百科
舉個例子,大一大二在大學裏面的時候我是有單車的,晚上下課的時候在停車場裏面常常忘記本身的車停在哪,要找半天才能找獲得,這種就叫盲目搜索,廣度優先搜索(BFS)和寬度優先搜索(DFS)都是盲目搜索。
那麼若是我手裏有個黑科技,可以告訴我我如今距離個人愛車多遠,那麼我是否是能夠以此爲依據,往距離逐漸減小的方向去搜索呢?這就是啓發式搜索(Heuristically Search),Astar(A*)尋路算法等就是啓發式搜索。
啓發式搜索與機器學習有一些概念是共通的,那麼對於機器學習來講,我也一樣須要一個和「距離我愛車多遠」這樣一個指標來判斷我如今參數距離我最優參數有「多遠」。咱們能夠統一的把這種東西叫作損失函數(loss function)
咱們給以前例子裏的函數一個名字,叫假設函數(hypothesis function),意爲預估值函數。損失函數則是用來衡量假設函數(hypothesis function)的準確性,具體衡量指標有不少,這裏咱們和吳恩達教程裏面同樣採用平方差的方式計算。
其中函數J
就是損失函數(爲何是J我好好奇),函數
h
是假設函數,能夠看到後面是平方差的平均值而後除以了個2。
公式裏面的2其實就是爲了後面求偏導的時候能夠把分數消掉,沒什麼太大的實際意義。
既然咱們如今知道了當前怎麼評價當前參數的好壞,那麼我怎麼去修正參數讓參數更好(損失函數的最小值)呢?
高中生都知道,在一元函數裏面,導數的幾何意義就是函數變化增長最快的方向。梯度其實相似,也是相似的,說白了就是一個向量,表示上升最快的方向。
梯度、偏導數部分的補充你們能夠本身去看高數書或者網上的一些資料。
那麼咱們就能夠獲得一個修正的公式,咱們迭代這個公式許屢次來修正參數。
這裏是減號是由於梯度表示上升最快,因此用的是負梯度。而後其中其中α表示學習速率(learning rate),這個值越大每次修正的就越多,不過這個不是越高越好,若是過高了可能會一直在最低點「擺動」而沒法收斂。也有的使用可變的學習速率,一開始設置較高,接近最低點的過程當中逐漸下降。
接下來咱們看一下求導以後的結果
這裏有一點值得注意的是,在這個梯度降低中咱們每次迭代都使用了全部的m個訓練數據,這種也叫批量梯度降低法Batch Gradient Descent,BGD
這樣每次迭代都將對m個樣本進行計算,計算量大。因此有些優化方案,有興趣的能夠去看一下
如今咱們知道了如何去修正參數了,但咱們實際上修正以後獲得的是損失函數(loss function)的極小值而不必定是最小值
因爲起始點(起始參數)的不一樣,最後可能獲得的並非全局的最優解(損失函數最小)。我說一下從西瓜書上看到的幾個優化方法。
說了那麼多理論,是時候寫一些代碼了。我打算使用Python來作一下斯坦福Machine Learning課程裏面關於線性迴歸的練習。pdf以及數據均可以在個人GitHub庫 上下載到
若是你不想被配環境煩死的話,我真的推薦裝Anaconda
,除此以外要說的就是我用的都是Python3.x。
在這個練習中,咱們要用簡單線性迴歸實現預測食物卡車的利潤。咱們如今已經有了(城市人數,城市利潤)這樣的許多對數據,如今我要作的就是用線性迴歸模型並訓練出參數來預測我若是給另外一個城市(城市人數),那麼卡車的利潤是多少。
# 參考http://www.johnwittenauer.net/machine-learning-exercises-in-python-part-1/
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 計算損失,用了矢量化編程而不是for循環
def computeLoss(X, y, theta):
inner = np.power(((X * theta.T) - y), 2)
return np.sum(inner) / (2 * len(X))
# 梯度降低部分
def gradientDescent(X, y, theta, alpha, iters):
temp = np.matrix(np.zeros(theta.shape))
parameters = int(theta.ravel().shape[1])
cost = np.zeros(iters)
for i in range(iters):
error = (X * theta.T) - y
for j in range(parameters):
term = np.multiply(error, X[:,j])
temp[0,j] = theta[0,j] - ((alpha / len(X)) * np.sum(term))
theta = temp
cost[i] = computeLoss(X, y, theta)
return theta, cost
# 讀入訓練數據
# windows用戶路徑可能須要修改下,後期有時間可能會作統一
def loadData(path):
trainingData = pd.read_csv(path, header=None, names=['Population', 'Profit'])
trainingData.head()
trainingData.describe()
trainingData.plot(kind='scatter', x='Population', y='Profit', figsize=(12,8))
plt.show()
return trainingData
trainingData = loadData(os.getcwd() + '/../data/ex1data1.txt')
# 在數據集前插入一列Ones做爲常數係數,也就是y=k*x+b*1這種形式
trainingData.insert(0, 'Ones', 1)
# 將輸入X以及輸出y從數據集中分割
cols = trainingData.shape[1]
X = trainingData.iloc[:,0:cols-1]
y = trainingData.iloc[:,cols-1:cols]
# 把pandas的DataFrames轉換成numpy的矩陣
X = np.matrix(X.values)
y = np.matrix(y.values)
# 初始化參數爲全0的,固然也能夠初始化成其餘的
theta = np.matrix(np.array([0,0]))
# 各向量的維度
X.shape, theta.shape, y.shape
# 初始損失函數值
computeLoss(X, y, theta) # 32.07,後面能夠看看訓練完後的損失函數值
# 設置學習速率以及迭代次數
alpha = 0.01
iters = 2000
# 使用梯度降低獲得模型參數
theta_fin, loss = gradientDescent(X, y, theta, alpha, iters)
theta_fin
# 計算訓練後的參數的損失值
computeLoss(X, y, theta_fin) # 4.47
# 爲了畫線用的,畫出訓練好後的直線
x = np.linspace(trainingData.Population.min(), trainingData.Population.max(), 100)
f = theta_fin[0, 0] + (theta_fin[0, 1] * x)
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(trainingData.Population, trainingData.Profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()
# 損失隨着迭代次數的變化
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters), loss, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Loss')
ax.set_title('Error vs. Training Epoch')
plt.show()
複製代碼
解釋其實註釋裏面都比較清楚,就不贅述了。
本文章來源於 - 梁王(lwio、lwyj123)