1. 程式人生 > >[二]機器學習之迴歸

[二]機器學習之迴歸

2.1 線性迴歸

2.1.1 實驗資料

    1.資料描述

資料來自出版書籍《An Introduction to Statistical Learning with Applications in R》(Springer,2013),作者Gareth James,Daniela Witten,Trevor Hastie and Robert Tibshirani。共200條資料,每條資料4個屬性。

資料下載地址:http://www-bcf.usc.edu/~gareth/ISL/Advertising.csv

    2.資料集資訊

資料共4列200行,每一行為一個特定的商品,前3列為輸入特徵,最後一列為輸出特徵。

輸入特徵:

TV:該商品用於電視上的廣告費用(千元,下同)

Radio:在廣播媒體上投資的廣告費用

Newspaper:用於報紙媒體的廣告費用

輸出特徵:

Sale:該商品的銷量

    3.資料樣例

2.1.2 實驗過程

執行python

    1.收集、準備資料

import pandas as pd
data = pd.read_csv("Advertising.csv")
data.head()#顯示前5行

檢視資料集大小

data.shape

    2.分析資料

import matplotlib.pyplot as plt
import pandas as pd
if __name__ == "__main__":
    path = "Advertising.csv"
#pandas讀入資料
    data = pd.read_csv(path)
    x = data[['TV','radio','newspaper']]
    y = data['sales']
    plt.figure(figsize=(9,12))
    plt.subplot(311)
    plt.plot(data['TV'],y,'ro')
    plt.title('TV')
    plt.grid()
    plt.subplot(312)
    plt.plot(data['radio'],y,'g^')
    plt.title('radio')
    plt.grid()
    plt.subplot(313)
    plt.plot(data['newspaper'],y,'b*')
    plt.title('newspaper')
    plt.grid()
    plt.tight_layout()
    plt.show()
    

得到繪圖:

    3.使用pandas構建特徵向量x和列標籤y

feature_cols = ['TV','radio','newspaper']
X = data[feature_cols]
print X.head()
print type(X)
print X.shape
y = data['sales']
print y.head()

結果如下:

    4.構建訓練集與測試集

from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=1)
#預設75%為訓練集,25%為測試集
print X_train.shape
print y_train.shape
print X_test.shape
print y_test.shape

    5.sklearn線性迴歸

from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
model = linreg.fit(X_train,y_train)
print model
print linreg.intercept_
print linreg.coef_
zip(feature_cols,linreg.coef_)

由此,可以得到各項係數:y=2.8769+0.0465*TV+0.1791*radio+0.00345*newspaper

    6.預測

y_pred = linreg.predict(X_test)
print y_pred
print type(y_pred)

    7.迴歸問題的評價測度

對於分類問題,評價測度(evalution metrics)是準確率,但這種方法不適用與迴歸問題。我們使用連續數值的評價測度

(1)平均絕對誤差(Mean Absolute Error,MAE)

(2)均方誤差(Mean Squared Error,MSE)

(3)均方根誤差(Root Mean Squared Error,RMSE)

此處使用RMSE:

print type(y_pred),type(y_test)
print len(y_pred),len(y_test)
print y_pred.shape,y_test.shape
from sklearn import metrics
import numpy as np
sum_mean=0
for i in range(len(y_pred)):
    sum_mean += (y_pred[i]-y_test.values[i])**2

print "RMSE by hand:",np.sqrt(sum_mean/len(y_pred))

    8.作圖

import matplotlib.pyplot as plt
plt.figure()
plt.plot(range(len(y_pred)),y_pred,'b',label="predict")#藍色線表示預測值
plt.plot(range(len(y_pred)),y_test,'r',label="test")#紅色線為真實值
plt.legend(loc="upper right")#右上角顯示標籤
plt.xlabel("the number of sales")
plt.ylabel("value of sales")
plt.show()

2.1.3 結果分析

根據結果y=2.8769+0.0465*TV+0.1791*radio+0.00345*newspaper可以看出,newspaper的係數很小,再觀察收益-newspaper散點圖,我們發現newspaper的線性關係不明顯,因此我們可以嘗試去除這個特徵,看看回歸預測的結果如何。

feature_cols = ['TV','radio']
X = data[feature_cols]
from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=1)
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
model = linreg.fit(X_train,y_train)
zip(feature_cols,linreg.coef_)
y_pred = linreg.predict(X_test)
sum_mean=0
for i in range(len(y_pred)):
    sum_mean += (y_pred[i]-y_test.values[i])**2

print "RMSE by hand:",np.sqrt(sum_mean/len(y_pred))
plt.figure()
plt.plot(range(len(y_pred)),y_pred,'b',label="predict")#藍色線表示預測值
plt.plot(range(len(y_pred)),y_test,'r',label="test")#紅色線為真實值
plt.legend(loc="upper right")#右上角顯示標籤
plt.xlabel("the number of sales")
plt.ylabel("value of sales")
plt.show()

測得結果為:1.387

預測值與真實值的關聯圖如下:

在移除newspaper特徵之後,得到的RMSE值變小了,說明newspaper特徵可能不適合作為預測銷量的特徵,因此,我們得到了新的模型。

2.1.4 注意事項

本模型雖然簡單,但它涵蓋了機器學習的相當部分內容,如使用75%的訓練集和25%的測試集,這往往是探索機器學習的第一步。得到的線性模型發現有負權,我們使用最為簡單的方法:直接刪除;但這樣做,仍然得到了更好的預測結果。

在機器學習中,由“奧卡姆剃刀”原理:如果能夠用簡單模型解決問題,則不用複雜的模型,因為複雜模型往往增加了不確定性,造成過多的成本浪費,且容易過擬合。

2.2 Logistic迴歸

2.2.1實驗資料

鳶尾花資料集或許是最有名的模式識別測試資料。該資料集包括3個鳶尾花類別,每個類別50個樣本,其中一個類別是與另外兩類線性可分的,而另外兩類線性不可分。

由於最原始的資料集存在兩個錯誤(35號和38號樣本),因此我們在試驗中使用的是修正過的資料。

資料下載地址:http://archive.ics.uci.edu/ml/dataset/Iris

2.2.2實驗過程

(一)資料描述

該資料集共包含150行,每行1個樣本,每個樣本有5個欄位:花萼長度(cm),花萼寬度(cm),花瓣長度(cm),花瓣寬度(cm),類別(三種,Iris Setosa,Iris Versicolor,Iris Virginica)

資料集特徵 多變數 記錄數 150
屬性特徵 實數 屬性數目 4
相關應用 分類 缺失值

(二)實驗程式碼

import numpy as np
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt

def iris_type(s):
    it = {'Iris-setosa':0,'Iris-versicolor':1,'Iris-virginica':2}
    return it[s]

if __name__ == "__main__":
    path = 'iris.data'#資料檔案路徑
    #路徑,浮點型資料,逗號分隔,第4列用函式iris_type單獨處理
    data = np.loadtxt(path,dtype=float,delimiter=',',converters={4:iris_type})
    #將資料的0-3列組成x,第4列得到y
    x,y = np.split(data,(4,),axis=1)
    #為了視覺化,僅使用前兩列特徵
    x = x[:,:2]
    #Logistic迴歸模型
    logreg = LogisticRegression()
    #根據資料[x,y],計算迴歸引數
    logreg.fit(x,y.ravel())
    #畫圖
    #橫縱各取樣多少個值
    N,M = 500,500
    #得到第0列範圍
    x1_min,x1_max = x[:,0].min(),x[:,0].max()
    #得到第1列範圍
    x2_min,x2_max = x[:,1].min(),x[:,1].max()
    t1 = np.linspace(x1_min,x1_max,N)
    t2 = np.linspace(x2_min,x2_max,M)
    #生成網格取樣點
    x1,x2 = np.meshgrid(t1,t2)
    #測試點
    x_test = np.stack((x1.flat,x2.flat),axis=1)
    #預測值
    y_hat = logreg.predict(x_test)
    #使之與輸入形狀相同
    y_hat = y_hat.reshape(x1.shape)
    #預測值的顯示
    plt.pcolormesh(x1,x2,y_hat,cmap=plt.cm.prism)
    plt.scatter(x[:,0],x[:,1],c=np.squeeze(y),edgecolors='k',cmap=plt.cm.prism)
    #顯示樣本
    plt.xlabel('Sepal length')
    plt.ylabel('Sepal width')
    plt.xlim(x1_min,x1_max)
    plt.ylim(x2_min,x2_max)
    plt.grid()
    plt.show()
    #訓練集上的預測結果
    y_hat = logreg.predict(x)
    y = y.reshape(-1)
    print y_hat.shape
    print y.shape
    result = y_hat == y
    print y_hat
    print y
    print result
    c = np.count_nonzero(result)
    print c
    print 'Accuracy: %.2f%%' %(100*float(c)/float(len(result)))

2.2.3結果分析

(一)實驗結果

(二)結果分析

1.僅僅使用兩個特徵:花萼長度和寬度,在150個樣本中,有115個分類正確,正確率為76.67%。

2.當我們使用更多特徵(4個特徵全部使用),再次執行程式:

import numpy as np
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt

def iris_type(s):
    it = {'Iris-setosa':0,'Iris-versicolor':1,'Iris-virginica':2}
    return it[s]

if __name__ == "__main__":
    path = 'iris.data'#資料檔案路徑
    #路徑,浮點型資料,逗號分隔,第4列用函式iris_type單獨處理
    data = np.loadtxt(path,dtype=float,delimiter=',',converters={4:iris_type})
    #將資料的0-3列組成x,第4列得到y
    x,y = np.split(data,(4,),axis=1)
    #為了視覺化,僅使用前兩列特徵
    #x = x[:,:2]
    #Logistic迴歸模型
    logreg = LogisticRegression()
    #根據資料[x,y],計算迴歸引數
    logreg.fit(x,y.ravel())
    #畫圖
    #橫縱各取樣多少個值
    N,M,P,Q = 100,100,100,100
    #得到第0列範圍
    x1_min,x1_max = x[:,0].min(),x[:,0].max()
    #得到第1列範圍
    x2_min,x2_max = x[:,1].min(),x[:,1].max()
    #得到第2列範圍
    x3_min,x3_max = x[:,2].min(),x[:,2].max()
    #得到第3列範圍
    x4_min,x4_max = x[:,3].min(),x[:,3].max()
    t1 = np.linspace(x1_min,x1_max,N)
    t2 = np.linspace(x2_min,x2_max,M)
    t3 = np.linspace(x3_min,x3_max,P)
    t4 = np.linspace(x4_min,x4_max,Q)
    #生成網格取樣點
    x1,x2,x3,x4 = np.meshgrid(t1,t2,t3,t4)
    #測試點
    x_test = np.stack((x1.flat,x2.flat,x3.flat,x4.flat),axis=1)
    #預測值
    y_hat = logreg.predict(x_test)
    #使之與輸入形狀相同
    y_hat = y_hat.reshape(x1.shape)
    #訓練集上的預測結果
    y_hat = logreg.predict(x)
    y = y.reshape(-1)
    print y_hat.shape
    print y.shape
    result = y_hat == y
    print y_hat
    print y
    print result
    c = np.count_nonzero(result)
    print c
    print 'Accuracy: %.2f%%' %(100*float(c)/float(len(result)))

 

可以發現,在150個樣本中,有144個分類正確,正確率為96.00%。