广义线性模型家族中,依据因变量的不同,可以有如下的划分:
(1)如果是连续的,就是多重线性回归。
(2)如果是二项分布,就是逻辑回归。
(3)如果是泊松(Poisson)分布,就是泊松回归。
(4)如果是负二项分布,就是负二项回归。
逻辑回归名字中虽有“回归”二字,但它是分类算法。逻辑回归的因变量可以是二分类的,也可以是多分类的,但是二分类的更为常用,也更加容易解释。所以实际中最常用的就是二分类的逻辑回归。
逻辑回归模型函数是我们后面常用的激活函数“sigmoid”函数,如果我们的输入为 X θ X\theta Xθ,输出为0和1(两类就可以),则可以用下式表示:
h θ ( X ) = 1 1 + e − X θ h_\theta(X) = \frac{1}{1+e^{-X\theta}} hθ(X)=1+e−Xθ1
此函数的图像表现:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m761ll1v-1585545189355)(D:\Haibo\TnoteBook\images\machine_learn\logistic_reg_pic.JPG)]
我们接下来使用极大似然估计优化逻辑回归的参数
由于逻辑回归是而分类,则有概念分布:
P ( y = 1 ∣ x ; θ ) = h θ ( x ) P ( y = 0 ∣ x ; θ ) = 1 − h θ ( x ) \begin{aligned} &P(y=1|x;\theta) = h_\theta(x)\\ &P(y=0|x;\theta) = 1-h_\theta(x) \end{aligned} P(y=1∣x;θ)=hθ(x)P(y=0∣x;θ)=1−hθ(x)
其联合概率分布为:
P ( y ∣ x ; θ ) = ( h θ ( x ) ) y ( 1 − h θ ( x ) ) 1 − y P(y|x;\theta) = (h_\theta(x))^y(1-h_\theta(x))^{1-y} P(y∣x;θ)=(hθ(x))y(1−hθ(x))1−y
对应的似然函数为:
L ( θ ) = ∏ i = 1 m ( h θ ( x ( i ) ) y ( i ) ( 1 − h θ ( x ( i ) ) ) 1 − y ( i ) L(\theta) =\prod\limits^{m}_{i=1}(h_\theta(x^{(i)})^{y^{(i)}}(1-h_\theta(x^{(i)}))^{1-y^{(i)}} L(θ)=i=1∏m(hθ(x(i))y(i)(1−hθ(x(i)))1−y(i)
对数似然函数为:
J ( θ ) = l o g L ( θ ) = ∑ i = 1 m ( y ( i ) l o g h ( x ( i ) ) + ( 1 − y ( i ) ) ( 1 − h ( x ( i ) ) ) \begin{aligned} J(\theta) &= logL(\theta) \\ &=\sum\limits^{m}_{i=1}(y^{(i)}log h(x^{(i)})+(1-y^{(i)})(1-h(x^{(i)})) \end{aligned} J(θ)=logL(θ)=i=1∑m(y(i)logh(x(i))+(1−y(i))(1−h(x(i)))
对数似然函数求梯度(已省略计算过程):
∂ ∂ θ j J ( θ ) = ( y − h θ ( x ) ) x j \frac{\partial}{\partial\theta_j}J(\theta)=(y-h_\theta(x))x_j ∂θj∂J(θ)=(y−hθ(x))xj
由上面的推导可以得到参数的迭代规则:
θ j = θ j − α ( h θ ( x ) − y ) x j \theta_j = \theta_j-\alpha(h_\theta(x)-y)x_j θj=θj−α(hθ(x)−y)xj
本节我们使用python写出逻辑回归代码优化sklearn带有的癌症数据集
'''
手写Logistic回归代码预测sklearn自带的癌症数据集
'''
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
class LogisticRegression(object):
def __init__(self,learning_rate=0.1,max_iter=1500,stop_error=1e-4):
'''构造函数'''
self.coef = None
self.intercept = None
self.lr = learning_rate
self.mi = max_iter
self.se = stop_error
def sigmoid(self,X):
'''sigmoid函数'''
return 1./(1.+np.exp(-X))
def der_sigmoid(self,X):
'''sigmoid函数导数'''
return self.sigmoid(X)*(1-self.sigmoid(X))
def logistic_model(self,theta,x):
'''模型计算'''
z = np.sum(theta.T*x)
return self.sigmoid(z)
def fit(self,X,Y):
'''使用梯度下降训练LR模型'''
#得到训练数据
self.x_train = X
self.y_train = Y
self.n_features = X.shape[1]
#初始化参数,全为1
self.theta = np.ones(self.n_features)
for step in range(self.mi):
self.theta = self._step_gradient()
loss = self.Loss_CrossEntropy(self.theta,self.x_train,self.y_train)
if step % 20 == 0:
print(f"iteration:{step},loss:{loss},theta:{self.theta}")
if loss<self.se:
print(f"iteration:{step},loss:{loss},theta:{self.theta}")
break
return self.theta
def _cross_entropy(self,y,y_hat):
'''交叉熵计算函数'''
n_samples = y.shape[0]
res = 0.
for i in range(n_samples):
res += (-y[i]*np.log(y_hat[i])-(1-y[i])*np.log(1-y_hat[i]))/n_samples
return res
def Loss_CrossEntropy(self,theta,x,y):
'''损失函数计算'''
y_hat = []
for i in range(x.shape[0]):
y_hat.append(self.logistic_model(theta,x[i]))
return self._cross_entropy(y,y_hat)
def _step_gradient(self):
'''梯度下降'''
M = float(len(self.y_train))
for i in range(self.x_train.shape[0]):
self.theta -= (1. / M)*self.lr*(self.logistic_model(self.theta,self.x_train[i])-self.y_train[i])*self.x_train[i]
return self.theta
def _predict(self,X, theta):
'''预测函数'''
y_hat = []
for i in range(X.shape[0]):
y_hat.append((self.logistic_model(theta, X[i]) > 0.5)*1)
return y_hat
def accuracy(self,theta, X, y):
'''准确率评估函数'''
y_hard = self._predict(X, theta)
count_right = sum(y_hard == y)
return count_right * 1.0 / len(y)
def get_data():
dataset = load_breast_cancer()
#data = pd.DataFrame(data=dataset.data,columns=dataset.feature_names)
#data['cancer'] = [dataset.target_names[t] for t in dataset.target]
X = dataset.data
y = dataset.target
#X_test = dataset.data
#数据归一化
std = X.std(axis=0)
mean = X.mean(axis=0)
X_norm = (X-mean)/std
#为减少截距参数,全优化为theta,在后面加1
ones = np.ones((X.shape[0],1))
X_ones = np.hstack((ones,X_norm))
#分割训练数据和测试数据
X_train,X_test,Y_train,Y_test = train_test_split(X_ones,y,test_size=0.3,random_state=12345)
return [X_train,Y_train,X_test,Y_test]
if __name__ == "__main__":
X_train, Y_train, X_test, Y_test = get_data()
LR = LogisticRegression()
theta = LR.fit(X_train, Y_train)
print(LR.accuracy(theta,X_test,Y_test))
#[out]:
'''iteration:1480,loss:0.04912826826649911,theta:[ 0.66067831 -0.41699501 -0.68479606 -0.46465251 -0.41594285 -0.50296146
-0.09195785 -0.94823898 -1.06558475 -0.20327686 0.69524534 -1.09357091
0.14172414 -0.83429623 -0.61169349 0.50944495 0.85765425 0.21714991
-0.37680249 0.22253374 0.86564795 -0.77599478 -0.93407023 -0.74392032
-0.672051 -0.87079857 -0.01495728 -0.80462611 -0.97748235 -0.5603786
-0.11103954]
0.9766081871345029'''
逻辑回归也会存在过拟合问题,所以我们也需要考虑正则化,正则化包括L1正则化和L2正则化
二元逻辑回归的L1正则化损失函数表达式如下:
J ( θ ) = − Y T ∗ l o g h θ ( X ) − ( E − Y ) T ∗ l o g ( E − h θ ( X ) ) + α ∣ ∣ θ ∣ ∣ 1 J(\theta) = -Y^T*logh_\theta(X)-(E-Y)^T*log(E-h_\theta(X))+\alpha||\theta||_1 J(θ)=−YT∗loghθ(X)−(E−Y)T∗log(E−hθ(X))+α∣∣θ∣∣1
二元逻辑回归的L2正则化损失函数表达式如下:
J ( θ ) = − Y T ∗ l o g h θ ( X ) − ( E − Y ) T ∗ l o g ( E − h θ ( X ) ) + 1 2 α ∣ ∣ θ ∣ ∣ 2 2 J(\theta) = -Y^T*logh_\theta(X)-(E-Y)^T*log(E-h_\theta(X))+\frac{1}{2}\alpha||\theta||_2^2 J(θ)=−YT∗loghθ(X)−(E−Y)T∗log(E−hθ(X))+21α∣∣θ∣∣22
逻辑回归的正则化和线性回归的正则化有相同的性质。我们可以使用sklearn带有的logistic回归进行正则化优化
from sklearn.linear_model import LogisticRegression as SkLr
'''LogisticRegression的参数介绍:
penalty:惩罚项,可以选'l1','l2',对应L1,L2
dual:选择目标函数为原始形式还是对偶形式。
tol:优化算法停止的条件。当迭代前后的函数差值小于等于tol时就停止。
C:正则化系数。其越小,正则化越强。
fit_intercept:选择逻辑回归模型中是否会有常数项b。
class_weight:用于标示分类模型中各种类型的权重
random_state:随机数种子
solver:逻辑回归损失函数的优化方法。
max_iter:优化算法的迭代次数
'''
lr = SkLr(penalty='l1',C=1.0)
lr.fit(X_train, Y_train)
print(lr.score(X_test, Y_test))
逻辑回归可用于以下几个方面:
(1)用于概率预测。用于可能性预测时,得到的结果有可比性。比如根据模型进而预测在不同的自变量情况下,发生某病或某种情况的概率有多大。
(2)用于分类。实际上跟预测有些类似,也是根据模型,判断某人属于某病或属于某种情况的概率有多大,也就是看一下这个人有多大的可能性是属于某病。进行分类时,仅需要设定一个阈值即可,可能性高于阈值是一类,低于阈值是另一类。
(3)寻找危险因素。寻找某一疾病的危险因素等。
(4)仅能用于线性问题。只有当目标和特征是线性关系时,才能用逻辑回归。在应用逻辑回归时注意两点:一是当知道模型是非线性时,不适用逻辑回归;二是当使用逻辑回归时,应注意选择和目标为线性关系的特征。
(5)各特征之间不需要满足条件独立假设,但各个特征的贡献独立计算。