Python 機(jī)器學(xué)習(xí)實(shí)戰(zhàn)教程:回歸

Python 機(jī)器學(xué)習(xí)實(shí)戰(zhàn)教程:回歸

原文:Regression - Intro and Data

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

引言和數(shù)據(jù)

歡迎閱讀 Python 機(jī)器學(xué)習(xí)系列教程的回歸部分琐谤。這里,你應(yīng)該已經(jīng)安裝了 Scikit-Learn欠橘。如果沒有,安裝它掂铐,以及 Pandas 和 Matplotlib挖诸。

pip install numpy

pip install scipy

pip install scikit-learn

pip install matplotlib

pip install pandas

除了這些教程范圍的導(dǎo)入之外埋合,我們還要在這里使用 Quandl:

pip install quandl

首先,對(duì)于我們將其用于機(jī)器學(xué)習(xí)而言里逆,什么是回歸呢肛根?它的目標(biāo)是接受連續(xù)數(shù)據(jù),尋找最適合數(shù)據(jù)的方程活鹰,并能夠?qū)μ囟ㄖ颠M(jìn)行預(yù)測(cè)哈恰。使用簡單的線性回歸只估,你可以僅僅通過創(chuàng)建最佳擬合直線,來實(shí)現(xiàn)它着绷。

這里蛔钙,我們可以使用這條直線的方程,來預(yù)測(cè)未來的價(jià)格荠医,其中日期是 x 軸吁脱。

回歸的熱門用法是預(yù)測(cè)股票價(jià)格。由于我們會(huì)考慮價(jià)格隨時(shí)間的流動(dòng)彬向,并且使用連續(xù)的數(shù)據(jù)集兼贡,嘗試預(yù)測(cè)未來的下一個(gè)流動(dòng)價(jià)格,所以可以這樣做娃胆。

回歸是監(jiān)督的機(jī)器學(xué)習(xí)的一種遍希,也就是說,科學(xué)家向其展示特征里烦,之后向其展示正確答案來教會(huì)機(jī)器凿蒜。一旦教會(huì)了機(jī)器,科學(xué)家就能夠使用一些不可見的數(shù)據(jù)來測(cè)試機(jī)器胁黑,其中科學(xué)家知道正確答案废封,但是機(jī)器不知道。機(jī)器的答案會(huì)與已知答案對(duì)比别厘,并且度量機(jī)器的準(zhǔn)確率虱饿。如果準(zhǔn)確率足夠高拥诡,科學(xué)家就會(huì)考慮將其算法用于真實(shí)世界触趴。

由于回歸廣泛用于股票價(jià)格,我們可以使用一個(gè)示例從這里開始渴肉。最開始冗懦,我們需要數(shù)據(jù)。有時(shí)候數(shù)據(jù)易于獲取仇祭,有時(shí)你需要出去并親自收集披蕉。我們這里,我們至少能夠以簡單的股票價(jià)格和成交量信息開始乌奇,它們來自 Quandl没讲。我們會(huì)抓取 Google 的股票價(jià)格,它的代碼是GOOGL

import pandas as pd
import quandl

df = quandl.get("WIKI/GOOGL")

print(df.head())

注意:寫這篇文章的時(shí)候礁苗,Quandl 的模塊使用大寫 Q 引用爬凑,但現(xiàn)在是小寫 q,所以import quandl试伙。

到這里嘁信,我們擁有:

              Open    High     Low   Close    Volume  Ex-Dividend  \
Date                                                                
2004-08-19  100.00  104.06   95.96  100.34  44659000            0   
2004-08-20  101.01  109.08  100.50  108.31  22834300            0   
2004-08-23  110.75  113.48  109.05  109.40  18256100            0   
2004-08-24  111.24  111.60  103.57  104.87  15247300            0   
2004-08-25  104.96  108.00  103.88  106.00   9188600            0   

            Split Ratio  Adj. Open  Adj. High  Adj. Low  Adj. Close  \
Date                                                                  
2004-08-19            1     50.000      52.03    47.980      50.170   
2004-08-20            1     50.505      54.54    50.250      54.155   
2004-08-23            1     55.375      56.74    54.525      54.700   
2004-08-24            1     55.620      55.80    51.785      52.435   
2004-08-25            1     52.480      54.00    51.940      53.000   

            Adj. Volume  
Date                     
2004-08-19     44659000  
2004-08-20     22834300  
2004-08-23     18256100  
2004-08-24     15247300  
2004-08-25      9188600 

這是個(gè)非常好的開始于样,我們擁有了數(shù)據(jù),但是有點(diǎn)多了潘靖。

這里穿剖,我們有很多列,許多都是多余的卦溢,還有些不怎么變化糊余。我們可以看到,常規(guī)和修正(Adj)的列是重復(fù)的单寂。修正的列看起來更加理想啄刹。常規(guī)的列是當(dāng)天的價(jià)格,但是股票有個(gè)叫做分拆的東西凄贩,其中一股突然就變成了兩股誓军,所以一股的價(jià)格要減半,但是公司的價(jià)值不變疲扎。修正的列為股票分拆而調(diào)整昵时,這使得它們對(duì)于分析更加可靠。

所以椒丧,讓我們繼續(xù)壹甥,削減原始的 DataFrame。

df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]

現(xiàn)在我們擁有了修正的列壶熏,以及成交量句柠。有一些東西需要注意。許多人談?wù)摶蛘呗犝f機(jī)器學(xué)習(xí)棒假,就像無中生有的黑魔法溯职。機(jī)器學(xué)習(xí)可以突出已有的數(shù)據(jù),但是數(shù)據(jù)需要先存在帽哑。你需要有意義的數(shù)據(jù)谜酒。所以你怎么知道是否有意義呢?我的最佳建議就是妻枕,僅僅簡化你的大腦僻族。考慮一下屡谐,歷史價(jià)格會(huì)決定未來價(jià)格嗎述么?有些人這么認(rèn)為,但是久而久之這被證實(shí)是錯(cuò)誤的愕掏。但是歷史規(guī)律呢度秘?突出的時(shí)候會(huì)有意義(機(jī)器學(xué)習(xí)會(huì)有所幫助),但是還是太弱了亭珍。那么敷钾,價(jià)格變化和成交量隨時(shí)間的關(guān)系枝哄,再加上歷史規(guī)律呢?可能更好一點(diǎn)阻荒。所以挠锥,你已經(jīng)能夠看到,并不是數(shù)據(jù)越多越好侨赡,而是我們需要使用有用處的數(shù)據(jù)蓖租。同時(shí),原始數(shù)據(jù)應(yīng)該做一些轉(zhuǎn)換羊壹。

考慮每日波動(dòng)蓖宦,例如最高價(jià)減最低價(jià)的百分比差值如何?每日的百分比變化又如何呢油猫?你覺得Open, High, Low, Close這種簡單數(shù)據(jù)稠茂,還是Close, Spread/Volatility, %change daily更好?我覺得后者更好一點(diǎn)情妖。前者都是非常相似的數(shù)據(jù)點(diǎn)睬关,后者基于前者的統(tǒng)一數(shù)據(jù)創(chuàng)建,但是帶有更加有價(jià)值的信息毡证。

所以电爹,并不是你擁有的所有數(shù)據(jù)都是有用的,并且有時(shí)你需要對(duì)你的數(shù)據(jù)執(zhí)行進(jìn)一步的操作料睛,并使其更加有價(jià)值丐箩,之后才能提供給機(jī)器學(xué)習(xí)算法。讓我們繼續(xù)并轉(zhuǎn)換我們的數(shù)據(jù):

df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0

這會(huì)創(chuàng)建一個(gè)新的列恤煞,它是基于收盤價(jià)的百分比極差屎勘,這是我們對(duì)于波動(dòng)的粗糙度量。下面阱州,我們會(huì)計(jì)算每日百分比變化:

df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

現(xiàn)在我們會(huì)定義一個(gè)新的 DataFrame:

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
print(df.head())
            Adj. Close    HL_PCT  PCT_change  Adj. Volume
Date                                                     
2004-08-19      50.170  8.072553    0.340000     44659000
2004-08-20      54.155  7.921706    7.227007     22834300
2004-08-23      54.700  4.049360   -1.218962     18256100
2004-08-24      52.435  7.657099   -5.726357     15247300
2004-08-25      53.000  3.886792    0.990854      9188600

特征和標(biāo)簽

基于上一篇機(jī)器學(xué)習(xí)回歸教程挑秉,我們將要對(duì)我們的股票價(jià)格數(shù)據(jù)執(zhí)行回歸。目前的代碼:

import quandl
import pandas as pd

df = quandl.get("WIKI/GOOGL")
df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0
df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
print(df.head())

這里我們已經(jīng)獲取了數(shù)據(jù)苔货,判斷出有價(jià)值的數(shù)據(jù),并通過操作創(chuàng)建了一些立哑。我們現(xiàn)在已經(jīng)準(zhǔn)備好使用回歸開始機(jī)器學(xué)習(xí)的過程夜惭。首先,我們需要一些更多的導(dǎo)入铛绰。所有的導(dǎo)入是:

import quandl, math
import numpy as np
import pandas as pd
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression

我們會(huì)使用numpy模塊來將數(shù)據(jù)轉(zhuǎn)換為 NumPy 數(shù)組诈茧,它是 Sklearn 的預(yù)期。我們?cè)谟玫?code>preprocessing和cross_validation時(shí)捂掰,會(huì)深入談?wù)撍麄兏一幔穷A(yù)處理是用于在機(jī)器學(xué)習(xí)之前曾沈,對(duì)數(shù)據(jù)清洗和縮放的模塊。交叉驗(yàn)證在測(cè)試階段使用鸥昏。最后塞俱,我們也從 Sklearn 導(dǎo)入了LinearRegression算法,以及svm吏垮。它們用作我們的機(jī)器學(xué)習(xí)算法來展示結(jié)果障涯。

這里,我們已經(jīng)獲取了我們認(rèn)為有用的數(shù)據(jù)膳汪。真實(shí)的機(jī)器學(xué)習(xí)如何工作呢唯蝶?使用監(jiān)督式學(xué)習(xí),你需要特征和標(biāo)簽遗嗽。特征就是描述性屬性粘我,標(biāo)簽就是你嘗試預(yù)測(cè)的結(jié)果。另一個(gè)常見的回歸示例就是嘗試為某個(gè)人預(yù)測(cè)保險(xiǎn)的保費(fèi)痹换。保險(xiǎn)公司會(huì)收集你的年齡涂滴、駕駛違規(guī)行為、公共犯罪記錄晴音,以及你的信用評(píng)分柔纵。公司會(huì)使用老客戶,獲取數(shù)據(jù)锤躁,并得出應(yīng)該給客戶的“理想保費(fèi)”搁料,或者如果他們覺得有利可圖的話,他們會(huì)使用實(shí)際使用的客戶系羞。

所以郭计,對(duì)于訓(xùn)練機(jī)器學(xué)習(xí)分類器來說,特征是客戶屬性椒振,標(biāo)簽是和這些屬性相關(guān)的保費(fèi)昭伸。

我們這里,什么是特征和標(biāo)簽?zāi)嘏煊课覀儑L試預(yù)測(cè)價(jià)格庐杨,所以價(jià)格就是標(biāo)簽?如果這樣夹供,什么是特征呢灵份?對(duì)于預(yù)測(cè)我們的價(jià)格來說,我們的標(biāo)簽哮洽,就是我們打算預(yù)測(cè)的東西填渠,實(shí)際上是未來價(jià)格盗似。這樣悄雅,我們的特征實(shí)際上是:當(dāng)前價(jià)格、HL 百分比和百分比變化。標(biāo)簽價(jià)格是未來某個(gè)點(diǎn)的價(jià)格缨叫。讓我們繼續(xù)添加新的行:

forecast_col = 'Adj. Close'
df.fillna(value=-99999, inplace=True)
forecast_out = int(math.ceil(0.01 * len(df)))

這里卒煞,我們定義了預(yù)測(cè)列狸驳,之后我們將任何 NaN 數(shù)據(jù)填充為 -99999毯侦。對(duì)于如何處理缺失數(shù)據(jù),你有一些選擇瑰谜,你不能僅僅將 NaN(不是數(shù)值)數(shù)據(jù)點(diǎn)傳給機(jī)器學(xué)習(xí)分類西欺冀,你需要處理它。一個(gè)主流選項(xiàng)就是將缺失值填充為 -99999萨脑。在許多機(jī)器學(xué)習(xí)分類器中隐轩,會(huì)將其是被為離群點(diǎn)。你也可以僅僅丟棄包含缺失值的所有特征或標(biāo)簽渤早,但是這樣你可能會(huì)丟掉大量的數(shù)據(jù)职车。

真實(shí)世界中,許多數(shù)據(jù)集都很混亂鹊杖。多數(shù)股價(jià)或成交量數(shù)據(jù)都很干凈悴灵,很少有缺失數(shù)據(jù),但是許多數(shù)據(jù)集會(huì)有大量缺失數(shù)據(jù)骂蓖。我見過一些數(shù)據(jù)集积瞒,大量的行含有缺失數(shù)據(jù)。你并不一定想要失去所有不錯(cuò)的數(shù)據(jù)登下,如果你的樣例數(shù)據(jù)有一些缺失茫孔,你可能會(huì)猜測(cè)真實(shí)世界的用例也有一些缺失。你需要訓(xùn)練被芳、測(cè)試并依賴相同數(shù)據(jù)缰贝,以及數(shù)據(jù)的特征。

最后畔濒,我們定義我們需要預(yù)測(cè)的東西剩晴。許多情況下,就像嘗試預(yù)測(cè)客戶的保費(fèi)的案例中侵状,你僅僅需要一個(gè)數(shù)字赞弥,但是對(duì)于預(yù)測(cè)來說,你需要預(yù)測(cè)指定數(shù)量的數(shù)據(jù)點(diǎn)壹将。我們假設(shè)我們打算預(yù)測(cè)數(shù)據(jù)集整個(gè)長度的 1%嗤攻。因此,如果我們的數(shù)據(jù)是 100 天的股票價(jià)格诽俯,我們需要能夠預(yù)測(cè)未來一天的價(jià)格。選擇你想要的那個(gè)。如果你只是嘗試預(yù)測(cè)明天的價(jià)格暴区,你應(yīng)該選取一天之后的數(shù)據(jù)闯团,而且也只能一天之后的數(shù)據(jù)。如果你打算預(yù)測(cè) 10 天仙粱,我們可以為每一天生成一個(gè)預(yù)測(cè)房交。

我們這里,我們決定了伐割,特征是一系列當(dāng)前值候味,標(biāo)簽是未來的價(jià)格,其中未來是數(shù)據(jù)集整個(gè)長度的 1%隔心。我們假設(shè)所有當(dāng)前列都是我們的特征白群,所以我們使用一個(gè)簡單的 Pnadas 操作添加一個(gè)新的列:

df['label'] = df[forecast_col].shift(-forecast_out)

現(xiàn)在我們擁有了數(shù)據(jù),包含特征和標(biāo)簽硬霍。下面我們?cè)趯?shí)際運(yùn)行任何東西之前帜慢,我們需要做一些預(yù)處理和最終步驟,我們?cè)谙乱黄坛虝?huì)關(guān)注唯卖。

訓(xùn)練和測(cè)試

歡迎閱讀 Python 機(jī)器學(xué)習(xí)系列教程的第四部分粱玲。在上一個(gè)教程中,我們獲取了初始數(shù)據(jù)拜轨,按照我們的喜好操作和轉(zhuǎn)換數(shù)據(jù)抽减,之后我們定義了我們的特征。Scikit 不需要處理 Pandas 和 DataFrame橄碾,我出于自己的喜好而處理它卵沉,因?yàn)樗觳⑶腋咝А7粗吧琒klearn 實(shí)際上需要 NumPy 數(shù)組偎箫。Pandas 的 DataFrame 可以輕易轉(zhuǎn)換為 NumPy 數(shù)組,所以事情就是這樣的皆串。

目前為止我們的代碼:

import quandl, math
import numpy as np
import pandas as pd
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression

df = quandl.get("WIKI/GOOGL")

print(df.head())
#print(df.tail())

df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]

df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
print(df.head())

forecast_col = 'Adj. Close'
df.fillna(value=-99999, inplace=True)
forecast_out = int(math.ceil(0.01 * len(df)))

df['label'] = df[forecast_col].shift(-forecast_out)

我們之后要丟棄所有仍舊是 NaN 的信息淹办。

df.dropna(inplace=True)

對(duì)于機(jī)器學(xué)習(xí)來說,通常要定義X(大寫)作為特征恶复,和y(小寫)作為對(duì)于特征的標(biāo)簽怜森。這樣,我們可以定義我們的特征和標(biāo)簽谤牡,像這樣:

X = np.array(df.drop(['label'], 1))
y = np.array(df['label'])

上面副硅,我們所做的就是定義X(特征),是我們整個(gè)的 DataFrame翅萤,除了label列恐疲,并轉(zhuǎn)換為 NumPy 數(shù)組。我們使用drop方法,可以用于 DataFrame培己,它返回一個(gè)新的 DataFrame碳蛋。下面,我們定義我們的y變量省咨,它是我們的標(biāo)簽肃弟,僅僅是 DataFrame 的標(biāo)簽列,并轉(zhuǎn)換為 NumPy 數(shù)組零蓉。

現(xiàn)在我們就能告一段落笤受,轉(zhuǎn)向訓(xùn)練和測(cè)試了,但是我們打算做一些預(yù)處理敌蜂。通常箩兽,你希望你的特征在 -1 到 1 的范圍內(nèi)。這可能不起作用紊册,但是通常會(huì)加速處理過程比肄,并有助于準(zhǔn)確性。因?yàn)榇蠹叶际褂眠@個(gè)范圍囊陡,它包含在了 Sklearn 的preprocessing模塊中芳绩。為了使用它,你需要對(duì)你的X變量調(diào)用preprocessing.scale撞反。

X = preprocessing.scale(X)

下面妥色,創(chuàng)建標(biāo)簽y

y = np.array(df['label'])

現(xiàn)在就是訓(xùn)練和測(cè)試的時(shí)候了。方式就是選取 75% 的數(shù)據(jù)用于訓(xùn)練機(jī)器學(xué)習(xí)分類器遏片。之后選取剩下的 25% 的數(shù)據(jù)用于測(cè)試分類器嘹害。由于這是你的樣例數(shù)據(jù),你應(yīng)該擁有特征和一直標(biāo)簽吮便。因此笔呀,如果你測(cè)試后 25% 的數(shù)據(jù),你就會(huì)得到一種準(zhǔn)確度和可靠性髓需,叫做置信度许师。有許多方式可以實(shí)現(xiàn)它,但是僚匆,最好的方式可能就是使用內(nèi)建的cross_validation微渠,因?yàn)樗矔?huì)為你打亂數(shù)據(jù)。代碼是這樣:

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)

這里的返回值是特征的訓(xùn)練集咧擂、測(cè)試集逞盆、標(biāo)簽的訓(xùn)練集和測(cè)試集。現(xiàn)在松申,我們已經(jīng)定義好了分類器云芦。Sklearn 提供了許多通用的分類器俯逾,有一些可以用于回歸。我們會(huì)在這個(gè)例子中展示一些焕数,但是現(xiàn)在纱昧,讓我們使用svm包中的支持向量回歸刨啸。

clf = svm.SVR()

我們這里僅僅使用默認(rèn)選項(xiàng)來使事情簡單堡赔,但是你可以在sklearn.svm.SVR的文檔中了解更多。

一旦你定義了分類器设联,你就可以訓(xùn)練它了善已。在 Sklearn 中,使用fit來訓(xùn)練离例。

clf.fit(X_train, y_train)

這里换团,我們擬合了我們的訓(xùn)練特征和訓(xùn)練標(biāo)簽。

我們的分類器現(xiàn)在訓(xùn)練完畢宫蛆。這非常簡單艘包,現(xiàn)在我們可以測(cè)試了。

confidence = clf.score(X_test, y_test)

加載測(cè)試耀盗,之后:

print(confidence)
# 0.960075071072

所以這里想虎,我們可以看到準(zhǔn)確率幾乎是 96%。沒有什么可說的叛拷,讓我們嘗試另一個(gè)分類器舌厨,這一次使用LinearRegression

clf = LinearRegression()
# 0.963311624499

更好一點(diǎn),但是基本一樣忿薇。所以作為科學(xué)家裙椭,我們?nèi)绾沃溃x擇哪個(gè)算法呢署浩?不久揉燃,你會(huì)熟悉什么在多數(shù)情況下都工作,什么不工作筋栋。你可以從 Scikit 的站點(diǎn)上查看選擇正確的評(píng)估工具炊汤。這有助于你瀏覽一些基本的選項(xiàng)。如果你詢問搞機(jī)器學(xué)習(xí)的人二汛,它完全是試驗(yàn)和出錯(cuò)婿崭。你會(huì)嘗試大量的算法并且僅僅選取最好的那個(gè)。要注意的另一件事情就是肴颊,一些算法必須線性運(yùn)行氓栈,其它的不是。不要把線性回歸和線性運(yùn)行搞混了婿着。所以這些意味著什么呢授瘦?一些機(jī)器學(xué)習(xí)算法會(huì)一次處理一步醋界,沒有多線程,其它的使用多線程提完,并且可以利用你機(jī)器上的多核形纺。你可以深入了解每個(gè)算法,來弄清楚哪個(gè)可以多線程徒欣,或者你可以閱讀文檔逐样,并查看n_jobs參數(shù)。如果擁有n_jobs打肝,你就可以讓算法通過多線程來獲取更高的性能脂新。如果沒有狈定,就很不走運(yùn)了号阿。所以,如果你處理大量的數(shù)據(jù)完疫,或者需要處理中等規(guī)模的數(shù)據(jù)断医,但是需要很高的速度滞乙,你就可能想要線程加速。讓我們看看這兩個(gè)算法鉴嗤。

訪問sklearn.svm.SVR的文檔斩启,并查看參數(shù),看到n_jobs了嘛躬窜?反正我沒看到浇垦,所以它就不能使用線程。你可能會(huì)看到荣挨,在我們的小型數(shù)據(jù)集上男韧,差異不大。但是默垄,假設(shè)數(shù)據(jù)集由 20MB此虑,差異就很明顯。然后口锭,我們查看LinearRegression算法朦前,看到n_jobs了嘛?當(dāng)然鹃操,所以這里韭寸,你可以指定你希望多少線程。如果你傳入-1荆隘,算法會(huì)使用所有可用的線程恩伺。

這樣:

clf = LinearRegression(n_jobs=-1)

就夠了。雖然我讓你做了很少的事情(查看文檔)椰拒,讓我給你說個(gè)事實(shí)吧晶渠,僅僅由于機(jī)器學(xué)習(xí)算法使用默認(rèn)參數(shù)工作凰荚,不代表你可以忽略它們。例如褒脯,讓我們回顧svm.SVR便瑟。SVR 是支持向量回歸,在執(zhí)行機(jī)器學(xué)習(xí)時(shí)番川,它是一種架構(gòu)到涂。我非常鼓勵(lì)那些有興趣學(xué)習(xí)更多的人,去研究這個(gè)主題爽彤,以及向比我學(xué)歷更高的人學(xué)習(xí)基礎(chǔ)养盗。我會(huì)盡力把東西解釋得更簡單,但是我并不是專家适篙。回到剛才的話題箫爷,svm.SVR有一個(gè)參數(shù)叫做kernel嚷节。這個(gè)是什么呢?核就相當(dāng)于你的數(shù)據(jù)的轉(zhuǎn)換虎锚。這使得處理過程更加迅速硫痰。在svm.SVR的例子中,默認(rèn)值是rbf窜护,這是核的一個(gè)類型效斑,你有一些選擇。查看文檔柱徙,你可以選擇'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'或者一個(gè)可調(diào)用對(duì)象缓屠。同樣,就像嘗試不同的 ML 算法一樣护侮,你可以做你想做的任何事情敌完,嘗試一下不同的核吧。

for k in ['linear','poly','rbf','sigmoid']:
    clf = svm.SVR(kernel=k)
    clf.fit(X_train, y_train)
    confidence = clf.score(X_test, y_test)
    print(k,confidence)
linear 0.960075071072
poly 0.63712232551
rbf 0.802831714511
sigmoid -0.125347960903

我們可以看到羊初,線性的核表現(xiàn)最好滨溉,之后是rbf,之后是poly长赞,sigmoid很顯然是個(gè)擺設(shè)晦攒,并且應(yīng)該移除。

所以我們訓(xùn)練并測(cè)試了數(shù)據(jù)集得哆。我們已經(jīng)有 71% 的滿意度了脯颜。下面我們做什么呢?現(xiàn)在我們需要再進(jìn)一步柳恐,做一些預(yù)測(cè)伐脖,下一章會(huì)涉及它热幔。

預(yù)測(cè)

歡迎閱讀機(jī)器學(xué)習(xí)系列教程的第五章,當(dāng)前涉及到回歸讼庇。目前為止绎巨,我們收集并修改了數(shù)據(jù),訓(xùn)練并測(cè)試了分類器蠕啄。這一章中场勤,我們打算使用我們的分類器來實(shí)際做一些預(yù)測(cè)。我們目前所使用的代碼為:

import quandl, math
import numpy as np
import pandas as pd
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression

df = quandl.get("WIKI/GOOGL")
df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
forecast_col = 'Adj. Close'
df.fillna(value=-99999, inplace=True)
forecast_out = int(math.ceil(0.01 * len(df)))
df['label'] = df[forecast_col].shift(-forecast_out)

X = np.array(df.drop(['label'], 1))
X = preprocessing.scale(X)
X = X[:-forecast_out]
df.dropna(inplace=True)
y = np.array(df['label'])
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)

clf = LinearRegression(n_jobs=-1)
clf.fit(X_train, y_train)
confidence = clf.score(X_test, y_test)
print(confidence)

我會(huì)強(qiáng)調(diào)歼跟,準(zhǔn)確率大于 95% 的線性模型并不是那么好和媳。我當(dāng)然不會(huì)用它來交易股票。仍然有一些需要考慮的問題哈街,特別是不同公司有不同的價(jià)格軌跡留瞳。Google 非常線性,向右上角移動(dòng)骚秦,許多公司不是這樣她倘,所以要記住。現(xiàn)在作箍,為了做預(yù)測(cè)硬梁,我們需要一些數(shù)據(jù)。我們決定預(yù)測(cè) 1% 的數(shù)據(jù)胞得,因此我們打算荧止,或者至少能夠預(yù)測(cè)數(shù)據(jù)集的后 1%。所以我們什么可以這樣做呢阶剑?我們什么時(shí)候可以識(shí)別這些數(shù)據(jù)跃巡?我們現(xiàn)在就可以,但是要注意我們嘗試預(yù)測(cè)的數(shù)據(jù)个扰,并沒有像訓(xùn)練集那樣縮放瓷炮。好的,那么做什么呢递宅?是否要對(duì)后 1% 調(diào)用preprocessing.scale()娘香?縮放方法基于所有給它的已知數(shù)據(jù)集。理想情況下办龄,你應(yīng)該一同縮放訓(xùn)練集烘绽、測(cè)試集和用于預(yù)測(cè)的數(shù)據(jù)。這永遠(yuǎn)是可能或合理的嘛俐填?不是安接,如果你可以這么做,你就應(yīng)該這么做英融。但是盏檐,我們這里歇式,我們可以這么做。我們的數(shù)據(jù)足夠小胡野,并且處理時(shí)間足夠低材失,所以我們會(huì)一次性預(yù)處理并縮放數(shù)據(jù)。

在許多例子中硫豆,你不能這么做龙巨。想象如果你使用幾個(gè) GB 的數(shù)據(jù)來訓(xùn)練分類器。訓(xùn)練分類器會(huì)花費(fèi)幾天熊响,不能在每次想要做出預(yù)測(cè)的時(shí)候都這么做旨别。因此,你可能需要不縮放任何東西汗茄,或者單獨(dú)縮放數(shù)據(jù)秸弛。通常,你可能希望測(cè)試這兩個(gè)選項(xiàng)剔难,并看看那個(gè)對(duì)于你的特定案例更好胆屿。

要記住它,讓我們?cè)诙xX的時(shí)候處理所有行:

X = np.array(df.drop(['label'], 1))
X = preprocessing.scale(X)
X_lately = X[-forecast_out:]
X = X[:-forecast_out]

df.dropna(inplace=True)

y = np.array(df['label'])

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
clf = LinearRegression(n_jobs=-1)
clf.fit(X_train, y_train)
confidence = clf.score(X_test, y_test)
print(confidence)

要注意我們首先獲取所有數(shù)據(jù)偶宫,預(yù)處理,之后再分割环鲤。我們的X_lately變量包含最近的特征纯趋,我們需要對(duì)其進(jìn)行預(yù)測(cè)。目前你可以看到冷离,定義分類器吵冒、訓(xùn)練、和測(cè)試都非常簡單西剥。預(yù)測(cè)也非常簡單:

forecast_set = clf.predict(X_lately)

forecast_set是預(yù)測(cè)值的數(shù)組痹栖,表明你不僅僅可以做出單個(gè)預(yù)測(cè),還可以一次性預(yù)測(cè)多個(gè)值瞭空【景ⅲ看看我們目前擁有什么:

[ 745.67829395  737.55633261  736.32921413  717.03929303  718.59047951
  731.26376715  737.84381394  751.28161162  756.31775293  756.76751056
  763.20185946  764.52651181  760.91320031  768.0072636   766.67038016
  763.83749414  761.36173409  760.08514166  770.61581391  774.13939706
  768.78733341  775.04458624  771.10782342  765.13955723  773.93369548
  766.05507556  765.4984563   763.59630529  770.0057166   777.60915879] 0.956987938167 30

所以這些就是我們的預(yù)測(cè)結(jié)果,然后呢咆畏?已經(jīng)基本完成了南捂,但是我們可以將其可視化。股票價(jià)格是每一天的旧找,一周 5 天溺健,周末沒有。我知道這個(gè)事實(shí)钮蛛,但是我們打算將其簡化鞭缭,把每個(gè)預(yù)測(cè)值當(dāng)成每一天的剖膳。如果你打算處理周末的間隔(不要忘了假期),就去做吧岭辣,但是我這里會(huì)將其簡化吱晒。最開始,我們添加一些新的導(dǎo)入:

import datetime
import matplotlib.pyplot as plt
from matplotlib import style

我導(dǎo)入了datetime來處理datetime對(duì)象易结,Matplotlib 的pyplot包用于繪圖枕荞,以及style來使我們的繪圖更加時(shí)髦。讓我們?cè)O(shè)置一個(gè)樣式:

style.use('ggplot')

之后搞动,我們添加一個(gè)新的列躏精,forecast列:

df['Forecast'] = np.nan

我們首先將值設(shè)置為 NaN,但是我們之后會(huì)填充他鹦肿。

預(yù)測(cè)集的標(biāo)簽正好從明天開始矗烛。因?yàn)槲覀円A(yù)測(cè)未來m = 0.1 * len(df)天的數(shù)據(jù),相當(dāng)于把收盤價(jià)往前移動(dòng)m天生成標(biāo)簽箩溃。那么數(shù)據(jù)集的后m個(gè)是不能用作訓(xùn)練集和測(cè)試集的瞭吃,因?yàn)闆]有標(biāo)簽。于是我們將后m個(gè)數(shù)據(jù)用作預(yù)測(cè)集涣旨。預(yù)測(cè)集的第一個(gè)數(shù)據(jù)歪架,也就是數(shù)據(jù)集的第n - m個(gè)數(shù)據(jù),它的標(biāo)簽應(yīng)該是n - m + m = n天的收盤價(jià)霹陡,我們知道今天在df里面是第n - 1天和蚪,那么它就是明天。

我們首先需要抓取 DataFrame 的最后一天烹棉,將每一個(gè)新的預(yù)測(cè)值賦給新的日期攒霹。我們會(huì)這樣開始。

last_date = df.iloc[-1].name
last_unix = last_date.timestamp()
one_day = 86400
next_unix = last_unix + one_day

現(xiàn)在我們擁有了預(yù)測(cè)集的起始日期浆洗,并且一天有 86400 秒〈呤現(xiàn)在我們將預(yù)測(cè)添加到現(xiàn)有的 DataFrame 中。

for i in forecast_set:
    next_date = datetime.datetime.fromtimestamp(next_unix)
    next_unix += 86400
    df.loc[next_date] = [np.nan for _ in range(len(df.columns)-1)]+[i]

我們這里所做的是,迭代預(yù)測(cè)集的標(biāo)簽,獲取每個(gè)預(yù)測(cè)值和日期包斑,之后將這些值放入 DataFrame(使預(yù)測(cè)集的特征為 NaN)。最后一行的代碼創(chuàng)建 DataFrame 中的一行矫付,所有元素置為 NaN,然后將最后一個(gè)元素置為i(這里是預(yù)測(cè)集的標(biāo)簽)第焰。我選擇了這種單行的for循環(huán)买优,以便在改動(dòng) DataFrame 和特征之后,代碼還能正常工作。所有東西都做完了嗎杀赢?將其繪制出來烘跺。

df['Adj. Close'].plot()
df['Forecast'].plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

完整的代碼:

import Quandl, math
import numpy as np
import pandas as pd
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
from matplotlib import style
import datetime

style.use('ggplot')

df = Quandl.get("WIKI/GOOGL")
df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
forecast_col = 'Adj. Close'
df.fillna(value=-99999, inplace=True)
forecast_out = int(math.ceil(0.01 * len(df)))
df['label'] = df[forecast_col].shift(-forecast_out)

X = np.array(df.drop(['label'], 1))
X = preprocessing.scale(X)
X_lately = X[-forecast_out:]
X = X[:-forecast_out]

df.dropna(inplace=True)

y = np.array(df['label'])

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
clf = LinearRegression(n_jobs=-1)
clf.fit(X_train, y_train)
confidence = clf.score(X_test, y_test)

forecast_set = clf.predict(X_lately)
df['Forecast'] = np.nan

last_date = df.iloc[-1].name
last_unix = last_date.timestamp()
one_day = 86400
next_unix = last_unix + one_day

for i in forecast_set:
    next_date = datetime.datetime.fromtimestamp(next_unix)
    next_unix += 86400
    df.loc[next_date] = [np.nan for _ in range(len(df.columns)-1)]+[i]

df['Adj. Close'].plot()
df['Forecast'].plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

結(jié)果:

保存和擴(kuò)展

上一篇教程中,我們使用回歸完成了對(duì)股票價(jià)格的預(yù)測(cè)脂崔,并使用 Matplotlib 可視化滤淳。這個(gè)教程中,我們會(huì)討論一些接下來的步驟砌左。

我記得我第一次嘗試學(xué)習(xí)機(jī)器學(xué)習(xí)的時(shí)候脖咐,多數(shù)示例僅僅涉及到訓(xùn)練和測(cè)試的部分,完全跳過了預(yù)測(cè)部分汇歹。對(duì)于那些包含訓(xùn)練屁擅、測(cè)試和預(yù)測(cè)部分的教程來說,我沒有找到一篇解釋保存算法的文章产弹。在那些例子中派歌,數(shù)據(jù)通常非常小,所以訓(xùn)練痰哨、測(cè)試和預(yù)測(cè)過程都很快胶果。在真實(shí)世界中,數(shù)據(jù)都非常大斤斧,并且花費(fèi)更長時(shí)間來處理早抠。由于沒有一篇教程真正談?wù)摰竭@一重要的過程,我打算包含一些處理時(shí)間和保存算法的信息撬讽。

雖然我們的機(jī)器學(xué)習(xí)分類器花費(fèi)幾秒來訓(xùn)練贝或,在一些情況下,訓(xùn)練分類器需要幾個(gè)小時(shí)甚至是幾天锐秦。想象你想要預(yù)測(cè)價(jià)格的每天都需要這么做。這不是必要的盗忱,因?yàn)槲覀兡乜梢允褂?Pickle 模塊來保存分類器酱床。首先確保你導(dǎo)入了它:

import pickle

使用 Pickle,你可以保存 Python 對(duì)象趟佃,就像我們的分類器那樣扇谣。在定義、訓(xùn)練和測(cè)試你的分類器之后闲昭,添加:

with open('linearregression.pickle','wb') as f:
    pickle.dump(clf, f)

現(xiàn)在罐寨,再次執(zhí)行腳本,你應(yīng)該得到了linearregression.pickle序矩,它是分類器的序列化數(shù)據(jù)⊙炻蹋現(xiàn)在,你需要做的所有事情就是加載pickle文件,將其保存到clf瓶蝴,并照常使用毒返,例如:

pickle_in = open('linearregression.pickle','rb')
clf = pickle.load(pickle_in)

代碼中:

import Quandl, math
import numpy as np
import pandas as pd
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
from matplotlib import style
import datetime
import pickle

style.use('ggplot')

df = Quandl.get("WIKI/GOOGL")
df = df[['Adj. Open',  'Adj. High',  'Adj. Low',  'Adj. Close', 'Adj. Volume']]
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Low']) / df['Adj. Close'] * 100.0
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
forecast_col = 'Adj. Close'
df.fillna(value=-99999, inplace=True)
forecast_out = int(math.ceil(0.1 * len(df)))

df['label'] = df[forecast_col].shift(-forecast_out)

X = np.array(df.drop(['label'], 1))
X = preprocessing.scale(X)
X_lately = X[-forecast_out:]
X = X[:-forecast_out]

df.dropna(inplace=True)

y = np.array(df['label'])

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
#COMMENTED OUT:
##clf = svm.SVR(kernel='linear')
##clf.fit(X_train, y_train)
##confidence = clf.score(X_test, y_test)
##print(confidence)
pickle_in = open('linearregression.pickle','rb')
clf = pickle.load(pickle_in)


forecast_set = clf.predict(X_lately)
df['Forecast'] = np.nan

last_date = df.iloc[-1].name
last_unix = last_date.timestamp()
one_day = 86400
next_unix = last_unix + one_day

for i in forecast_set:
    next_date = datetime.datetime.fromtimestamp(next_unix)
    next_unix += 86400
    df.loc[next_date] = [np.nan for _ in range(len(df.columns)-1)]+[i]
df['Adj. Close'].plot()
df['Forecast'].plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

要注意我們注釋掉了分類器的原始定義,并替換為加載我們保存的分類器舷手。就是這么簡單拧簸。

最后,我們要討論一下效率和保存時(shí)間男窟,前幾天我打算提出一個(gè)相對(duì)較低的范式盆赤,這就是臨時(shí)的超級(jí)計(jì)算機(jī)。嚴(yán)肅地說歉眷,隨著按需主機(jī)服務(wù)的興起牺六,例如 AWS、DO 和 Linode姥芥,你能夠按照小時(shí)來購買主機(jī)兔乞。虛擬服務(wù)器可以在 60 秒內(nèi)建立,所需的模塊可以在 15 分鐘內(nèi)安裝凉唐,所以非常有限庸追。你可以寫一個(gè) shell 腳本或者什么東西來給它加速√ù眩考慮你需要大量的處理淡溯,并且還沒有一臺(tái)頂級(jí)計(jì)算機(jī),或者你使用筆記本簿训。沒有問題咱娶,只需要啟動(dòng)一臺(tái)服務(wù)器。

我對(duì)這個(gè)方式的最后一個(gè)注解是强品,使用任何主機(jī)膘侮,你通常都可以建立一個(gè)非常小型的服務(wù)器,加載所需的東西的榛,之后擴(kuò)展這個(gè)服務(wù)器琼了。我喜歡以一個(gè)小型服務(wù)器開始,之后夫晌,我準(zhǔn)備好的時(shí)候雕薪,我會(huì)改變它的尺寸,給它升級(jí)晓淀。完成之后所袁,不要忘了注銷或者降級(jí)你的服務(wù)器。

理論以及工作原理

歡迎閱讀第七篇教程凶掰。目前為止燥爷,你已經(jīng)看到了線性回歸的價(jià)值蜈亩,以及如何使用 Sklearn 來應(yīng)用它。現(xiàn)在我們打算深入了解它如何計(jì)算局劲。雖然我覺得不必要深入到每個(gè)機(jī)器學(xué)習(xí)算法數(shù)學(xué)中(你有沒有進(jìn)入到你最喜歡的模塊的源碼中勺拣,看看它是如何實(shí)現(xiàn)的?)鱼填,線性代數(shù)是機(jī)器學(xué)習(xí)的本質(zhì)药有,并且對(duì)于理解機(jī)器學(xué)習(xí)的構(gòu)建基礎(chǔ)十分實(shí)用。

線性代數(shù)的目標(biāo)是計(jì)算向量空間中的點(diǎn)的關(guān)系苹丸。這可以用于很多事情愤惰,但是某天,有個(gè)人有了個(gè)非匙咐恚狂野的想法宦言,拿他處理數(shù)據(jù)集的特征。我們也可以商模。記得之前我們定義數(shù)據(jù)類型的時(shí)候奠旺,線性回歸處理連續(xù)數(shù)據(jù)嗎?這并不是因?yàn)槭褂镁€性回歸的人施流,而是因?yàn)榻M成它的數(shù)學(xué)响疚。簡單的線性回歸可用于尋找數(shù)據(jù)集的最佳擬合直線。如果數(shù)據(jù)不是連續(xù)的瞪醋,就不是最佳擬合直線忿晕。讓我們看看一些示例。

協(xié)方差

上面的圖像顯然擁有良好的協(xié)方差银受。如果你通過估計(jì)畫一條最佳擬合直線践盼,你應(yīng)該能夠輕易畫出來:

如果圖像是這樣呢?

并不和之前一樣宾巍,但是是清楚的負(fù)相關(guān)咕幻。你可能能夠畫出最佳擬合直線,但是更可能畫不出來顶霞。

最后谅河,這個(gè)呢?

啥确丢?的確有最佳擬合直線,但是需要運(yùn)氣將其畫出來吐限。

將上面的圖像看做特征的圖像鲜侥,所以 X 坐標(biāo)是特征,Y 坐標(biāo)是相關(guān)的標(biāo)簽诸典。X 和 Y 是否有任何形式的結(jié)構(gòu)化關(guān)系呢描函?雖然我們可以準(zhǔn)確計(jì)算關(guān)系,未來我們就不太可能擁有這么多值了。

在其它圖像的案例中舀寓,X 和 Y 之間顯然存在關(guān)系胆数。我們實(shí)際上可以探索這種關(guān)系,之后沿著我們希望的任何點(diǎn)繪圖互墓。我們可以拿 Y 來預(yù)測(cè) X必尼,或者拿 X 來預(yù)測(cè) Y,對(duì)于任何我們可以想到的點(diǎn)篡撵。我們也可以預(yù)測(cè)我們的模型有多少的誤差判莉,即使模型只有一個(gè)點(diǎn)。我們?nèi)绾螌?shí)現(xiàn)這個(gè)魔法呢育谬?當(dāng)然是線性代數(shù)券盅。

首先,讓我們回到中學(xué)膛檀,我們?cè)谀抢飶?fù)習(xí)直線的定義:y = mx + b锰镀,其中m是斜率,b是縱截距咖刃。這可以是用于求解y的方程泳炉,我們可以將其變形來求解x,使用基本的代數(shù)原則:x = (y-b)/m僵缺。

好的胡桃,所以,我們的目標(biāo)是尋找最佳擬合直線磕潮。不是僅僅是擬合良好的直線翠胰,而是最好的那條。這條直線的定義就是y = mx + b自脯。y就是答案(我們其他的坐標(biāo)之景,或者甚至是我們的特征),所以我們?nèi)匀恍枰?code>m(斜率)和b(縱截距)膏潮,由于x可能為沿 x 軸的任一點(diǎn)锻狗,所以它是已知的。

最佳擬合直線的斜率m定義為:

注:可簡寫為m = cov(x, y) / var(x)焕参。

符號(hào)上面的橫杠代表均值轻纪。如果兩個(gè)符號(hào)挨著,就將其相乘叠纷。xs 和 ys 是所有已知坐標(biāo)刻帚。所以我們現(xiàn)在求出了y=mx+b最佳擬合直線定義的m(斜率),現(xiàn)在我們僅僅需要b(縱截距)涩嚣。這里是公式:

好的崇众。整個(gè)部分不是個(gè)數(shù)學(xué)教程掂僵,而是個(gè)編程教程。下一個(gè)教程中顷歌,我們打算這樣做锰蓬,并且解釋為什么我要編程實(shí)現(xiàn)它,而不是直接用模塊眯漩。

編程計(jì)算斜率

歡迎閱讀第八篇教程芹扭,我們剛剛意識(shí)到,我們需要使用 Python 重復(fù)編寫一些比較重要的算法坤塞,來嘗試給定數(shù)據(jù)集的計(jì)算最佳擬合直線冯勉。

在我們開始之前,為什么我們會(huì)有一些小麻煩呢摹芙?線性回歸是機(jī)器學(xué)習(xí)的構(gòu)建基礎(chǔ)灼狰。它幾乎用于每個(gè)單獨(dú)的主流機(jī)器學(xué)習(xí)算法之中,所以對(duì)它的理解有助于你掌握多數(shù)主流機(jī)器學(xué)習(xí)算法浮禾。出于我們的熱情交胚,理解線性回歸和線性代數(shù),是編寫你自己的機(jī)器學(xué)習(xí)算法盈电,以及跨入機(jī)器學(xué)習(xí)前沿蝴簇,使用當(dāng)前最佳的處理過程的第一步。由于處理過程的優(yōu)化和硬件架構(gòu)的改變匆帚。用于機(jī)器學(xué)習(xí)的方法論也會(huì)改變熬词。最近出現(xiàn)的神經(jīng)網(wǎng)絡(luò),使用大量 GPU 來完成工作吸重。你想知道什么是神經(jīng)網(wǎng)絡(luò)的核心嗎互拾?你猜對(duì)了九昧,線性代數(shù)税稼。

如果你能記得粘室,最佳擬合直線的斜率m

是的呈队,我們會(huì)將其拆成片段。首先天吓,進(jìn)行一些導(dǎo)入:

from statistics import mean
import numpy as np

我們從statistics導(dǎo)入mean鲫凶,所以我們可以輕易獲取列表的均值许布。下面替废,我們使numpy as np箍铭,所以我們可以其創(chuàng)建 NumPy 數(shù)組。我們可以對(duì)列表做很多事情椎镣,但是我們需要能夠做一些簡單的矩陣運(yùn)算坡疼,它并不對(duì)簡單列表提供,所以我們使用 NumPy衣陶。我們?cè)谶@個(gè)階段不會(huì)使用太復(fù)雜的 NumPy柄瑰,但是之后 NumPy 就會(huì)成為你的最佳伙伴。下面剪况,讓我們定義一些起始點(diǎn)吧教沾。

xs = [1,2,3,4,5]
ys = [5,4,6,5,6]

所以這里有一些我們要使用的數(shù)據(jù)點(diǎn),xsys译断。你可以認(rèn)為xs就是特征授翻,ys就是標(biāo)簽,或者他們都是特征孙咪,我們想要建立他們的聯(lián)系堪唐。之前提到過,我們實(shí)際上把它們變成 NumPy 數(shù)組翎蹈,以便執(zhí)行矩陣運(yùn)算淮菠。所以讓我們修改這兩行:

xs = np.array([1,2,3,4,5], dtype=np.float64)
ys = np.array([5,4,6,5,6], dtype=np.float64)

現(xiàn)在他們都是 NumPy 數(shù)組了。我們也顯式聲明了數(shù)據(jù)類型荤堪。簡單講一下合陵,數(shù)據(jù)類型有特性是屬性,這些屬性決定了數(shù)據(jù)本身如何儲(chǔ)存和操作〕窝簦現(xiàn)在它不是什么問題拥知,但是如果我們執(zhí)行大量運(yùn)算,并希望他們跑在 GPU 而不是 CPU 上就是了碎赢。

將其畫出來低剔,他們是:

現(xiàn)在我們準(zhǔn)備好構(gòu)建函數(shù)來計(jì)算m,也就是我們的直線斜率:

def best_fit_slope(xs,ys):
    return m

m = best_fit_slope(xs,ys)

好了肮塞。開個(gè)玩笑襟齿,所以這是我們的框架,現(xiàn)在我們要填充了峦嗤。

我們的第一個(gè)邏輯就是計(jì)算xs的均值蕊唐,再乘上ys的均值。繼續(xù)填充我們的框架:

def best_fit_slope(xs,ys):
    m = (mean(xs) * mean(ys))
    return m

目前為止還很簡單烁设。你可以對(duì)列表替梨、元組或者數(shù)組使用mean函數(shù)。要注意我這里使用了括號(hào)装黑。Python 的遵循運(yùn)算符的數(shù)學(xué)優(yōu)先級(jí)副瀑。所以如果你打算保證順序,要顯式使用括號(hào)恋谭。要記住你的運(yùn)算規(guī)則糠睡。

下面我們需要將其減去x*y的均值。這既是我們的矩陣運(yùn)算mean(xs*ys)【渭眨現(xiàn)在的代碼是:

def best_fit_slope(xs,ys):
    m = ( (mean(xs)*mean(ys)) - mean(xs*ys) )
    return m

我們完成了公式的分子部分狈孔,現(xiàn)在我們繼續(xù)處理的分母信认,以x的均值平方開始:(mean(xs)*mean(xs))。Python 支持** 2均抽,能夠處理我們的 NumPy 數(shù)組的float64類型嫁赏。添加這些東西:

def best_fit_slope(xs,ys):
    m = ( ((mean(xs)*mean(ys)) - mean(xs*ys)) /
           (mean(xs)**2))
    return m

雖然根據(jù)運(yùn)算符優(yōu)先級(jí),向整個(gè)表達(dá)式添加括號(hào)是不必要的油挥。我這里這樣做潦蝇,所以我可以在除法后面添加一行,使整個(gè)式子更加易讀和易理解深寥。不這樣的話攘乒,我們會(huì)在新的一行得到語法錯(cuò)誤。我們幾乎完成了惋鹅,現(xiàn)在我們只需要將x的均值平方和x的平方均值(mean(xs*xs))相減则酝。全部代碼為:

def best_fit_slope(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)**2) - mean(xs*xs)))
    return m

好的,現(xiàn)在我們的完整腳本為:

from statistics import mean
import numpy as np

xs = np.array([1,2,3,4,5], dtype=np.float64)
ys = np.array([5,4,6,5,6], dtype=np.float64)

def best_fit_slope(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)**2) - mean(xs**2)))
    return m

m = best_fit_slope(xs,ys)
print(m)
# 0.3

下面干什么负饲?我們需要計(jì)算縱截距b堤魁。我們會(huì)在下一個(gè)教程中處理它,并完成完整的最佳擬合直線計(jì)算返十。它比斜率更佳易于計(jì)算妥泉,嘗試編寫你自己的函數(shù)來計(jì)算它。如果你做到了洞坑,也不要跳過下一個(gè)教程盲链,我們會(huì)做一些別的事情。

計(jì)算縱截距

歡迎閱讀第九篇教程迟杂。我們當(dāng)前正在為給定的數(shù)據(jù)集刽沾,使用 Python 計(jì)算回歸或者最佳擬合直線。之前排拷,我們編寫了一個(gè)函數(shù)來計(jì)算斜率侧漓,現(xiàn)在我們需要計(jì)算縱截距。我們目前的代碼是:

from statistics import mean
import numpy as np

xs = np.array([1,2,3,4,5], dtype=np.float64)
ys = np.array([5,4,6,5,6], dtype=np.float64)

def best_fit_slope(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)*mean(xs)) - mean(xs*xs)))
    return m

m = best_fit_slope(xs,ys)
print(m)

請(qǐng)回憶监氢,最佳擬合直線的縱截距是:

這個(gè)比斜率簡單多了布蔗。我們可以將其寫到同一個(gè)函數(shù)來節(jié)省幾行代碼。我們將函數(shù)重命名為best_fit_slope_and_intercept浪腐。

下面纵揍,我們可以填充b = mean(ys) - (m*mean(xs)),并返回m, b

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)*mean(xs)) - mean(xs*xs)))
    
    b = mean(ys) - m*mean(xs)
    
    return m, b

現(xiàn)在我們可以調(diào)用它:

best_fit_slope_and_intercept(xs,ys)

我們目前為止的代碼:

from statistics import mean
import numpy as np

xs = np.array([1,2,3,4,5], dtype=np.float64)
ys = np.array([5,4,6,5,6], dtype=np.float64)

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)*mean(xs)) - mean(xs*xs)))
    
    b = mean(ys) - m*mean(xs)
    
    return m, b

m, b = best_fit_slope_and_intercept(xs,ys)

print(m,b)
# 0.3, 4.3

現(xiàn)在我們僅僅需要為數(shù)據(jù)創(chuàng)建一條直線:

要記住y=mx+b议街,我們能夠?yàn)榇司帉懸粋€(gè)函數(shù)泽谨,或者僅僅使用一行的for循環(huán)。

regression_line = [(m*x)+b for x in xs]

上面的一行for循環(huán)和這個(gè)相同:

regression_line = []
for x in xs:
    regression_line.append((m*x)+b)

好的,讓我們收取我們的勞動(dòng)果實(shí)吧吧雹。添加下面的導(dǎo)入:

import matplotlib.pyplot as plt
from matplotlib import style
style.use('ggplot')

我們可以繪制圖像骨杂,并且不會(huì)特備難看。現(xiàn)在:

plt.scatter(xs,ys,color='#003F72')
plt.plot(xs, regression_line)
plt.show()

首先我們繪制了現(xiàn)有數(shù)據(jù)的散點(diǎn)圖雄卷,之后我們繪制了我們的回歸直線腊脱,之后展示它。如果你不熟悉龙亲,可以查看 Matplotlib 教程集

輸出:

恭喜恭喜悍抑。所以鳄炉,如何基礎(chǔ)這個(gè)模型來做一些實(shí)際的預(yù)測(cè)呢?很簡單搜骡,你擁有了模型拂盯,只要填充x就行了。例如记靡,讓我們預(yù)測(cè)一些點(diǎn):

predict_x = 7

我們輸入了數(shù)據(jù)谈竿,也就是我們的特征。那么標(biāo)簽?zāi)兀?/p>

predict_y = (m*predict_x)+b
print(predict_y)
# 6.4

我們也可以繪制它:

predict_x = 7
predict_y = (m*predict_x)+b

plt.scatter(xs,ys,color='#003F72',label='data')
plt.plot(xs, regression_line, label='regression line')
plt.legend(loc=4)
plt.show()

輸出:

我們現(xiàn)在知道了如何創(chuàng)建自己的模型摸吠,這很好空凸,但是我們?nèi)耘f缺少了一些東西,我們的模型有多精確寸痢?這就是下一個(gè)教程的話題了呀洲。

R 平方和判定系數(shù)原理

歡迎閱讀第十篇教程。我們剛剛完成了線性模型的創(chuàng)建和處理啼止,現(xiàn)在我們好奇接下來要干什么〉蓝海現(xiàn)在,我們可以輕易觀察數(shù)献烦,并決定線性回歸模型有多么準(zhǔn)確滓窍。但是,如果你的線性回歸模型是拿神經(jīng)網(wǎng)絡(luò)的 20 個(gè)層級(jí)做出來的呢巩那?不僅僅是這樣吏夯,你的模型以步驟或者窗口工作,也就是一共 5 百萬個(gè)數(shù)據(jù)點(diǎn)拢操,一次只顯示 100 個(gè)锦亦,會(huì)怎么樣?你需要一些自動(dòng)化的方式來判斷你的最佳擬合直線有多好令境。

回憶之前杠园,我們展示幾個(gè)繪圖的時(shí)候,你已經(jīng)看到舔庶,最佳擬合直線好還是不好抛蚁。像這樣:

與這個(gè)相比:

第二張圖片中陈醒,的確有最佳擬合直線,但是沒有人在意瞧甩。即使是最佳擬合直線也是沒有用的钉跷。并且,我們想在花費(fèi)大量計(jì)算能力之前就知道它肚逸。

檢查誤差的標(biāo)準(zhǔn)方式就是使用平方誤差爷辙。你可能之前聽說過,這個(gè)方法叫做 R 平方或者判定系數(shù)朦促。什么叫平方誤差呢膝晾?

回歸直線和數(shù)據(jù)的y值的距離,就叫做誤差务冕,我們將其平方血当。直線的平方誤差是它們的平均或者和。我們簡單求和吧禀忆。

我們實(shí)際上已經(jīng)解除了平方誤差假設(shè)臊旭。我們的最佳擬合直線方程,用于計(jì)算最佳擬合回歸直線箩退,就是證明結(jié)果离熏。其中回歸直線就是擁有最小平方誤差的直線(所以它才叫做最小二乘法)。你可以搜索“回歸證明”乏德,或者“最佳擬合直線證明”來理解它撤奸。它很抑郁理解,但是需要代數(shù)變形能力來得出結(jié)果喊括。

為啥是平方誤差胧瓜?為什么不僅僅將其加起來?首先郑什,我們想要一種方式府喳,將誤差規(guī)范化為距離,所以誤差可能是 -5蘑拯,但是钝满,平方之后,它就是正數(shù)了申窘。另一個(gè)原因是要進(jìn)一步懲罰離群點(diǎn)弯蚜。進(jìn)一步的意思是,它影響誤差的程度更大剃法。這就是人們所使用的標(biāo)準(zhǔn)方式碎捺。你也可以使用4, 6, 8的冪,或者其他。你也可以僅僅使用誤差的絕對(duì)值收厨。如果你只有一個(gè)挑戰(zhàn)晋柱,也許就是存在一些離群點(diǎn),但是你并不打算管它們诵叁,你就可以考慮使用絕對(duì)值雁竞。如果你比較在意離群點(diǎn),你就可以使用更高階的指數(shù)拧额。我們會(huì)使用平方碑诉,因?yàn)檫@是大多數(shù)人所使用的。

好的侥锦,所以我們計(jì)算回歸直線的平方誤差联贩,什么計(jì)算呢?這是什么意思捎拯?平方誤差完全和數(shù)據(jù)集相關(guān),所以我們不再需要?jiǎng)e的東西了盲厌。這就是 R 平方引入的時(shí)候了署照,也叫作判定系數(shù)。方程是:

y_hat = x * m + b
r_sq = 1 - np.sum((y - y_hat) ** 2) / np.sum((y - y.mean()) ** 2)

這個(gè)方程的的本質(zhì)就是吗浩,1 減去回歸直線的平方誤差建芙,比上 y 平均直線的平方誤差。 y 平均直線就是數(shù)據(jù)集中所有 y 值的均值懂扼,如果你將其畫出來禁荸,它是一個(gè)水平的直線。所以阀湿,我們計(jì)算 y 平均直線赶熟,和回歸直線的平方誤差。這里的目標(biāo)是識(shí)別陷嘴,與欠擬合的直線相比映砖,數(shù)據(jù)特征的變化產(chǎn)生了多少誤差。

所以判定系數(shù)就是上面那個(gè)方程灾挨,如何判定它是好是壞邑退?我們看到了它是 1 減去一些東西幅虑。通常仍源,在數(shù)學(xué)中,你看到他的時(shí)候柴底,它返回了一個(gè)百分比秒拔,它是 0 ~ 1 之間的數(shù)值莫矗。你認(rèn)為什么是好的 R 平方或者判定系數(shù)呢?讓我們假設(shè)這里的 R 平方是 0.8,它是好是壞呢趣苏?它比 0.3 是好還是壞狡相?對(duì)于 0.8 的 R 平方,這就意味著回歸直線的平方誤差食磕,比上 y 均值的平方誤差是 2 比 10尽棕。這就是說回歸直線的誤差非常小于 y 均值的誤差。聽起來不錯(cuò)彬伦。所以 0.8 非常好滔悉。

那么與判定系數(shù)的值 0.3 相比呢?這里单绑,它意味著回歸直線的平方誤差回官,比上 y 均值的平方誤差是 7 比 10。其中 7 比 10 要壞于 2 比 10搂橙,7 和 2 都是回歸直線的平方誤差歉提。因此,目標(biāo)是計(jì)算 R 平方值区转,或者叫做判定系數(shù)苔巨,使其盡量接近 1。

編程計(jì)算 R 平方

歡迎閱讀第十一篇教程废离。既然我們知道了我們尋找的東西侄泽,讓我們實(shí)際在 Python 中計(jì)算它吧。第一步就是計(jì)算平方誤差蜻韭。函數(shù)可能是這樣:

def squared_error(ys_orig,ys_line):
    return sum((ys_line - ys_orig) * (ys_line - ys_orig))

使用上面的函數(shù)悼尾,我們可以計(jì)算出任何實(shí)現(xiàn)到數(shù)據(jù)點(diǎn)的平方誤差。所以我們可以將這個(gè)語法用于回歸直線和 y 均值直線肖方。也就是說闺魏,平方誤差只是判定系數(shù)的一部分,所以讓我們構(gòu)建那個(gè)函數(shù)吧俯画。由于平方誤差函數(shù)只有一行舷胜,你可以選擇將其嵌入到判定系數(shù)函數(shù)中,但是平方誤差是你在這個(gè)函數(shù)之外計(jì)算的東西活翩,所以我選擇將其單獨(dú)寫成一個(gè)函數(shù)烹骨。對(duì)于 R 平方:

def coefficient_of_determination(ys_orig,ys_line):
    y_mean_line = [mean(ys_orig) for y in ys_orig]
    squared_error_regr = squared_error(ys_orig, ys_line)
    squared_error_y_mean = squared_error(ys_orig, y_mean_line)
    return 1 - (squared_error_regr/squared_error_y_mean)

我們所做的是,計(jì)算 y 均值直線材泄,使用單行的for循環(huán)(其實(shí)是不必要的)沮焕。之后我們計(jì)算了 y 均值的平方誤差,以及回歸直線的平方誤差拉宗,使用上面的函數(shù)÷褪鳎現(xiàn)在辣辫,我們需要做的就是計(jì)算出 R 平方之,它僅僅是 1 減去回歸直線的平方誤差魁巩,除以 y 均值直線的平方誤差急灭。我們返回該值,然后就完成了谷遂。組合起來并跳過繪圖部分葬馋,代碼為:

from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style
style.use('ggplot')

xs = np.array([1,2,3,4,5], dtype=np.float64)
ys = np.array([5,4,6,5,6], dtype=np.float64)

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)*mean(xs)) - mean(xs*xs)))
    b = mean(ys) - m*mean(xs)
    return m, b

def squared_error(ys_orig,ys_line):
    return sum((ys_line - ys_orig) * (ys_line - ys_orig))

def coefficient_of_determination(ys_orig,ys_line):
    y_mean_line = [mean(ys_orig) for y in ys_orig]
    squared_error_regr = squared_error(ys_orig, ys_line)
    squared_error_y_mean = squared_error(ys_orig, y_mean_line)
    return 1 - (squared_error_regr/squared_error_y_mean)
    
m, b = best_fit_slope_and_intercept(xs,ys)
regression_line = [(m*x)+b for x in xs]

r_squared = coefficient_of_determination(ys,regression_line)
print(r_squared)
# 0.321428571429

##plt.scatter(xs,ys,color='#003F72',label='data')
##plt.plot(xs, regression_line, label='regression line')
##plt.legend(loc=4)
##plt.show()

這是個(gè)很低的值,所以根據(jù)這個(gè)度量肾扰,我們的最佳擬合直線并不是很好畴嘶。這里的 R 平方是個(gè)很好的度量手段嗎?可能取決于我們的目標(biāo)集晚。多數(shù)情況下窗悯,如果我們關(guān)心準(zhǔn)確預(yù)測(cè)未來的值,R 平方的確很有用偷拔。如果你對(duì)預(yù)測(cè)動(dòng)機(jī)或者趨勢(shì)感興趣蒋院,我們的最佳擬合直線實(shí)際上已經(jīng)很好了。R 平方不應(yīng)該如此重要莲绰≡梦郏看一看我們實(shí)際的數(shù)據(jù)集,我們被一個(gè)較低的數(shù)值卡住了钉蒲。值與值之間的變化在某些點(diǎn)上是 20% ~ 50%,這已經(jīng)非常高了彻坛。我們完全不應(yīng)該感到意外顷啼,使用這個(gè)簡單的數(shù)據(jù)集,我們的最佳擬合直線并不能描述真實(shí)數(shù)據(jù)昌屉。

但是钙蒙,我們剛才說的是一個(gè)假設(shè)。雖然我們邏輯上統(tǒng)一這個(gè)假設(shè)间驮,我們需要提出一個(gè)新的方法躬厌,來驗(yàn)證假設(shè)。到目前為止的算法非尘好保基礎(chǔ)扛施,我們現(xiàn)在只能做很少的事情,所以沒有什么空間來改進(jìn)誤差了屹篓,但是之后疙渣,你會(huì)在空間之上發(fā)現(xiàn)空間。不僅僅要考慮算法本身的層次空間堆巧,還有由很多算法層次組合而成的算法妄荔。其中泼菌,我們需要測(cè)試它們來確保我們的假設(shè),關(guān)于算法是干什么用的啦租,是正確的哗伯。考慮把操作組成成函數(shù)由多么簡單篷角,之后焊刹,從這里開始,將整個(gè)驗(yàn)證分解成數(shù)千行代碼内地。

我們?cè)谙乱黄坛趟龅氖前槌危瑯?gòu)建一個(gè)相對(duì)簡單的數(shù)據(jù)集生成器,根據(jù)我們的參數(shù)來生成數(shù)據(jù)阱缓。我們可以使用它來按照意愿操作數(shù)據(jù)非凌,之后對(duì)這些數(shù)據(jù)集測(cè)試我們的算法,根據(jù)我們的假設(shè)修改參數(shù)荆针,應(yīng)該會(huì)產(chǎn)生一些影響敞嗡。我們之后可以將我們的假設(shè)和真實(shí)情況比較,并希望他們匹配航背。這里的例子中喉悴,假設(shè)是我們正確編寫這些算法,并且判定系數(shù)低的原因是玖媚,y 值的方差太大了箕肃。我們會(huì)在下一個(gè)教程中驗(yàn)證這個(gè)假設(shè)。

為測(cè)試創(chuàng)建樣例數(shù)據(jù)集

歡迎閱讀第十二篇教程今魔。我們已經(jīng)了解了回歸勺像,甚至編寫了我們自己的簡單線性回歸算法。并且错森,我們也構(gòu)建了判定系數(shù)算法來檢查最佳擬合直線的準(zhǔn)確度和可靠性吟宦。我們之前討論和展示過,最佳擬合直線可能不是最好的擬合涩维,也解釋了為什么我們的示例方向上是正確的殃姓,即使并不準(zhǔn)確。但是現(xiàn)在瓦阐,我們使用兩個(gè)頂級(jí)算法蜗侈,它們由一些小型算法組成。隨著我們繼續(xù)構(gòu)造這種算法層次睡蟋,如果它們之中有個(gè)小錯(cuò)誤宛篇,我們就會(huì)遇到麻煩,所以我們打算驗(yàn)證我們的假設(shè)薄湿。

在編程的世界中叫倍,系統(tǒng)化的程序測(cè)試通常叫做“單元測(cè)試”偷卧。這就是大型程序構(gòu)建的方式,每個(gè)小型的子系統(tǒng)都不斷檢查吆倦。隨著大型程序的升級(jí)和更新听诸,可以輕易移除一些和之前系統(tǒng)沖突的工具。使用機(jī)器學(xué)習(xí)蚕泽,這也是個(gè)問題晌梨,但是我們的主要關(guān)注點(diǎn)僅僅是測(cè)試我們的假設(shè)。最后须妻,你應(yīng)該足夠聰明仔蝌,可以為你的整個(gè)機(jī)器學(xué)習(xí)系統(tǒng)創(chuàng)建單元測(cè)試,但是目前為止荒吏,我們需要盡可能簡單敛惊。

我們的假設(shè)是,我們創(chuàng)建了最賤he直線绰更,之后使用判定系數(shù)法來測(cè)量瞧挤。我們知道(數(shù)學(xué)上),R 平方的值越低儡湾,最佳擬合直線就越不好特恬,并且越高(接近 1)就越好。我們的假設(shè)是徐钠,我們構(gòu)建了一個(gè)這樣工作的系統(tǒng)癌刽,我們的系統(tǒng)有許多部分,即使是一個(gè)小的操作錯(cuò)誤都會(huì)產(chǎn)生很大的麻煩尝丐。我們?nèi)绾螠y(cè)試算法的行為显拜,保證任何東西都預(yù)期工作呢?

這里的理念是創(chuàng)建一個(gè)樣例數(shù)據(jù)集摊崭,由我們定義,如果我們有一個(gè)正相關(guān)的數(shù)據(jù)集杰赛,相關(guān)性非常強(qiáng)呢簸,如果相關(guān)性很弱的話,點(diǎn)也不是很緊密乏屯。我們用眼睛很容易評(píng)測(cè)這個(gè)直線根时,但是機(jī)器應(yīng)該做得更好。讓我們構(gòu)建一個(gè)系統(tǒng)辰晕,生成示例數(shù)據(jù)蛤迎,我們可以調(diào)整這些參數(shù)。

最開始含友,我們構(gòu)建一個(gè)框架函數(shù)替裆,模擬我們的最終目標(biāo):

def create_dataset(hm,variance,step=2,correlation=False):

    return np.array(xs, dtype=np.float64),np.array(ys,dtype=np.float64)

我們查看函數(shù)的開頭校辩,它接受下列參數(shù):

  • hm(how much):這是生成多少個(gè)數(shù)據(jù)點(diǎn)。例如我們可以選擇 10辆童,或者一千萬宜咒。

  • variance:決定每個(gè)數(shù)據(jù)點(diǎn)和之前的數(shù)據(jù)點(diǎn)相比,有多大變化把鉴。變化越大故黑,就越不緊密。

  • step:每個(gè)點(diǎn)距離均值有多遠(yuǎn)庭砍,默認(rèn)為 2场晶。

  • correlation:可以為Falsepos或者neg怠缸,決定不相關(guān)诗轻、正相關(guān)和負(fù)相關(guān)。

要注意凯旭,我們也導(dǎo)入了random概耻,這會(huì)幫助我們生成(偽)隨機(jī)數(shù)據(jù)集。

現(xiàn)在我們要開始填充函數(shù)了罐呼。

def create_dataset(hm,variance,step=2,correlation=False):
    val = 1
    ys = []
    for i in range(hm):
        y = val + random.randrange(-variance,variance)
        ys.append(y)

非常簡單鞠柄,我們僅僅使用hm變量,迭代我們所選的范圍嫉柴,將當(dāng)前值加上一個(gè)負(fù)差值到證差值的隨機(jī)范圍厌杜。這會(huì)產(chǎn)生數(shù)據(jù),但是如果我們想要的話计螺,它沒有相關(guān)性夯尽。讓我們這樣:

def create_dataset(hm,variance,step=2,correlation=False):
    val = 1
    ys = []
    for i in range(hm):
        y = val + random.randrange(-variance,variance)
        ys.append(y)
        if correlation and correlation == 'pos':
            val+=step
        elif correlation and correlation == 'neg':
            val-=step

非常棒了,現(xiàn)在我們定義好了 y 值登馒。下面匙握,讓我們創(chuàng)建 x,它更簡單陈轿,只是返回所有東西圈纺。

def create_dataset(hm,variance,step=2,correlation=False):
    val = 1
    ys = []
    for i in range(hm):
        y = val + random.randrange(-variance,variance)
        ys.append(y)
        if correlation and correlation == 'pos':
            val+=step
        elif correlation and correlation == 'neg':
            val-=step

    xs = [i for i in range(len(ys))]
    
    return np.array(xs, dtype=np.float64),np.array(ys,dtype=np.float64)

我們準(zhǔn)備好了。為了創(chuàng)建樣例數(shù)據(jù)集麦射,我們所需的就是:

xs, ys = create_dataset(40,40,2,correlation='pos')

讓我們將之前線性回歸教程的代碼放到一起:

from statistics import mean
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib import style
style.use('ggplot')


def create_dataset(hm,variance,step=2,correlation=False):
    val = 1
    ys = []
    for i in range(hm):
        y = val + random.randrange(-variance,variance)
        ys.append(y)
        if correlation and correlation == 'pos':
            val+=step
        elif correlation and correlation == 'neg':
            val-=step

    xs = [i for i in range(len(ys))]
    
    return np.array(xs, dtype=np.float64),np.array(ys,dtype=np.float64)

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys)) /
         ((mean(xs)*mean(xs)) - mean(xs*xs)))
    
    b = mean(ys) - m*mean(xs)

    return m, b


def coefficient_of_determination(ys_orig,ys_line):
    y_mean_line = [mean(ys_orig) for y in ys_orig]

    squared_error_regr = sum((ys_line - ys_orig) * (ys_line - ys_orig))
    squared_error_y_mean = sum((y_mean_line - ys_orig) * (y_mean_line - ys_orig))

    print(squared_error_regr)
    print(squared_error_y_mean)

    r_squared = 1 - (squared_error_regr/squared_error_y_mean)

    return r_squared


xs, ys = create_dataset(40,40,2,correlation='pos')
m, b = best_fit_slope_and_intercept(xs,ys)
regression_line = [(m*x)+b for x in xs]
r_squared = coefficient_of_determination(ys,regression_line)
print(r_squared)

plt.scatter(xs,ys,color='#003F72', label = 'data')
plt.plot(xs, regression_line, label = 'regression line')
plt.legend(loc=4)
plt.show()

執(zhí)行代碼蛾娶,你會(huì)看到:

判定系數(shù)是 0.516508576011(要注意你的結(jié)果不會(huì)相同,因?yàn)槲覀兪褂昧穗S機(jī)數(shù)范圍)潜秋。

不錯(cuò)蛔琅,所以我們的假設(shè)是,如果我們生成一個(gè)更加緊密相關(guān)的數(shù)據(jù)集峻呛,我們的 R 平方或判定系數(shù)應(yīng)該更好罗售。如何實(shí)現(xiàn)它呢辜窑?很簡單,把范圍調(diào)低莽囤。

xs, ys = create_dataset(40,10,2,correlation='pos')

現(xiàn)在我們的 R 平方值為 0.939865240568谬擦,非常不錯(cuò),就像預(yù)期一樣朽缎。讓我們測(cè)試負(fù)相關(guān):

xs, ys = create_dataset(40,10,2,correlation='neg')

R 平方值是 0.930242442156惨远,跟之前一樣好,由于它們參數(shù)相同话肖,只是方向不同北秽。

這里,我們的假設(shè)證實(shí)了:變化越小 R 值和判定系數(shù)越高最筒,變化越大 R 值越低贺氓。如果是不相關(guān)呢?應(yīng)該很低床蜘,接近于 0辙培,除非我們的隨機(jī)數(shù)排列實(shí)際上有相關(guān)性。讓我們測(cè)試:

xs, ys = create_dataset(40,10,2,correlation=False)

判定系數(shù)為 0.0152650900427邢锯。

現(xiàn)在為止扬蕊,我覺得我們應(yīng)該感到自信为居,因?yàn)槭虑槎挤衔覀兊念A(yù)期卖宠。

既然我們已經(jīng)對(duì)簡單的線性回歸很熟悉了竹观,下個(gè)教程中我們開始講解分類泻骤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搀缠,隨后出現(xiàn)的幾起案子绊茧,更是在濱河造成了極大的恐慌跌帐,老刑警劉巖护戳,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翎冲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡媳荒,警方通過查閱死者的電腦和手機(jī)抗悍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肺樟,“玉大人檐春,你說我怎么就攤上這事逻淌∶床” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵卡儒,是天一觀的道長田柔。 經(jīng)常有香客問我俐巴,道長,這世上最難降的妖魔是什么硬爆? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任欣舵,我火速辦了婚禮,結(jié)果婚禮上缀磕,老公的妹妹穿的比我還像新娘缘圈。我一直安慰自己,他們只是感情好袜蚕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布糟把。 她就那樣靜靜地躺著,像睡著了一般牲剃。 火紅的嫁衣襯著肌膚如雪遣疯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天凿傅,我揣著相機(jī)與錄音缠犀,去河邊找鬼。 笑死聪舒,一個(gè)胖子當(dāng)著我的面吹牛辨液,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播过椎,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼室梅,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了疚宇?” 一聲冷哼從身側(cè)響起亡鼠,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敷待,沒想到半個(gè)月后间涵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榜揖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年勾哩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片举哟。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡思劳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妨猩,到底是詐尸還是另有隱情潜叛,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站威兜,受9級(jí)特大地震影響销斟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜椒舵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一蚂踊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧笔宿,春花似錦犁钟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侥加,卻和暖如春捧存,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背担败。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工昔穴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人提前。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓吗货,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狈网。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宙搬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容