文章原創(chuàng),最近更新:2018-06-4
1.交叉驗證
2.模型評估方法
3.正則化懲罰
4.邏輯回歸模型
課程來源: python數據分析與機器學習實戰(zhàn)-唐宇迪
課程資料:這里所涉及到的練習資料creditcard.csv相關的鏈接以及密碼如下:
鏈接: https://pan.baidu.com/s/1APgU4cTAaM9zb8_xAIc41Q 密碼: xgg7
1.交叉驗證
這節(jié)課的主要內容是交叉驗證的學習.首先要了解交叉驗證,具體如下:
- 什么是交叉驗證法但指?
在建立分類模型時,交叉驗證(Cross Validation)簡稱為CV抗楔,CV是用來驗證分類器的性能棋凳。它的主體思想是將原始數據進行分組,一部分作為訓練集连躏,一部分作為驗證集剩岳。利用訓練集訓練出模型,利用驗證集來測試模型入热,以評估分類模型的性能拍棕。
訓練數據上的誤差叫做訓練誤差,它對算法模型的評價過于樂觀勺良。利用測試數據測量的是測試誤差绰播,我門報告的是測試誤差。有的時候訓練集上的正確率可能達到100%郑气,但是在測試集上可能和隨機猜測差不多幅垮。
- 為什么用交叉驗證法?
交叉驗證用于評估模型的預測性能尾组,尤其是訓練好的模型在新數據上的表現忙芒,可以在一定程度上減小過擬合。
還可以從有限的數據中獲取盡可能多的有效信息讳侨。
-
交叉驗證常用的幾種方法:
1.去一法 Leave-One-Out Cross Validation(記為LOO-CV)**
它的做法是呵萨,從訓練集中拿出一個樣本,并在缺少這個樣本的數據上訓練出一個模型跨跨,然后看模型是否能對這個樣本正確分類潮峦。假設樣本個數有N個囱皿,則該方法一共要訓練出N個模型,利用這N個模型最終的驗證集的分類準確率的平均數作為此下LOO-CV分類器的性能指標忱嘹。然而隨著數據量的增大嘱腥,工作量會劇增,在時間是處于劣勢拘悦。但是它具有顯著德爾優(yōu)點:
1)每一回合中幾乎所有的樣本皆用于訓練模型,因此最接近原始樣本的分布,這樣評估所得的結果比較可靠齿兔。
2)實驗過程中沒有隨機因素會影響實驗數據,確保實驗過程是可以被復制的。2础米、k折交叉驗證 K-fold Cross Validation(記為K-CV)
K折交叉驗證是以部分代價去獲得去一法的大部分收益分苇,這里的k折是吧數據分為k組。它的做法是將k-1組作為訓練集訓練出一個模型屁桑,然后將剩下的一組用做測試集医寿。利用這k個模型最終的平均正確率來衡量模型的正確率。常使用的一般是5折10折蘑斧,5折交叉驗證是將數據分為5組靖秩。實際做法是把20%的數據拿出去作為測試集,將剩下的80%數據訓練模型乌叶。使用80%或者90%的數據與使用所有數據的效果比較接近盆偿。
使用交叉驗證時,需要謹慎保持數數據的分布平衡准浴,不能在某一折中全部是一類的數據事扭。
學習參考鏈接:
1、為什么要用交叉驗證
2乐横、一篇文章,帶你明白什么是過擬合,欠擬合以及交叉驗證
比如有個集合叫data求橄,通常建立機器模型的時候,先對數據進行切分或者選擇葡公,取前面80%的數據當成訓練集罐农,取20%的數據當成測試集。80%的數據是來建立一個模型催什,剩下的20%的數據是用來測試模型的表達效果是怎么樣的涵亏?
- 因此第一步是將數據進行切分,切分成訓練集以及測試集蒲凶。這部分操作是必須要做的气筋。
- 第二步還要在訓練集進行平均切分,比如平均切分成3份旋圆,分別是數據集1,2,3宠默。為什么要進行隨機的切分呢?因為最終的測試數據集灵巧,只能夠在一個最終的測試階段搀矫,在模型以及參數都調整好之后抹沪,才能用測試集去測試當前模型的效果是怎么樣的?
在建立模型的時候瓤球,不管建立什么樣的模型融欧,這個模型伴隨著很多參數,有不同的參數進行選擇冰垄,這個參數選擇大比較好蹬癌,還是選擇小比較好一些?從經驗值角度來說虹茶,肯定沒辦法很準的,怎么樣去確定這個參數呢隅要?只能通過交叉驗證的方式蝴罪。
那什么又叫交叉驗證呢?
- 第一次:將數據集1,2分別建立模型步清,用數據集3在當前權重下一個驗證的效果要门。數據集3是個驗證集,驗證集是訓練集的一部分廓啊。用驗證集去收集模型是好還是壞欢搜?
- 第二次:將數據集1,3分別建立模型,用數據集2在當前權重下一個驗證的效果谴轮。
- 第三次:將數據集2,3分別建立模型炒瘟,用數據集1在當前權重下一個驗證的效果。
為什么要驗證模型3次呢第步?其實這些操作并非是重復的疮装,每一次的訓練集是不一樣的。(比如第一次的訓練集是1和2粘都,第二次的訓練集是1和3廓推,第三次的訓練集是3和2)此外驗證集也是不一樣的。(比如第一次的驗證集是3翩隧,第二次的驗證集是2樊展,第三次的驗證集是1)
現在是比較求穩(wěn)的操作,如果只是求一次的交叉驗證堆生,這樣的操作會存在風險专缠。比如只做第一次交叉驗證,會使3驗證集偏簡單一些顽频。會使模型效果偏高藤肢,此外模型有些數據是錯誤值以及離群值,如果把這些不太好的數據當成驗證集糯景,會使模型的效果偏低的嘁圈。模型當然是不希望偏高也不希望偏低省骂,那就需要多做幾次交叉驗證模型,求平均值最住。這里有1钞澳,2,3分別求驗證集涨缚,每個驗證集都有評估的標準轧粟。最終模型的效果將1,2,3的評估效果加在一起,再除以3,就可以得到模型一個大致的效果脓魏。
交叉驗證只是做一步求穩(wěn)的操作兰吟,要讓模型的評估效果是可信的。既不能偏高也不能偏低茂翔,就這樣求了平均值來當模型的效果混蔼。
之前說到要做數據交叉驗證,要對原始數據集進行切分珊燎。
- sklearn.cross_validation是交叉驗證模塊惭嚣,train_test_split對原始數據集有進行切分的操作。
- test_size = 0.3實際做法是把30%的數據拿出去作為測試集悔政,將剩下的70%數據訓練模型晚吞。這個可以根據實際需求進行修改。
- random_state = 0谋国,為了使訓練集以及測試集一樣槽地,設置隨機狀態(tài)為0,這樣就拋開了樣本對模型的影響烹卒。(之前有對原始數據集進行洗牌闷盔,再切分測試集以及訓練集,才能保證隨機切分旅急。)
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)
之前做了下采樣的數據集逢勾,讓0和1都比較少,要對下采樣數據集進行的交叉切分相同的操作藐吮。
X_train_undersample, X_test_undersample, y_train_undersample, y_test_undersample = train_test_split(X_undersample
,y_undersample
,test_size = 0.3
,random_state = 0)
為什么同時要對下采樣以及原始的數據進行交叉切分呢?
現在要拿下采樣的數據進行模型訓練的操作,但是模型訓練完要進行測試,那么測試的時候拿什么數據集進行測試呢?是拿下采樣切分的測試數據集進行測試么?二下采樣切分的測試數據數量比較少,而且也是下采樣的測試數據集,不具備原始數據的分布規(guī)則.最終的測試集是拿原始數據集中的測試數據集再進行測試.
因此這里有2種切分的方式,第一種是對原始數據集即28萬個數據進行交叉切分.然后有對984個下采樣數據集又進行了一次交叉切分,
from sklearn.cross_validation import train_test_split
# Whole dataset
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)
print("Number transactions train dataset: ", len(X_train))
print("Number transactions test dataset: ", len(X_test))
print("Total number of transactions: ", len(X_train)+len(X_test))
# Undersampled dataset
X_train_undersample, X_test_undersample, y_train_undersample, y_test_undersample = train_test_split(X_undersample
,y_undersample
,test_size = 0.3
,random_state = 0)
print("")
print("Number transactions train dataset: ", len(X_train_undersample))
print("Number transactions test dataset: ", len(X_test_undersample))
print("Total number of transactions: ", len(X_train_undersample)+len(X_test_undersample))
輸出結果如下:
Number transactions train dataset: 199364
Number transactions test dataset: 85443
Total number of transactions: 284807
Number transactions train dataset: 688
Number transactions test dataset: 296
Total number of transactions: 984
后面會拿原始數據中的85443的數據集進行測試操作,而下采樣的數據總共有984個,訓練集的數據共有668個,測試集有296個,上面已經將數據集進行了切分,就可以進行建模的操作,在建模的過程中要使用邏輯回歸.
2.模型評估方法
假設有1000個病人的數據,要對1000個病人進行分類,有哪些是癌癥的?哪些不是患有癌癥的?
假設有990個人不患癌癥,10個人是患癌癥.用一個最常見的評估標準,比方說精度,就是真實值與預測值之間的差異.真實值用y來表示,預測值用y1來表示.y真實值1,2,3...10,共有10個樣本,y1預測值1,2,3...10,共有10個樣本.精度就是看真實值y與預測值y1是否一樣的.要么都是0,要么都是1,如果是一致,就用=表示,比如1號真實值樣本=預測值的1號樣本,如果不相等就用不等號來表示.如果等號出現了8個,那么它的精確度為8/10=80%,從而確定模型的精度.
990個人不患癌癥,10個人是患癌癥建立一個模型,所有的預測值都會建立一個正樣本.對1000個樣本輸入到模型,它的精確度是多少呢?990/1000=99%
這個模型把所有的值都預測成正樣本,但是沒有得到任何一個負樣本.在醫(yī)院是想得到癌癥的識別,但是檢查出來的結果是0個,雖然精度達到了99%,
但這個模型是沒有任何的含義的,因為一個癌癥病人都找不出來.在建立模型的時候一定要想好一件事,模型雖然很容易建立出來,那么難點是應該怎么樣去評估這樣的模型呢?
剛才提到了用精度去評估模型,但是精度有些時候是騙人的.尤其是在樣本數據不均衡的情況下.
接下來要講到一個知識點叫recall,叫召回率或叫查全率.recall有0或者1,我們的目標是找出患有癌癥的那10個人.因此根據目標制定衡量的標準.就是有10個癌癥病人,能夠檢測出來有幾個?如果檢測0個癌癥病人,那么recall值就是0/10=0;如果檢測2個癌癥病人,那么recall值就是2/10=20%.用recall檢測模型的效果更科學一些.
建立模型無非是選擇一些參數,如果精度專用recall來表示,也并非那么容易.在統(tǒng)計學中會經常提到的4個詞,分別如下:
比如一個班級有80個男生,20個女生,共100個人,在100多個人中有個目標,把所有的女生都抓出來.建立一個模型,挑選50個人,預測結果是20個是女的,剩下30個是男的.
- TP:表示預測對的正例結果,比如判斷成正例,20個女生,當成正例.
- FP:表示預測錯的正例結果,把負例判斷成正例,比如把男生判斷成女生,共有30個.
- FN:就是把女生錯當成男生的例子為0個.
- TN:就是把男生判斷成了男生,因此等于50.
這里的Recall = TP/(TP+FN)
3.正則化懲罰
先導入機器學習建模的庫
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import KFold, cross_val_score
from sklearn.metrics import confusion_matrix,recall_score,classification_report
from sklearn.linear_model import LogisticRegression邏輯回歸
-
from sklearn.cross_validation import KFold, cross_val_score,
- 這里的KFold是指交叉驗證的時候,可以選擇做幾倍的交叉驗證.之前有提到將原始的訓練集切分成3份,不光可以切分成3份,也可以切分成4份或者5份都可以的,可以根據自己的喜好,任意的切分.
- cross_val_score值是指交叉驗證評估得到的結果,
-
from sklearn.metrics import confusion_matrix,recall_score,classification_report
- confusion_matrix是混淆矩陣
在機器建模的時候需要做這樣的一件事,要做交叉驗證,要把原始的數據集切分成幾部分,fold = KFold(len(y_train_data),5,shuffle=False) ,這里將原始數據傳進來,并切分成了5部分.
在邏輯回歸當中,需要有寫參數傳進來,今天的參數叫做正則化懲罰項,什么叫正則化懲罰?
比如有A模型:?1溺拱、?2、?3...?10谣辞,比如還有B模型:?1迫摔、?2、?3...?10泥从,這兩個模型的recall值都是等于90%句占。如果兩個模型的recall值都是等于90%,是不是隨便選一個都可以呢躯嫉?
比如A模型的原點浮動比較大纱烘,具體如截圖:
比如B模型的原點浮動比較小杨拐,具體如截圖:
雖然兩個模型的recall值都是等于90%,A模型的浮動范圍太大了擂啥,都希望模型更加穩(wěn)定一些哄陶,不光滿足訓練的數據,還要盡可能的滿足測試數據哺壶。因此希望模型的浮動差異更小一些屋吨,差異小可以使過度擬合的風險更小一些。
過度擬合的意思是在訓練集表達效果很好,但是在測試集表達效果很差,因此這組模型發(fā)生了過擬合。過擬合是非常常見的現象,很大程度上是因為權重參數浮動較大引起的乘陪,因此希望得到B模型,因為B模型的浮動差異比較小。
那么怎么樣能夠得到B模型呢沙廉?從而就引入了正則化的東西,懲罰模型的?胖翰,因為模型的數據有時候分布大接剩,有時候分布小。希望大力度懲罰A模型萨咳,小力度懲罰B模型懊缺,可不可以呢?
- L2正則化
首先介紹一些L2正則化培他,對于目標損失函數來說鹃两,希望目標函數是越低越好的,在懲罰的過程中舀凛,需要在(loss)損失目標函數中+1/2w*w俊扳,即就是如下截圖:
對于A模型,w值浮動比較大猛遍,如果計算w*w的話馋记,這樣的話計算的目標損失函數的值就會更大。對于B模型而言懊烤,計算的目標損失函數的值也是如此梯醒。
分別計算A、B模型中的loss+1/2w*w中的值腌紧,哪個值更加低茸习?
- L1正則化
(loss)損失目標函數中+|w|,去計算當前的懲罰力度是多少壁肋?
因此有兩種懲罰函數号胚,一種是L2正則化籽慢,一種是L1正則化。
在判斷之前需要設置好參數涕刚,需要設置當前懲罰的力度有多大嗡综?可以設置成0.1懲罰力度比較小,也可以設置懲罰力度為1杜漠,也可以設置懲罰力度為10极景。但是懲罰力度等于多少的時候,效果比較好呢驾茴?具體多少也不知道盼樟,需要通過交叉驗證,去評估一下什么樣的參數達到更好的效果锈至。
c_param_range = [0.01,0.1,1,10,100]這里就是前面提到的那一章的懲罰力度晨缴。需要將這5個參數不斷的嘗試。
這一部分內容是可視化顯示峡捡,具體如下:
results_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
results_table['C_parameter'] = c_param_range
在循環(huán)里面利用懲罰力度的參數,看一下那個參數的取值效果更好.
for c_param in c_param_range:
print('-------------------------------------------')
print('C parameter: ', c_param)
print('-------------------------------------------')
print('')
下面的循環(huán)是對數據進行交叉驗證,具體如下:
lr = LogisticRegression(C = c_param, penalty = 'l1')首先建立邏輯回歸模型,在邏輯回歸函數,傳進C這個懲罰力度參數.懲罰的方式可以選擇l1懲罰或者l2懲罰.
lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())這個語句是對模型進行訓練,用交叉驗證的方式建立一個模型.
y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values),建立完模型之后就可以進行預測.
比如在C=0的情況下,它的效果是多少的?并計算recall的值,
recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
recall_accs.append(recall_acc)
print('Iteration ', iteration,': recall score = ', recall_acc)
4.邏輯回歸模型
完整的案例代碼如下:
def printing_Kfold_scores(x_train_data,y_train_data):
fold = KFold(len(y_train_data),5,shuffle=False)
# Different C parameters
c_param_range = [0.01,0.1,1,10,100]
results_table = pd.DataFrame(index = range(len(c_param_range),2), columns = ['C_parameter','Mean recall score'])
results_table['C_parameter'] = c_param_range
# the k-fold will give 2 lists: train_indices = indices[0], test_indices = indices[1]
j = 0
for c_param in c_param_range:
print('-------------------------------------------')
print('C parameter: ', c_param)
print('-------------------------------------------')
print('')
recall_accs = []
for iteration, indices in enumerate(fold,start=1):
# Call the logistic regression model with a certain C parameter
lr = LogisticRegression(C = c_param, penalty = 'l1')
# Use the training data to fit the model. In this case, we use the portion of the fold to train the model
# with indices[0]. We then predict on the portion assigned as the 'test cross validation' with indices[1]
lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
# Predict values using the test indices in the training data
y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values)
# Calculate the recall score and append it to a list for recall scores representing the current c_parameter
recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
recall_accs.append(recall_acc)
print('Iteration ', iteration,': recall score = ', recall_acc)
# The mean value of those recall scores is the metric we want to save and get hold of.
results_table.ix[j,'Mean recall score'] = np.mean(recall_accs)
j += 1
print('')
print('Mean recall score ', np.mean(recall_accs))
print('')
best_c = printing_Kfold_scores(X_train_undersample,y_train_undersample)
輸出結果如下:
-------------------------------------------
C parameter: 0.01
-------------------------------------------
Iteration 1 : recall score = 0.958904109589
Iteration 2 : recall score = 0.917808219178
Iteration 3 : recall score = 1.0
Iteration 4 : recall score = 0.972972972973
Iteration 5 : recall score = 0.954545454545
Mean recall score 0.960846151257
-------------------------------------------
C parameter: 0.1
-------------------------------------------
Iteration 1 : recall score = 0.835616438356
Iteration 2 : recall score = 0.86301369863
Iteration 3 : recall score = 0.915254237288
Iteration 4 : recall score = 0.932432432432
Iteration 5 : recall score = 0.878787878788
Mean recall score 0.885020937099
-------------------------------------------
C parameter: 1
-------------------------------------------
Iteration 1 : recall score = 0.835616438356
Iteration 2 : recall score = 0.86301369863
Iteration 3 : recall score = 0.966101694915
Iteration 4 : recall score = 0.945945945946
Iteration 5 : recall score = 0.893939393939
Mean recall score 0.900923434357
-------------------------------------------
C parameter: 10
-------------------------------------------
Iteration 1 : recall score = 0.849315068493
Iteration 2 : recall score = 0.86301369863
Iteration 3 : recall score = 0.966101694915
Iteration 4 : recall score = 0.959459459459
Iteration 5 : recall score = 0.893939393939
Mean recall score 0.906365863087
-------------------------------------------
C parameter: 100
-------------------------------------------
Iteration 1 : recall score = 0.86301369863
Iteration 2 : recall score = 0.86301369863
Iteration 3 : recall score = 0.966101694915
Iteration 4 : recall score = 0.959459459459
Iteration 5 : recall score = 0.893939393939
Mean recall score 0.909105589115
*********************************************************************************
Best model to choose from cross validation is with C parameter = 0.01
*********************************************************************************
C parameter是懲罰力度參數,從這里可以看出哪些recall值比較低?哪些recall值比較高?希望找出較高模型的參數,這個數值是其中一個5倍交叉驗證的結果值,具體如下:
Iteration 1 : recall score = 0.849315068493
Iteration 2 : recall score = 0.86301369863
Iteration 3 : recall score = 0.966101694915
Iteration 4 : recall score = 0.959459459459
Iteration 5 : recall score = 0.893939393939
通過結果可以看出,當懲罰參數是0.01,recall的值最高.