簡介
這一節主要是為模型打補丁,在這之前筆者已經介紹並實現了幾種典型的機器學習模型,比如線性迴歸、logistic迴歸、最大熵、感知機、svm等,但目前它們都有一個共性,那就是構造的損失函式對每個樣本都是“一視同仁”的,即每個樣本在損失函式中權重都是一樣的,為了方便,可以將它們的損失函式做如下抽象:
\[L(w,x,y)=\sum_{i=1}^Nl(w,x_i,y_i)
\]
這裡\(L(\cdot)\)表示整體的損失函式,\(l(w,x_i,y_i)\)表示第\(i\)個樣本的損失函式,樣本量為\(N\),對具體情況有:
線性迴歸有:
\[l(w,x_i,y_i)=(y_i-w^Tx_i)^2
\]
對logistic迴歸:
\[l(w,x_i,y_i)=-y_ilog\phi(x_i,w)-(1-y_i)log(1-\phi(x_i,w)),這裡 \phi(x,w)=\frac{1}{1+e^{-w^Tx}}
\]
對感知機:
\[l(w,x_i,y_i)=max\{0,-y_iw^Tx_i\}
\]
對最大熵模型:
\[l(w,x_i,y_i)=\frac{exp(\sum_{j=1}^nw_jf_j(x_i,y_i))}{\sum_yexp(\sum_{j=1}^nw_jf_j(x_i,y))},這裡f_j,j=1,2,..,n表示特徵函式
\]
對svm:
\[l(w,x_i,y_i)=\frac{1}{2N}w^Tw+C\varepsilon_i,y_i(w^T\phi(x_i)+b)\geq 1-\varepsilon_i,\varepsilon_i\geq0
\]
代價敏感
如果對所有樣本的損失函式都考慮一樣的權重其實是有問題的,比如對於離群點、異常點這樣的資料,其實可以忽略掉其損失函式;特別地,對於類別不平衡分類問題,我們可以給少數類樣本更高的權重,而對於多數類更低的權重;另外對於像adaboost這樣的整合學習方法,我們可以迭代調整每個樣本點的權重以組合得到一個不錯的強分類器;所以在損失函式中考慮樣本權重,在某些場景下其實很有必要,簡單來說考慮樣本權重後,損失函式可以更新如下:
\[L(w,x,y)=\sum_{i=1}^N\alpha_il(w,x_i,y_i)
\]
這裡\(\alpha_i\)表示樣本\(i\)的權重
程式碼實現
程式碼實現其實很easy,根據目前的情況可以分為兩類:
(1)若採用的隨機梯度下降,可以對每次更新時的梯度\(dw\)乘以\(\alpha_i\);
(2)若採用對偶方式求解,則對其拉格朗日乘子做調整
具體地,我們為fit
函式新增一個引數sample_weight
以指定每個樣本的權重(對各模型的更新程式碼就不帖了,見ml_models),接下來我們用svm測試不平衡分類的效果
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
import numpy as np
import os
os.chdir('../')
from ml_models import utils
from ml_models.svm import SVC
%matplotlib inline
X, y = make_classification(n_samples=500, n_features=2,
n_informative=2,n_redundant=0,
n_repeated=0, n_classes=2,
n_clusters_per_class=1,weights=[0.05, 0.95],
class_sep=3,flip_y=0.05, random_state=0)
svc_without_sample_weight=SVC(kernel='rbf',gamma=2.0,tol=0.01)
svc_without_sample_weight.fit(X,y)
utils.plot_decision_function(X=X,y=y,clf=svc_without_sample_weight)
#然後我們加大少數類的權重
weights=np.where(y==0,20,1)
svc_with_sample_weight=SVC(kernel='rbf',gamma=2.0,tol=0.01)
svc_with_sample_weight.fit(X,y,sample_weight=weights)
utils.plot_decision_function(X=X,y=y,clf=svc_with_sample_weight)