Machine Learning in Python (Scikit-learn)-(No.1)
作者?:范淼?(人人網)
1. 閑話篇
機器學習(ML),自然語言處理(NLP),神馬的,最近太火了。。。不知道再過幾年,大家都玩兒ML,還會不會繼續火下去。。。需要有人繼續再添點柴火才行。本人僅僅是一個迷途小書童,知識有限,還望各位ML大神多多指點:)。
最近想系統地收拾一下ML的現有工具,發現比較好的應該是這個http://scikit-learn.org/stable/index.html。
對于初學和進階階段的ML研究者們是個不錯的選擇。不過美中不足的是少了Large-scale ML的一些,畢竟這是單機的。后面琢磨琢磨,寫個ADMM(今年ICML劇多相關的論文)的吧,這個之前在MSRA的Learning Group做過一個Turtorial.
尤其是他的參考手冊,更是沒有太多廢話,都能一針見血地講明重點:http://scikit-learn.org/stable/user_guide.html
其實不要指望這個工具包能有啥新的東西,不過就是這些經典的東西,要是你真掌握了,也基本God Like!了。:),特別是你用ML創業的時候,可能真能用上一兩個思路,也就是被訓練出來的思想估計是大學能留下來的,剩下的都在狗肚子里。
我們來大致瀏覽一下這個系統的ML工具的功能,整體內容較多,我們逐步更新,想具體了解哪個部分的童鞋可以留言,我一下子還真很難都詳細介紹(我會基本上保證一周更新一個小章節,逐步學習。首先弄懂模型原理,講出來,然后使用對應數據實戰一下,貼出代碼,作圖,最后利用測試結果適當比較一下模型之間的差異),所有的代碼,我都會后續貼到CSDN或者Github上面。
---------------------------------------------------華麗麗的分割線---------------------------------------------------------
2. 配置篇
推薦學習配置:python 2.7, pycharm IDE (這個Python的IDE不錯,推薦大家用下,如果用過Eclipse寫Java,這個上手會很快), numpy, scipy。其他還有一些需要下載的包,大家可以邊配置邊有問題留言,建議在windows下面弄弄就行,我基本不用Linux。
有些小伙伴建議我也詳細講講在windows下的配置。的確,這一系列的配置還真心沒有那么簡單,我特地找了一臺windows7 Ultimiate SP1 x64 的裸機來重現一下整體配置過程。
首先是Python 2.7 (切記Python 3.x 和2.x的版本完全不是一路貨,不存在3.x向下兼容的問題,所以,如果哪位小伙伴為了追求軟件版本高而不小心安裝了python 3.x,我只能說。。好吧。。你被坑了。最簡單的理解,你可以認為這兩個Python版本壓根就不是一門相同的編程語言,就連print的語法都不同)
1. Python 2.7.x ?在 x64 windows平臺下的解釋器。具體下載地址:https://www.python.org/download/releases/2.7.8/注意64位的是這個Windows X86-64 MSI Installer(2.7.8)
測試這個Python是否在你的環境里配置好,你可以在命令行里直接輸入python,如果報錯,那么你需要手動配置一下環境,這個大家上網搜就可以解決(簡單說,在環境變量PATH里把你的Python的安裝文件夾路徑寫進去)。
2. 然后安裝Pycharm,這個是我在Hulu實習的時候用到過的IDE,還是濤哥推薦的,還不錯。因為有正版收費的問題,推薦大家下載它的(community)版http://www.jetbrains.com/pycharm/download/。安裝好后,它應該會讓你選擇剛才安裝好的Python的解釋器,這樣你就可以做一些簡單的python編程了,用過eclipse的人,這個上手非常快。
3. 接著就需要配置跟sklearn有關的一系列Python的擴展包了。這個美國加州一個學校的一個非官方網站張貼了所有windows直接安裝的版本http://www.lfd.uci.edu/~gohlke/pythonlibs/,特別實用,大家到里面去下載跟python 2.7 amd64有關的安裝包。然后直接下載運行即可。需要下載的一系列擴展包的列表(按照依賴順序):Numpy-MKL, SciPy, Scikit-learn。有了這些就可以學習Scikit-learn這個工具包了。
4. 此外,如果想像我一樣,同時可以畫圖,那么就需要matplotlib,這個也有一個網站手冊http://matplotlib.org/contents.html,同樣也需要一系列擴展包的支持。使用matplotlib 需要如下必備的庫,numpy,dateutil,pytz,pyparsing,six。都能從剛才我推薦的下載網站上獲取到。
上面的一系列都搞定了,大家可以使用我第一個線性回歸的代碼(加粗的代碼)測試一下,直接輸出圖像,最后還能保存成為png格式的圖片。
------------------------------華麗麗的分割線------------------------------------------
3. 數據篇
用工具之前先介紹幾個我會用到的數據
這里大部分的數據都是從這個經典的機器學習網站提供的:
https://archive.ics.uci.edu/ml/
sklearn.datasets里面集成了這個網站里的部分數據(剛接觸Python的童鞋,需要一點點Python的知識,和Java類似,使用現成工具模塊的時候,需要import一下,我們這個基于Python的機器學習工具包的全名是sklearn,這里介紹數據,所以下一個目錄是datasets)。具體的Python代碼:
import sklearn.datasets
數據一:波士頓房價(適合做回歸),以后直接用boston標記
這行代碼就讀進來了
boston = sklearn.datasets.load_boston()
查詢具體數據說明,用這個代碼:
print boston.DESCR
輸出如下:
Data Set Characteristics:
:Number of Instances: 506
:Number of Attributes: 13 numeric/categorical predictive
:Median Value (attribute 14) is usually the target
:Attribute Information (in order):
- CRIM per capita crime rate by town
- ZN proportion of residential land zoned for lots over 25,000 sq.ft.
- INDUS proportion of non-retail business acres per town
- CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
- NOX nitric oxides concentration (parts per 10 million)
- RM average number of rooms per dwelling
- AGE proportion of owner-occupied units built prior to 1940
- DIS weighted distances to five Boston employment centres
- RAD index of accessibility to radial highways
- TAX full-value property-tax rate per $10,000
- PTRATIO pupil-teacher ratio by town
- B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
- LSTAT % lower status of the population
- MEDV Median value of owner-occupied homes in $1000's
一共506組數據,13維特征,
比如第一個維度的特征是犯罪率,第六個是每個房子平均多少房間等等。
boston.data 獲取這506 * 13的特征數據
boston.target 獲取對應的506 * 1的對應價格
數據二:牽牛花(適合做簡單分類),標記為Iris
import sklearn.datasets
iris = sklearn.datasets.load_iris()
iris.data 獲取特征
iris.target 獲取對應的類別
Data Set Characteristics:
:Number of Instances: 150 (50 in each of three classes)
:Number of Attributes: 4 numeric, predictive attributes and the class
:Attribute Information:
- sepal length in cm
- sepal width in cm
- petal length in cm
- petal width in cm
- class:
- Iris-Setosa
- Iris-Versicolour
- Iris-Virginica
這個數據基本是個ML的入門選手都知道,一共三類牽牛花,獲取特征和對應的類別標簽也是同上
一共150樣本,3類,特征維度為4
數據三: 糖尿病(回歸問題),diabetes
這個數據包很奇怪,沒有描述。我也到原本的UCI的網站上查了一下,也是沒有太好的描述。
import sklearn.datasets
diabetes = sklearn.datasets.load_diabetes()
print diabetes.keys()
這樣的輸出只有data, targets。
我也觀察了一下數據,感覺是經過額外的歸一化處理的,原始的數據樣貌已經看不出來了。。
下面這個圖是我從網站上Copy下來的有限的描述,樣本量為442,特征維度為10,每個特征元素的值都是連續的實數,在正負0.2之間。。目標這個整數值有可能是血糖。
Samples total442
Dimensionality10
Featuresreal, -.2 < x < .2
Targetsinteger 25 - 346
數據四:手寫數字識別(多類分類,10個類別,從0-9)digits
import sklearn.datasets
digits = sklearn.datasets.load_digits()
總體樣本量:1797,每個類別大約180個樣本,每個手寫數字是一個8*8的圖片,每個像素是0-16的整數值。
綜上,大家可以加載相應的數據來玩,這幾個數據算是比較有代表性的。后面會介紹如何利用SKLEARN工具下載更大規模的數據,比如MINIST的大規模的手寫數字識別庫等等。
總之,如果你想獲取特征,就在*.data里,對應的類別或者回歸值在*.target里面
光說不練不行,我對每個介紹的方法都會選用上面的Dataset實際測試一下,并且會酌情給出結果和圖像。
------------------------------華麗麗的分割線------------------------------------------
4.實戰篇
這個監督學習最常用,分類啊,預測回歸(預測個股票啥的,雖然在我大天朝不太適合)啊。
1.1. Generalized Linear Models
最通用的線性模型
把你的特征x和對應的權重w相加,最后爭取接近你的目標y,機器學的就是w。
這個模型應用最廣,其實就是大家會權衡各種各樣的因素,最后給一個總評。
1.1.1. Ordinary Least Squares最小二乘約束
目標函數是這個
要總體的平方和最小。
具體代碼大家import sklearn.linear_model,然后sklearn.linear_model.LinearRegression()就是這個模塊了。做個簡單的什么房價估計還行(別說預測,那個不準,只能說估計一下租房的價格,隨便在搜房網上弄點兒數據,他那里有現成的特征,什么地理位置啊,面積啊,朝向啊等等,最后你回歸一個大致房價玩玩)。
我們就使用波士頓的房價來預測一下(后面的所有python代碼注意縮進!我是沒工夫一行一行調整了。。。多包涵):
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import numpy.linalg
import matplotlib.pyplot
if __name__ == "__main__":
# Load boston dataset
boston = sklearn.datasets.load_boston()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(boston.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = boston.data[shuffleIdx[:sampleBoundary]]
train_targets = boston.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = boston.data[shuffleIdx[sampleBoundary:]]
test_targets = boston.target[shuffleIdx[sampleBoundary:]]
# Train
linearRegression = sklearn.linear_model.LinearRegression()
linearRegression.fit(train_features, train_targets)
# Predict
predict_targets = linearRegression.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
error = numpy.linalg.norm(predict_targets - test_targets, ord = 1) / n_test_samples
print "Ordinary Least Squares (Boston) Error: %.2f" %(error)
# Draw
matplotlib.pyplot.plot(X, predict_targets, 'r--', label = 'Predict Price')
matplotlib.pyplot.plot(X, test_targets, 'g:', label='True Price')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("Ordinary Least Squares (Boston)")
matplotlib.pyplot.ylabel("Price")
matplotlib.pyplot.savefig("Ordinary Least Squares (Boston).png", format='png')
matplotlib.pyplot.show()
結果:
Ordinary Least Squares (Boston) Error:3.35。基本上,平均每筆預測,都會距離真實的價格差3350美金,這個數值的單位是1000 U.S.D. (見數據描述)
下面這個圖就是預測和實際價格的對比圖線,這里是隨機采樣了50%作為訓練,50%做預測,效果還行,看來這個線性模型還可以接受。
1.1.2. Ridge Regression
這個中文一般叫嶺回歸,就是在上面的目標函數上加個正則項,嶺回歸用二范數(L2 norm)。
這個范數的目的在于對整體學習到的權重都控制得比較均衡,因為我們的數據不能保證非常正常,有的時候,接近線性相關的那些噪聲樣本會加劇權重系數的非均衡學習,最后就是這個樣子
一旦某個特征噪音比較大,剛好那個權重也不小,那回歸結果就慘了。
好,我們再用波士頓的房價試試嶺回歸。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import numpy.linalg
import matplotlib.pyplot
if __name__ == "__main__":
# Load boston dataset
boston = sklearn.datasets.load_boston()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(boston.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = boston.data[shuffleIdx[:sampleBoundary]]
train_targets = boston.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = boston.data[shuffleIdx[sampleBoundary:]]
test_targets = boston.target[shuffleIdx[sampleBoundary:]]
# Train with Cross Validation
ridgeRegression = sklearn.linear_model.RidgeCV(alphas=[0.01, 0.05, 0.1, 0.5, 1.0, 10.0])
這個地方使用RidgeCV 直接交叉驗證出我需要試驗的幾個懲罰因子,它會幫我選擇這些里面在集內測試表現最優的一個參數。后面的輸出選擇了0.1。
ridgeRegression.fit(train_features, train_targets)
print "Alpha = ", ridgeRegression.alpha_
# Predict
predict_targets = ridgeRegression.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
error = numpy.linalg.norm(predict_targets - test_targets, ord = 1) / n_test_samples
print "Ridge Regression (Boston) Error: %.2f" %(error)
# Draw
matplotlib.pyplot.plot(X, predict_targets, 'r--', label = 'Predict Price')
matplotlib.pyplot.plot(X, test_targets, 'g:', label='True Price')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("Ridge Regression (Boston)")
matplotlib.pyplot.ylabel("Price (1000 U.S.D)")
matplotlib.pyplot.savefig("Ridge Regression (Boston).png", format='png')
matplotlib.pyplot.show()
輸出:
Alpha = 0.1
Ridge Regression (Boston) Error: 3.21
基本上,這樣的結果,誤差在3210美金左右,比之前的最一般的線性模型好一點。而且,這種情況下,基本上預測出來的圖線的方差比較小,振幅略小,因為有Ridge的懲罰項的約束,保證每個特征的變化不會對整體預測有過大的影響
1.1.3. Lasso
老是聽MSRA的師兄說這個,貌似還挺火的一個研究,這里面就是把二范數(L2)換成一范數(L1)。
絕對值的這個約束,更想讓學習到的權重稀疏一些,壓縮感知啥的跟這個有關。
這個估計不會有太大的性能提升,對于Boston數據,因為本來特征就不稀疏,后面可以試試newsgroup20。那個夠稀疏。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import numpy.linalg
import matplotlib.pyplot
if __name__ == "__main__":
# Load boston dataset
boston = sklearn.datasets.load_boston()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(boston.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = boston.data[shuffleIdx[:sampleBoundary]]
train_targets = boston.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = boston.data[shuffleIdx[sampleBoundary:]]
test_targets = boston.target[shuffleIdx[sampleBoundary:]]
# Train
lasso = sklearn.linear_model.LassoCV(alphas=[0.01, 0.05, 0.1, 0.5, 1.0, 10.0])
lasso.fit(train_features, train_targets)
print "Alpha = ", lasso.alpha_
# Predict
predict_targets = lasso.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
error = numpy.linalg.norm(predict_targets - test_targets, ord = 1) / n_test_samples
print "Lasso (Boston) Error: %.2f" %(error)
# Draw
matplotlib.pyplot.plot(X, predict_targets, 'r--', label = 'Predict Price')
matplotlib.pyplot.plot(X, test_targets, 'g:', label='True Price')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("Lasso (Boston)")
matplotlib.pyplot.ylabel("Price (1000 U.S.D)")
matplotlib.pyplot.savefig("Lasso (Boston).png", format='png')
matplotlib.pyplot.show()
輸出:
Alpha = 0.01
Lasso (Boston) Error: 3.39
這個結果的振幅還是比較大的。特別是對于低價位的振幅。
1.1.4. Elastic Net
這個不知道中文怎么說合適,其實就是兼顧了上面兩個正則項(L1和L2兩個先驗(Prior)),既保證能夠訓練出一組比較稀疏的模型(Lasso的貢獻),同時還能兼具嶺回歸L2的好處。這個我沒試過,不知道啥樣的數據這么做最合適,回頭我試幾個數據集,比較一下普通的線性回歸和這個模型的性能。
很自然地,要用一個額外的參數來平衡這兩個先驗約束,一個是懲罰因子alpha,這個之前也有,另一個就是
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import numpy.linalg
import matplotlib.pyplot
if __name__ == "__main__":
# Load boston dataset
boston = sklearn.datasets.load_boston()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(boston.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = boston.data[shuffleIdx[:sampleBoundary]]
train_targets = boston.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = boston.data[shuffleIdx[sampleBoundary:]]
test_targets = boston.target[shuffleIdx[sampleBoundary:]]
# Train
elasticNet = sklearn.linear_model.ElasticNetCV(alphas=[0.01, 0.05, 0.1, 0.5, 1.0, 10.0], l1_ratio=[0.1,0.3,0.5,0.7,0.9])
elasticNet.fit(train_features, train_targets)
print "Alpha = ", elasticNet.alpha_
print "L1 Ratio = ", elasticNet.l1_ratio_
# Predict
predict_targets = elasticNet.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
error = numpy.linalg.norm(predict_targets - test_targets, ord = 1) / n_test_samples
print "Elastic Net (Boston) Error: %.2f" %(error)
# Draw
matplotlib.pyplot.plot(X, predict_targets, 'r--', label = 'Predict Price')
matplotlib.pyplot.plot(X, test_targets, 'g:', label='True Price')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("Elastic Net (Boston)")
matplotlib.pyplot.ylabel("Price (1000 U.S.D)")
matplotlib.pyplot.savefig("Elastic Net (Boston).png", format='png')
matplotlib.pyplot.show()
輸出:
Alpha = 0.01
L1 Ratio = 0.9
Elastic Net (Boston) Error: 3.14
貌似還是混合所有制比較牛逼!知道這年頭審論文最怕遇到題目里面有啥么?Hybird...,這尼瑪性能不提升都對不起這個單詞。。。
1.1.10. Logistic regression
這里補充一個比較實用的邏輯斯蒂回歸,雖然名字叫這個,但是一般用在分類上。
采用這個函數來表達具體樣本的特征加權組合能夠分到哪個類別上(注:下面的圖片來自博客http://blog.csdn.net/marvin521/article/details/9263483)
下面的這個sigmod函數對于z值特別敏感,但是他的優點在于他是連續可導的,這個非常重要,便于我們用梯度法計算W。
事實證明,Logistic Regression做分類非常好用也很易用,據說Goolge對點擊率CTR的預測也會用到這個模型,這個我沒有考證過,只是聽說,不過下面的代碼對Iris的分類結果倒是也能說明這個做分類也是挺好用的(這里強調,我們經常看到Logistic Regression用來做二分類,事實上它可以拓展到對多類分類上,我這里不過多介紹,大家可以查Softmax Regression做參考)。
我們使用Iris的數據來測試一下:
大致回顧一下Iris(牽牛花(數據篇有詳細介紹))的數據特點:150個樣本,3類,每類基本50條數據,每個數據條目4中特征,都是連續數值類型。我們的目標就是把隨機抽取的50%(切記要隨機打亂數據,這個數據原始的順序不是打亂的,前50條都是一個類別,別弄錯了。)的數據做個類別0,1,2的預測。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import matplotlib.pyplot
if __name__ == "__main__":
# Load iris dataset
iris = sklearn.datasets.load_iris()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(iris.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = iris.data[shuffleIdx[:sampleBoundary]]
train_targets = iris.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = iris.data[shuffleIdx[sampleBoundary:]]
test_targets = iris.target[shuffleIdx[sampleBoundary:]]
# Train
logisticRegression = sklearn.linear_model.LogisticRegression()
logisticRegression.fit(train_features, train_targets)
# Predict
predict_targets = logisticRegression.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
correctNum = 0
for i in X:
if predict_targets[i] == test_targets[i]:
correctNum += 1
accuracy = correctNum * 1.0 / n_test_samples
print "Logistic Regression (Iris) Accuracy: %.2f" %(accuracy)
# Draw
matplotlib.pyplot.subplot(2, 1, 1)
matplotlib.pyplot.title("Logistic Regression (Iris)")
matplotlib.pyplot.plot(X, predict_targets, 'ro-', label = 'Predict Labels')
matplotlib.pyplot.ylabel("Predict Class")
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.subplot(2, 1, 2)
matplotlib.pyplot.plot(X, test_targets, 'g+-', label='True Labels')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.ylabel("True Class")
matplotlib.pyplot.savefig("Logistic Regression (Iris).png", format='png')
matplotlib.pyplot.show()
輸出:
Logistic Regression (Iris) Accuracy: 0.95
使用50%作訓練,50%做測試,分類精度可以達到95%。
下面這個圖算是一個直觀的輔助,因為分類精度比較高,所以預測類別和真實類別對應的走勢幾乎相同:
http://blog.renren.com/blog/bp/Q7Vlj0xW7D
接著之前No.1,我們繼續。
之前的易懂的線性模型基本走了一遭,我們再看看,如果數據的特征因素是復合的,平方的,立方的(也就是多項式回歸會怎么樣?)。我覺得這種東西沒有定論,誰也不能確定特征組合會不會有道理,再說的直白點,到底特征是不是幫助我們機器學習的有效利器,也沒有定論,但是至少目前看還是有效的。
1.1.15. Polynomial regression: extending linear models with basis functions
我們之前都是關注,怎么找到特征的線性組合,但是事實上,不可能都是線性組合,房價也許從某個特征(比如有一個特征是房子的平均面積,這個和價格有可能是線性關系;但是如果是這個地區的房子的數量,這個很難講,有可能就不是線性的,有可能是平方的,也有可能是其他復雜的關系,比如邏輯斯蒂關系,因為環境飽和有可能造成房價持平甚至下跌)。我們這里考慮這種多項式組合的特征關系。
這是原來的特征線性組合
這個就是特征的二項式組合,
我們來看看代碼上,怎么來處理,還是用房價的數據。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.linear_model
import numpy.random
import numpy.linalg
import matplotlib.pyplot
import sklearn.preprocessing
if __name__ == "__main__":
# Load boston dataset
boston = sklearn.datasets.load_boston()
# Data tranform
polynominalData = sklearn.preprocessing.PolynomialFeatures(degree=2).fit_transform(boston.data)
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(boston.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = polynominalData[shuffleIdx[:sampleBoundary]]
train_targets = boston.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = polynominalData[shuffleIdx[sampleBoundary:]]
test_targets = boston.target[shuffleIdx[sampleBoundary:]]
# Train
linearRegression = sklearn.linear_model.LinearRegression()
linearRegression.fit(train_features, train_targets)
# Predict
predict_targets = linearRegression.predict(test_features)
# Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
error = numpy.linalg.norm(predict_targets - test_targets, ord = 1) / n_test_samples
print "Polynomial Regression (Degree = 2) (Boston) Error: %.2f" %(error)
# Draw
matplotlib.pyplot.plot(X, predict_targets, 'r--', label = 'Predict Price')
matplotlib.pyplot.plot(X, test_targets, 'g:', label='True Price')
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("Polynomial Regression (Degree = 2) (Boston)")
matplotlib.pyplot.ylabel("Price (1000 U.S.D)")
matplotlib.pyplot.savefig("Polynomial Regression (Degree = 2) (Boston).png", format='png')
matplotlib.pyplot.show()
這份代碼里,我使用的是二項式特征轉換,最高階次是2。然后使用普通的線性擬合,
輸出:
Polynomial Regression (Degree = 2) (Boston) Error: 3.26
誤差在3260美金上下,我記得之前的普通的線性回歸是3350。略好一點點。
有些喜歡質疑的同學也許會問,我這代碼會不會有問題?沒關系,我們繼續延伸一個小話題,如果我們只修改一個地方:
# Data tranform
polynominalData = sklearn.preprocessing.PolynomialFeatures(degree=4).fit_transform(boston.data),改成4階的,會怎么樣呢?后果不堪設想。。。
輸出:
Polynomial Regression (Degree = 4) (Boston) Error: 30.19
誤差達到3W美金,這模型完全不能用了。
大家可以看到,預測價格(紅色虛線)的震動非常強烈,而真實價格基本在30左右徘徊(綠色的虛線)。這說明你的模型在對測試數據的泛化能力上非常差。但是有人一定會問:“我設計的4階模型應該比2階的考慮的特征組合要多得多啊,怎么會測試的時候這么差?” 是啊,考慮全面了,還這么差,我只能說“您想多了”。事實上,沒有那么多數據夠你合理地調整參數,因為你的模型過于復雜。這種情況叫做過擬合(overfitting)。上面的圖片顯示的就是典型的過擬合。那么如果你的模型本身就是二次的,你用線性回歸,那么效果也會略差,這種情況叫做欠擬合(underfitting)
在大數據時代,深度學習的模型參數非常多,但是數據也多,這樣復雜模型本身的強大的表達能力得以展現,這是我覺得為什么在圖像,語音這些領域 ,深度學習這么有效的簡單原因。
---------------------------------------------------------------------------------------------------------------------------------
支持向量機的歷史命運特別像諾基亞,曾經輝煌很長一段時間,盡管現在已經成為歷史,但是終究不能磨滅期偉大貢獻。應該是上個世紀90年代,幾乎在學術界充斥了大量的關于SVM的話題論文。要是那個時候誰不知道SVM,就跟現在不知道深度學習似的,不知道要遭到多少鄙視:)。其實我也不懂深度學習。。。被鄙視習慣了,也就見慣不慣了。
我們的這個sklearn系列的討論帖不在于介紹數學細節,更關注怎么用,什么情況下使用什么模型更適合。因此我同意下面的四條關于SVM的優勢的總結,這些總結從側面告訴你什么時候用SVM:
a. 高維度特征數據有效
b. 訓練樣本數量小于特征維數的數據有效(這個特別霸氣)
c. 節約模型的存儲內存(就那么幾個支持向量有用)
d. 還可以根據需要對特征進行高維變化(核函數的方法)
1.2.1. Classification
SVM用來做Classification,縮寫就是SVC(Support Vector Classification)(SVM不僅僅能做分類,這個一定要說明)的基本思想非常直觀,也是要找一個超平面(2類分類),但是要找最好的那個。下圖來自博文:http://blog.csdn.net/marvin521/article/details/9286099。我們可以看到,類似B,C的分隔線可以有無數個,都能分離藍色和紅色的兩個類別,但是貌似D的分類方式更讓人接受,好像如果有一個新的數據,大體上像D這樣劃分更容易對,是吧。這里D的方式就是找到了已知數據分布的最大間隔,有充足的泛化空間讓給那些沒有看到的數據,這樣模型的泛化能力達到了最大(機器學習的關鍵問題不在于模型在訓練樣本上的契合程度,在于泛化能力如何,雖然這是很難評估的),這是為什么SVM在90年代的時候風靡一時的原因,它也的確好使。
再來看,其實像D這樣的分隔線的確定貌似不太依賴那些遠離分隔線的數據點,只有那些距離分割線(如果是更多維度的特征,那就是分隔超平面)最近的一些點能夠支持分割線確定位置,因此叫支持向量機。而那些用來確定分割線的有效數據點(特征向量),叫做支持向量。
來,我們用代碼找找感覺:
這里需要說明一下:如果我們繼續使用Iris的數據,這是一個多類別(3個類別)的分類問題,我覺得大家需要大致了解一下SVC這套工具是怎么處理多類分類的問題的(畢竟,我們給出的例子是2類分類的)。
大體上有兩種,將兩類分類器擴展到多類分類問題,我這里強調,不是只有兩種,而是,將兩類分類問題進行擴展,達到多(假設有n個類別) 分類的目的,這個思路有兩種:一種是訓練n*(n-1)/ 2個二類分類器,兩兩類別之間訓練一個分類器,用于專門處理;另外一種就是把其中一個類別拿出來作為正類別,其他的所有類別統一歸為負類,這樣會訓練n個訓練樣本。
用Iris的數據我們都來試試。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.svm
import numpy.random
import matplotlib.pyplot
import matplotlib.colors
if __name__ == "__main__":
# Load iris dataset
iris = sklearn.datasets.load_iris()
# Split the dataset with sampleRatio
sampleRatio = 0.5
n_samples = len(iris.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = iris.data[shuffleIdx[:sampleBoundary]]
train_targets = iris.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = iris.data[shuffleIdx[sampleBoundary:]]
test_targets = iris.target[shuffleIdx[sampleBoundary:]]
# Train
svc = sklearn.svm.SVC()
nusvc = sklearn.svm.NuSVC()
linearsvc = sklearn.svm.LinearSVC()
svc.fit(train_features, train_targets)
nusvc.fit(train_features, train_targets)
linearsvc.fit(train_features, train_targets)
predict_targets = svc.predict(test_features)
#SVC Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
correctNum = 0
for i in X:
if predict_targets[i] == test_targets[i]:
correctNum += 1
accuracy = correctNum * 1.0 / n_test_samples
print "SVC Accuracy: %.2f" %(accuracy)
predict_targets = nusvc.predict(test_features)
#NuSVC Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
correctNum = 0
for i in X:
if predict_targets[i] == test_targets[i]:
correctNum += 1
accuracy = correctNum * 1.0 / n_test_samples
print "NuSVC Accuracy: %.2f" %(accuracy)
predict_targets = linearsvc.predict(test_features)
#LinearSVC Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
correctNum = 0
for i in X:
if predict_targets[i] == test_targets[i]:
correctNum += 1
accuracy = correctNum * 1.0 / n_test_samples
print "LinearSVC Accuracy: %.2f" %(accuracy)
1.3. Stochastic Gradient Descent
1.4. Nearest Neighbors
1.4.2. Nearest Neighbors Classification
借著剛剛更新過的Logistic Regression 對 Iris做分類的余興,我們來看看使用近鄰法是怎么做分類(近鄰法不僅能做分類,還能回歸,我先介紹分類,這個比較好懂)的。這個算是基于實例的分類方法,和前面介紹的回歸啊,分類啊這些方法都不同,之前都是要訓練出一個具體的數學函數,對吧。這種近鄰法不需要預先訓練出什么公式。近鄰法的思想很簡單,“物以類聚,人以群分”,特征相似的,類別最相近。KNN(K Nearest Neighbor)的意思就是在某個待分類的樣本周圍找K個根據特征度量距離最近的K個已知類別的樣本,這K個樣本里面,如果某個類別個數最多,那么這個待分類的樣本就從屬于那個類別。意思就是,找特性最相近的朋黨,然后少數服從多數。
當然,這個工具包也沒有那么簡單,除了KNN(KNeighborsClassifier)還有RNN(RadiusNeighborsClassifier),說白了,KNN不在乎那K個最近的點到底離你有多遠,反正總有相對最近的K個。但是RNN要考慮半徑Radius,在待測樣本以Radius為半徑畫個球(如果是二維特征就是圓,三維特征以上,你可以理解為一個超球面),這個球里面的都算進來,這樣就不能保證每個待測樣本都能考慮相同數量的最近樣本。
同時,我們也可以根據距離的遠近來對這些已知類別的樣本的投票進行加權,這個想法當然很自然。后面的代碼都會體現。
我們還是用Iris來測試一下,這次采樣比例弄得狠了點,20%訓練,80%用來預測測試,就是為了區別一下兩種距離加權方式[unifrom, distance]。
'''
Author: Miao Fan
Affiliation: Department of Computer Science and Technology, Tsinghua University, P.R.China.
Email: fanmiao.cslt.thu@gmail.com
'''
import sklearn.datasets
import sklearn.neighbors
import numpy.random
import matplotlib.pyplot
import matplotlib.colors
if __name__ == "__main__":
# Load iris dataset
iris = sklearn.datasets.load_iris()
# Split the dataset with sampleRatio
sampleRatio = 0.2
n_samples = len(iris.target)
sampleBoundary = int(n_samples * sampleRatio)
# Shuffle the whole data
shuffleIdx = range(n_samples)
numpy.random.shuffle(shuffleIdx)
# Make the training data
train_features = iris.data[shuffleIdx[:sampleBoundary]]
train_targets = iris.target[shuffleIdx [:sampleBoundary]]
# Make the testing data
test_features = iris.data[shuffleIdx[sampleBoundary:]]
test_targets = iris.target[shuffleIdx[sampleBoundary:]]
# Train
n_neighbors = 5 #選5個最近鄰
for weights in ['uniform', 'distance']: #這個地方采用兩種加權方式
kNeighborsClassifier = sklearn.neighbors.KNeighborsClassifier(n_neighbors, weights=weights)
kNeighborsClassifier.fit(train_features, train_targets)
# Test
predict_targets = kNeighborsClassifier.predict(test_features)
#Evaluation
n_test_samples = len(test_targets)
X = range(n_test_samples)
correctNum = 0
for i in X:
if predict_targets[i] == test_targets[i]:
correctNum += 1
accuracy = correctNum * 1.0 / n_test_samples
print "K Neighbors Classifier (Iris) Accuracy [weight = '%s']: %.2f" %(weights, accuracy)
# Draw
cmap_bold = matplotlib.colors.ListedColormap(['red', 'blue', 'green'])
X_test = test_features[:, 2:4]
X_train = train_features[:, 2:4]
matplotlib.pyplot.scatter(X_train[:, 0], X_train[:, 1], label = 'train samples', marker='o', c = train_targets, cmap=cmap_bold,)
matplotlib.pyplot.scatter(X_test[:,0], X_test[:, 1], label = 'test samples', marker='+', c = predict_targets, cmap=cmap_bold)
legend = matplotlib.pyplot.legend()
matplotlib.pyplot.title("K Neighbors Classifier (Iris) [weight = %s]" %(weights))
matplotlib.pyplot.savefig("K Neighbors Classifier (Iris) [weight = %s].png" %(weights), format='png')
matplotlib.pyplot.show()
輸出:
K Neighbors Classifier (Iris) Accuracy [weight = 'uniform']: 0.91
K Neighbors Classifier (Iris) Accuracy [weight = 'distance']: 0.93
加權方法略好一點,大約提升2%的精度(注意這兩個圖,我只是采用了其中的兩個維度特征進行的重建,事實上應該有4個維度):
1.5. Gaussian Processes
1.6. Cross decomposition
1.7. Naive Bayes
1.8. Decision Trees
1.10. Multiclass and multilabel algorithms
1.13. Linear and quadratic discriminant analysis
然后讓我們開始無監督學習:(聚類啊,概率密度估計(離群點檢測)啊,數據降維啊)等等。相對而言,這個部分的工具還是比起許多其他ML包要豐富地多!什么流形學習啊都有。
2.5. Decomposing signals in components (matrix factorization problems)
2.7. Novelty and Outlier Detection
2.9. Neural network models (unsupervised)
3. Model selection and evaluation
模型選擇有的時候,特別是在使用ML創業的時候更需要把握。其實好多問題不同模型都差不多到80%精度,后面怎么提升才是重點。不止一個小伙伴想要用Deep Learning 這個話題作為噱頭準備9月份的博士或者碩士開題,那玩意兒想做好,你還真得有耐心調參數,回想起MSRA我那同一排的大嬸(神)們,都是NIPS啊!!!丫的,1%的提升都要尖叫了:),其實我想說,妹的,參數不一樣唄。。。這就是Black Magic(黑魔法)。玩深度學習的多了,估計以后不是模型值錢,是參數值錢了。
另外就是特征選擇,這個玩意兒也有講究,如果真正用ML創業,其實模型還是那些模型,特征和參數的選擇往往更能看出這個人的水平,別瞎試,千萬別。。。
3.1. Cross-validation: evaluating estimator performance
3.2. Grid Search: Searching for estimator parameters
3.3. Pipeline: chaining estimators
3.4. FeatureUnion: Combining feature extractors
3.5. Model evaluation: quantifying the quality of predictions
3.7. Validation curves: plotting scores to evaluate models
4.5. Pairwise metrics, Affinities and Kernels
5.5. Datasets in svmlight / libsvm format
5.6. The Olivetti faces dataset
5.7. The 20 newsgroups text dataset
5.8. Downloading datasets from the mldata.org repository
5.9. The Labeled Faces in the Wild face recognition dataset