1. 程式人生 > >機器學習--邏輯迴歸及乳腺癌預測

機器學習--邏輯迴歸及乳腺癌預測

邏輯迴歸演算法是用來解決分類問題的演算法。

邏輯迴歸模型由sklearn.linear_model.LogisticRegression實現

例項:乳腺癌預測

a. 模型訓練

# 載入自帶乳腺癌資料集
from sklearn.datasets import load_breast_cancer

cancer=load_breast_cancer()
X=cancer.data
y=cancer.target
print('data.shape:{0};no. positive:{1};no. negative:{2}'.format(X.shape,y[y==1].shape[0],y[y==0].shape[0]))
print(cancer.data[0])
data.shape:(569, 30);no. positive:357;no. negative:212
[1.799e+01 1.038e+01 1.228e+02 1.001e+03 1.184e-01 2.776e-01 3.001e-01
 1.471e-01 2.419e-01 7.871e-02 1.095e+00 9.053e-01 8.589e+00 1.534e+02
 6.399e-03 4.904e-02 5.373e-02 1.587e-02 3.003e-02 6.193e-03 2.538e+01
 1.733e+01 1.846e+02 2.019e+03 1.622e-01 6.656e-01 7.119e-01 2.654e-01
 4.601e-01 1.189e-01]
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2)

from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train,y_train)

train_score = model.score(X_train,y_train)
test_score = model.score(X_test,y_test)
print('train score:{train_score: .6f}; test score:{test_score:.6f}'.format(train_score=train_score,test_score=test_score))

# 檢視預測樣本中有幾個正確
y_pred = model.predict(X_test)
# sum()只返回True的個數
print('matchs:{0}/{1}'.format(np.equal(y_pred,y_test).sum(),y_test.shape[0]))
train score: 0.967033; test score:0.921053
matchs:105/114

可以看到,在114個測試集樣本中,預測成功的有105個。

針對二分類問題,Logistic Regression模型會針對每個樣本輸出兩個概率(0和1的概率),哪個概率高就輸出哪個類別。

因此,可以針對測試資料集,找出模型預測自信度低於90%的樣本,即預測為陰性的自信度與預測為陽性的自信度同時高於10%的樣本。

model.predict_proba()計算概率

# 找出預測概率低於90%的樣本
y_pred_proba = model.predict_proba(X_test)   #每個測試樣本的測試概率
print('sample of predict probability:{0}'.format(y_pred_proba[0]))  #列印第一個樣本資料

# 找出第一列,即預測為陰性的概率大於0.1的樣本
result = y_pred_proba[y_pred_proba[:,0]>0.1]

# 在result裡找出第二列,即預測為陽性概率大於0.1的樣本
result_1 = result[result[:,1]>0.1]
print(result_1)
sample of predict probability:[0.01939711 0.98060289]
[[0.88507494 0.11492506]
 [0.42675504 0.57324496]
 [0.1620304  0.8379696 ]
 [0.76926382 0.23073618]
 [0.17474437 0.82525563]
 [0.89571027 0.10428973]
 [0.61655269 0.38344731]
 [0.73476095 0.26523905]
 [0.10713253 0.89286747]
 [0.67842307 0.32157693]
 [0.89533222 0.10466778]
 [0.15608456 0.84391544]
 [0.86678907 0.13321093]
 [0.82521291 0.17478709]
 [0.19164219 0.80835781]
 [0.21962619 0.78037381]
 [0.44663372 0.55336628]
 [0.33092213 0.66907787]
 [0.63308328 0.36691672]
 [0.11658098 0.88341902]
 [0.80607166 0.19392834]
 [0.80001438 0.19998562]
 [0.86308949 0.13691051]
 [0.19086302 0.80913698]
 [0.12474998 0.87525002]]

可以看到有些樣本的預測概率較低:[0.61655269 0.38344731],預測為陰性的概率為61%。

b. 模型優化

LogisticRegression模型預測準確度達到92%,較好地預測結果。要優化模型,可以先從增加多項式特徵入手:

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline

def polynomial_model(degree=1,**kwarg):
    polynomial_features = PolynomialFeatures(degree=degree, include_bias=False)
    logistic_regression = LogisticRegression(**kwarg)
    pipeline = Pipeline([('polynomial_features',polynomial_features),('logistic_regression',logistic_regression)])
    return pipeline

# 二階多項式
import time
# 使用L1範數為正則項,實現引數稀疏化
model = polynomial_model(degree=2,penalty='l1')

start = time.clock()
model.fit(X_train,y_train)

train_score = model.score(X_train,y_train)
test_score = model.score(X_test,y_test)

print('elaspe:{0:.6f}; train score:{1:.6f}; test score:{2:.6f}'.format(time.clock()-start,train_score,test_score))

elaspe:0.202307; train score:1.000000; test score:0.947368

找出二階多項式logisticRegression模型的特徵數量,以及非0特徵引數數量:

model.named_steps['']提取pipeline中的模型

model.coef_模型係數

logistic_regression = model.named_steps['logistic_regression']
print('model parameters shape:{0};count of non-zero element:{1}'.format(logistic_regression.coef_.shape,np.count_nonzero(logistic_regression.coef_)))
model parameters shape:(1, 495);count of non-zero element:86

原模型特徵有30個,變換成二階多項式後有495個特徵,其中非零特徵有86個,大部分特徵被拋棄。

c. 學習曲線

畫出學習曲線,對比使用L1範數、L2範數作為正則項的一階多項式模型、二階多項式模型,找出最佳的模型。

# L1範數的一階和二階多項式
cv = ShuffleSplit(n_splits=10,test_size=0.2,random_state=0)
title = 'Learning Curve(degree ={0},penalty={1})'
degrees=[1,2]
penalty='l1'

start=time.clock()
plt.figure(figsize=(12,4),dpi=144)
for i in range(len(degrees)):
    plt.subplot(1,2,i+1)
    plot_learning_curve(polynomial_model(degree=degrees[i],penalty=penalty),title.format(degrees[i],penalty),X,y,ylim=(0.8,1.01),cv=cv)
print('elaspe:{0:.6f}'.format(time.clock()-start))

# L2範數的一階和二階多項式
penalty='l2'

start=time.clock()
plt.figure(figsize=(12,4),dpi=144)
for i in range(len(degrees)):
    plt.subplot(1,2,i+1)
    plot_learning_curve(polynomial_model(degree=degrees[i],penalty=penalty),title.format(degrees[i],penalty),X,y,ylim=(0.8,1.01),cv=cv)
print('elaspe:{0:.6f}'.format(time.clock()-start))

可以看到,使用2階多項式,L1範數訓練集和測試集的準確度最高。

L1: elaspe:12.783659  L2:elaspe:3.204324

L1範數學習曲線用時較長,這是因為sklearn的learning_curve()函式在畫學習曲線時要對模型進行多次訓練,並計算交叉驗證樣本評分。同時,為了使曲線更平滑,針對每個點還會進行多次計算求平均值,這就是ShuffleSplit的作用。

本樣本數只有569個,是很小的資料集,如果資料集增加到100倍甚至更多,可以先抽取一小部分資料來畫學習曲線,待選擇好最有引數後再使用全部資料來訓練模型。

參考:

黃永昌《scikit-learn機器學習》