邏輯迴歸
算法基礎理解
前面我們講到過線性迴歸算法和多項式迴歸算法,算法的本質以及目的便是求出 ý = f(x),如果給函數輸入一個預測樣本 x ,經過 f(x) 運算後得到一個 ý;但是這種方法存在問題,那便是,我們得到的預測值是處在負無窮到正無窮之間的,沒有限制,這樣做的弊端很大。
但是邏輯迴歸不同,邏輯迴歸的原理是將樣本的特徵和樣本發生的概率結合起來,預測樣本發生的概率,然後再對樣本發生的概率進行分析,同時這也是邏輯迴歸算法和其他算法的不同點。
邏輯迴歸算法既可以解決分類問題(二分類,也可以通過改進解決多分類問題),也可以解決迴歸問題。
公式推導以及代碼封裝
代碼封裝
class LogisticRegression:
def __init__(self):
self.coef_ = None
self.intercept_ = None
self._theta = None
'''tool function'''
def _sigmod(self,t):
return 1. / (1. + np.exp(-t))
'''use the gradient to fit the model'''
def fit(self,X_train,y_train,eta=0.01,n_iters = 1e4):
'''check'''
assert X_train.shape[0] == y_train.shape[0],\
"the size must be valid"
def J(theta,X_b,y):
y_hat = self._sigmod(X_b.dot(theta))
try:
return -np.sum(y*np.log(y_hat) + (1-y)*np.log(1-y_hat)) / len(y)
except:
return float('inf')
def DJ(theta,X_b,y):
return X_b.T.dot(self._sigmod(X_b.dot(theta)) - y) / len(X_b)
def gradient_decent(X_b,y,initial_theta,eta,n_iters=1e4,epsilon = 1e-8):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
last_theta = theta
gradient = DJ(theta,X_b,y)
theta = theta - eta*gradient
while(abs(J(theta,X_b,y) - J(last_theta,X_b,y))):
break
cur_iter += 1
return theta
'''main step'''
X_b = np.hstack([np.ones((len(X_train),1)),X_train])
initial_theta = np.zeros(X_b.shape[1])
self._theta = gradient_decent(X_b,y_train,initial_theta,eta,n_iters)
self.coef_ = self._theta[1:]
self.intercept_ = self._theta[0]
return self
def predict_proda(self,X_predict):
'''check'''
assert self.coef_ is not None and self.intercept_ is not None,\
"predict after fit"
assert X_predict.shape[1] == len(self.coef_),\
"the size must be valid"
X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
return self._sigmod(X_b.dot(self._theta))
'''real predict'''
def predict(self,X_predict):
'''check'''
assert self.coef_ is not None and self.intercept_ is not None, \
"predict after fit"
assert X_predict.shape[1] == len(self.coef_), \
"the size must be valid"
proda = self.predict_proda(X_predict)
return np.array(proda>=0.5,dtype='int')
def __repr__(self):
return "LogisticRegression()"
決策邊界
爲了可視化模型,我們在分類問題中有一個十分重要的工具,叫做決策邊界。其定義簡單明瞭,我們在特徵空間內部,根據不同的特徵對樣本進行分類,不同類型之間的分界線就是決策邊界,通過決策邊界我們可以更好的可視化模型。值得注意的是,處於決策邊界上的點我們歸爲哪一類都可以,但是這種情況很少發生。
繪製決策邊界代碼封裝:(二維空間內)
from matplotlib.colors import ListedColormap
def plot_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(-1, 1)
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
導入鳶尾花數據集數據
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 取前兩個特徵
X = X[y<2,:2]
y = y[y<2]
plt.scatter(X[y==0, 0], X[y==0, 1], color='red')
plt.scatter(X[y==1, 0], X[y==1, 1], color='blue')
plt.show()
繪製不同模型的決策邊界
邏輯迴歸模型:
# 劃分數據集
from sklearn.model_selection import train_test_split
# 繪製邏輯迴歸模型的決策邊界
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
plot_decision_boundary(log_reg, axis=[4, 7.5, 1.5, 4.5])
plt.scatter(X[y==0, 0], X[y==0, 1], color='red')
plt.scatter(X[y==1, 0], X[y==1, 1], color='blue')
plt.show()
KNN模型
from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train, y_train)
plot_decision_boundary(knn_clf, axis=[4, 7.5, 1.5, 4.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.show()
邏輯迴歸(使用多項式特徵)
我們之前大多數實現的都是接近於在我們的數據集中找到一條直線分割兩部分數據集,也可以理解爲解決的基本上都是二分類問題,但是現實中大多數都是多分類問題,我們可以借鑑多項式迴歸的做法,在邏輯迴歸中引入多項式特徵,實現多分類問題。
代碼實現:
模擬數據集
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(666)
X = np.random.normal(0,1,size(200,2))
y = np.array(X[:,0]**2 + X[:,1]**2 < 1.5,dtype='int')
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
邏輯迴歸,不添加多項式項
from sklearn.linear_model import LogisticRegression
log = LogisticRegression()
log.fit(X,y)
plot_decision_boundary(log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
邏輯迴歸,添加多項式項
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticsRegression
def PolynomialLogisticRegression(degree):
return Pipeline([
('poly', PolynomialFeatures(degree=degree)),
('std_scaler', StandardScaler()),
('log_reg', LogisticRegression())
])
poly_log_reg = PolynomialLogisticRegression(degree=2)
poly_log_reg.fit(X, y)
plot_decision_boundary(poly_log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
補充點:scikit-learn中進行多項式邏輯迴歸時爲了解決過擬合的問題引入的正則項是 C.J(θ) + L2 ,L2是默認,我們可以通過管道以及調參進行調整。
OVR & OVO
使用邏輯迴歸算法可以通過另外的方式來解決多分類問題,正如本節所講的OVR以及OVO。
OVR(One vs Rest):一對剩餘的意思,有時候我們也將其稱爲OVA(One vs All),其主要的原理便是,取一種樣本作爲一類,讓其餘的樣本變爲另外一類,這樣就變成了n個二分類問題,使用邏輯迴歸算法訓練出n個模型,將待預測的樣本傳入這n個模型中,所得到的的概率最高的模型對應的樣本類型便是該預測樣本的類型。
OVO(One VS One):一共具有n個樣本,兩兩結合,一共產生了Cn2中情況,也產生了Cn2個預測結果,種類的最多的便是預測的樣本類型。