Jacob的 Python機(jī)器學(xué)習(xí)系列:
Python機(jī)器學(xué)習(xí)(一):kNN算法
Python機(jī)器學(xué)習(xí)(二):線性回歸算法
Python機(jī)器學(xué)習(xí)(三):梯度下降法
Python機(jī)器學(xué)習(xí)(四):PCA 主成分分析
Python機(jī)器學(xué)習(xí)(五):SVM 支撐向量機(jī)
機(jī)器學(xué)習(xí)研究的問(wèn)題分為分類問(wèn)題和回歸問(wèn)題。分類問(wèn)題很好理解避消,而回歸問(wèn)題就是找到一條曲線摸袁,可以最大程度地?cái)M合樣本特征和樣本輸出標(biāo)記之間的關(guān)系。當(dāng)給算法一個(gè)輸入時(shí)突那,這條曲線可以計(jì)算出相應(yīng)可能的輸出巩踏。回歸算法最簡(jiǎn)單的就是線性回歸庞瘸。當(dāng)樣本特征只有一個(gè)時(shí)惜论,稱為簡(jiǎn)單線性回歸许赃;當(dāng)樣本特征有多個(gè)時(shí),稱為多元線性回歸馆类。
1.簡(jiǎn)單線性回歸
由上圖可知混聊,簡(jiǎn)單線性回歸只有一個(gè)特征x,一個(gè)標(biāo)記y乾巧。假定x和y之間具有類似于線性的關(guān)系句喜,就可以使用使用簡(jiǎn)單線性回歸算法僵闯。假定我們找到了最佳擬合的直線方程
則對(duì)于每一個(gè)樣本點(diǎn)x(i),預(yù)測(cè)值如下藤滥。其中帶箭頭的y是預(yù)測(cè)值鳖粟,稱為 y head。右上角的 i 是指樣本的索引拙绊。
我們希望預(yù)測(cè)值和真實(shí)值之間的差距盡量小向图。一般用歐氏距離來(lái)衡量。下式稱為損失函數(shù)(Loss Function)
換句話說(shuō)标沪,我們的目標(biāo)就是找到一組a和b榄攀,使得下式最小
通過(guò)分析不同的問(wèn)題,我們需要確定問(wèn)題的損失函數(shù)金句。通過(guò)最優(yōu)化損失函數(shù)檩赢,獲得機(jī)器學(xué)習(xí)的模型。幾乎所有的參數(shù)學(xué)習(xí)算法都是這樣的套路
那么這個(gè)問(wèn)題是一個(gè)典型的最小二乘法問(wèn)題违寞,即最小化誤差的平方贞瞒。推導(dǎo)可得以下公式
可以用python封裝成這種形式
"""
Created by 楊幫杰 on 10/1/18
Right to use this code in any way you want without
warranty, support or any guarantee of it working
E-mail: yangbangjie1998@qq.com
Association: SCAU 華南農(nóng)業(yè)大學(xué)
"""
import numpy as np
class SimpleLinearRegression:
def __init__(self):
"""初始化Simple Linear Regression 模型"""
self.a_ = None
self.b_ = None
def fit(self, x_train, y_train):
"""根據(jù)訓(xùn)練數(shù)據(jù)集x_train,y_train訓(xùn)練Simple Linear Regression 模型"""
assert x_train.nidm == 1, \
"Simple Linear Regressor can only solve single feature training data."
assert len(x_train) == len(y_train), \
"the size of x_train must be equal to the size of y_train"
x_mean = np.mean(x_train)
y_mean = np.mean(y_train)
"""進(jìn)行向量化可以加快訓(xùn)練速度"""
# num = 0.0
# d = 0.0
# for x, y in zip(x_train, y_train):
# num += (x - x_mean) * (y - y_mean)
# d += (x - x_mean) ** 2
num = (x_train - x_mean).dot(y_train - y_mean)
d = (x_train - x_mean).dot(x_train - x_mean)
self.a_ = num/d
self.b_ = y_mean - self.a_ * x_mean
return self
def predict(self, x_predict):
"""給定待預(yù)測(cè)數(shù)據(jù)集x_predict, 返回表示x_predict的結(jié)果向量"""
assert x_predict.ndim == 1, \
"Simeple Linear Regressor can only solve single feature training data."
assert self.a_ is not None and self.b_ is not None, \
"must fit before predict!"
return np.array([self._predict(x) for x in x_predict])
def _predict(self, x_single):
"""給定單個(gè)待預(yù)測(cè)數(shù)據(jù)x_single, 返回x_single的預(yù)測(cè)結(jié)果值"""
return self.a_ * x_single + self.b_
def __repr__(self):
return "SimpleLinearRegression()"
衡量線性回歸模型好壞有多個(gè)標(biāo)準(zhǔn),均方誤差(Mean Squared Error)趁曼、均方根誤差(Root Mean Squared Error)军浆、平均絕對(duì)誤差(Mean Absolute Error)等。一般使用MSE挡闰。
而如果想像分類問(wèn)題一樣將評(píng)判得分限制在0和1之間乒融,則應(yīng)該使用R Square
右邊一項(xiàng)的分子代表使用模型產(chǎn)生的錯(cuò)誤,分母代表使用平均值進(jìn)行預(yù)測(cè)產(chǎn)生的錯(cuò)誤摄悯。分母也可以理解為一個(gè)模型赞季,稱為Baseline Model。
R Square的輸出分為以下幾種情況:
- R^2 = 1奢驯,則模型不犯任何錯(cuò)誤申钩,完美
- R^2 = 0,模型為基準(zhǔn)模型叨橱,相當(dāng)于沒(méi)訓(xùn)練過(guò)
- R^2 < 0典蜕,數(shù)據(jù)可能不存在任何線性關(guān)系
2.多元線性回歸
多元線性回歸,就是指樣本特征值有多個(gè)。根據(jù)這多個(gè)特征值來(lái)預(yù)測(cè)樣本的標(biāo)記值罗洗。那么特征X和參數(shù)Θ就是一個(gè)向量。
相類似地钢猛,我們需要找到一個(gè)損失函數(shù)伙菜。我們需要找到一組參數(shù)Θ,使下式盡可能小
為了方便進(jìn)行矩陣運(yùn)算命迈,我們寫成這種形式
預(yù)測(cè)值可以寫成這種形式
X展開(kāi)是這個(gè)樣子。每一行是一個(gè)樣本點(diǎn)淑倾,每一列(除了第一列)是一種特征
經(jīng)過(guò)推導(dǎo)馏鹤,得到這樣一個(gè)公式。這成為多元線性回歸的正規(guī)方程解(Normal Equation)娇哆。結(jié)果就是參數(shù)向量湃累。
如上,可以封裝成這種形式
"""
Created by 楊幫杰 on 10/1/18
Right to use this code in any way you want without
warranty, support or any guarantee of it working
E-mail: yangbangjie1998@qq.com
Association: SCAU 華南農(nóng)業(yè)大學(xué)
"""
import numpy as np
class LinearRegression:
def __init__(self):
"""初始化Linear Regression模型"""
self.coef_ = None
self.interception_ = None
self._theta = None
def fit_normal(self, X_train, y_train):
"""根據(jù)訓(xùn)練數(shù)據(jù)集X_train, y_train訓(xùn)練Linear Regression模型"""
assert X_train.shape[0] == y_train.shape[0], \
"the size of X_train must be equal to the size of y_train"
X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
self.interception_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def predict(self, X_predict):
"""給定待預(yù)測(cè)數(shù)據(jù)集X_predict, 返回表示X_predict的結(jié)果向量"""
assert self.interception_ is not None and self.coef_ is not None, \
"must fit before predict!"
assert X_predict.shape[1] == len(self.coef_), \
"the feature number of X_predict must be equal to X_train"
X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
return X_b.dot(self._theta)
def __repr__(self):
return "LinearRegression()"
sciki-learn中使用線性回歸如下
"""
Created by 楊幫杰 on 10/1/18
Right to use this code in any way you want without
warranty, support or any guarantee of it working
"""
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
# 加載波士頓房?jī)r(jià)的數(shù)據(jù)集
boston = datasets.load_boston()
# 清除一些不合理的數(shù)據(jù)
X = boston.data
y = boston.target
X = X[y < 50.0]
y = y[y < 50.0]
# 分離出測(cè)試集并擬合
X_train, X_test, y_train, y_test = train_test_split(X, y)
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)
# 打印結(jié)果
print(lin_reg.coef_)
print(lin_reg.intercept_)
print(lin_reg.score(X_test, y_test))
輸出如下
3.總結(jié)
線性回歸是許多其他回歸和分類問(wèn)題的基礎(chǔ)碍讨。
它最大的優(yōu)點(diǎn)是對(duì)數(shù)據(jù)具有很強(qiáng)的解釋性治力。比如某一項(xiàng)的參數(shù)是正數(shù),那么很可能這個(gè)特征和樣本標(biāo)記之間成正相關(guān)勃黍,反之成負(fù)相關(guān)宵统。
優(yōu)點(diǎn):
- 思想簡(jiǎn)單,實(shí)現(xiàn)容易
- 是許多非線性模型的基礎(chǔ)
- 具有很好的可解釋性
缺點(diǎn):
- 假設(shè)特征和標(biāo)記之間有線性關(guān)系覆获,現(xiàn)實(shí)中不一定
- 訓(xùn)練的時(shí)間復(fù)雜度比較高
References:
機(jī)器學(xué)習(xí)實(shí)戰(zhàn) —— Peter Harrington