前言
逻辑回归形式简单、模型可解释性好、模型效果也不错,因此在工业界的使用率很高。逻辑回归属于监督学习中的分类模型,主要用于二分类。核心是利用logitistic函数拟合数据的到一件事情发生的概率,然后根据概率进行分类。
逻辑回归原理
logistic函数
逻辑回归的因变量取值只有0和1。假设在n个独立自变量 x0;x1;⋯;xn x 0 ; x 1 ; ⋯ ; x n
记y=1的概率为:
记y=0的概率为:1-p。那么0和1的概率比(优势比 Odds)为
对odds取对数即得logistic变换
令
则
根据线性回归原理
得到p的函数是
逻辑回归的损失函数
损失函数一般有四种:平方损失函数,对数损失函数,HingeLoss0-1损失函数,绝对值损失函数。将极大似然函数去对数以后等同于对数损失函数。
逻辑回归的损失函数是通过最大似然估计推到出来的。为什么不使用平方损失函数呢?是因为如果使用平方损失函数,梯度的更新和sigmod函数本身的梯度是相关的,而sigmod函数本身的梯度不大于0.25,这会导致训练的速度会很慢。
Cost函数:
损失函数求解
逻辑回归的损失函数无法直接求解,一般使用梯度下降的方法来逼近最优解。梯度下降又有批量梯度下降,随机梯度下降和小批量梯度下降三种方式,各有优劣。
-批量梯度下降:能获得全局最优解,缺点是计算量大,参数更新慢。
-随机梯度下降:高方差频繁更新,优点是使得sgd会跳到新的和潜在更好的局部最优解,缺点是使得收敛到局部最优解的过程更加的复杂。
-小批量梯度下降:减少了参数更新的次数,可以达到更加稳定收敛结果,一般在深度学习当中我们采用这种方法。
除了以上三种方法,还有Adma,动量法等优化方法。
过拟合和正则化
假设我们有足够多的特征,并且函数曲线可以对训练数据拟合的很好(损失函数≈0),很可能会导致模型过分复杂,从而泛化能力弱。
过拟合的解决方法:
- 减少特征数量:进行特征筛选
- 使用正则化
其中正则化一般是在损失函数中加入一个和模型复杂度正相关的函数来降低模型复杂度,防止过拟合。
一般在回归中用到的正则化为L1正则化和L2正则化。
加入L2正则化以后的逻辑斯特回归损失函数
其中 λ λ 为正则化系数
逻辑回归的优缺点
优点
- 形式简单,模型的可解释性好。从特征权重能看出特征的重要程度和对结果的影响程度。
- 训练速度快
- 结果易于调整。逻辑回归输出的结果是发生的概率,可以通过调整阀值来改变分类结果。
缺点:
- 对不平衡样本效果不佳,需要对样本做处理。
- 处理非线性数据较麻烦。
注意点:
- 在建模是最好将所有重要的自变量量都包含进来,可以使用逐步筛选的方法来估计。
- 自变量之间应该互不相关,即不存在多重共线。
- 逻辑回归需要较大的样本量,因为在样本量较少时,极大似然估计的效果比最小二乘法要差。
代码部分
1.使用Python画出sigmoid函数的图形
#sigmoid函数
import matplotlib.pyplot as plt
import numpy as np
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
z = np.arange(-7, 7, 0.1)
phi_z = sigmoid(z)
plt.plot(z, phi_z)
plt.axvline(0.0, color='k')
plt.axhspan(0.0, 1.0, facecolor='1.0', alpha=1.0, ls='dotted')
plt.axhline(y=0.5, ls='dotted', color='k')
plt.yticks([0.0, 0.5, 1.0])
plt.ylim(-0.1, 1.1)
plt.xlabel('z')
plt.ylabel('$\phi (z)$')
plt.show()
从图得出,当z为0时结果为0.5,当z为
∞
∞
时结果趋近与1;当z为
−∞
−
∞
时结果趋近与-1.
2.使用sklearn中的LogisticRegression拟合模型。
import pandas as pd
from sklearn import datasets
import numpy as np
iris =datasets.load_iris()
x=iris.data[:,[2,3]]
y=iris.target
from sklearn.cross_validation import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=0)
from sklearn.preprocessing import StandardScaler
sc =StandardScaler()
x_train_std = sc.fit_transform(x_train)
x_test_std =sc.transform(x_test)
from sklearn.linear_model import Perceptron
ppn =Perceptron(n_iter=40,eta0=0.1,random_state=0)
ppn.fit(x_train_std,y_train)
y_pred=ppn.predict(x_test_std)
print((y_test!=y_pred).sum())
from sklearn.metrics import accuracy_score
print(accuracy_score(y_test,y_pred))
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
def plot_decision_regions(x,y,classifier,test_idx=None,resolution=0.02):
markers=('s','x','o','^','v')
colors = ('red','blue','lightgreen','gray','cyan')
cmap =ListedColormap(colors[:len(np.unique(y))])
x1_min,x1_max =x[:,0].min()-1,x[:,0].max()+1
x2_min,x2_max = x[:,0].min()-1,x[:,0].max()+1
xx1,xx2=np.meshgrid(np.arange(x1_min,x1_max,resolution),np.arange(x2_min,x2_max,resolution))
z=classifier.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
z=z.reshape(xx1.shape)
plt.contourf(xx1,xx2,z,alpha=0.4,cmap=cmap)
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
x_test,y_test=x[test_idx,:],y[test_idx]
for idx,cl in enumerate(np.unique(y)):
plt.scatter(x=x[y==cl,0],y=x[y==cl,1],alpha=0.8,c=cmap(idx),marker=markers[idx],label=cl)
if test_idx:
x_test,y_test=x[test_idx,:],y[test_idx]
plt.scatter(x_test[:,0],x_test[:,1],c='',alpha=1.0,
linewidth=1,marker='o',s=55,label='test set')
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(C=1000.0, random_state=0)
lr.fit(X_train_std, y_train)
plot_decision_regions(X_combined_std,y_combined, classifier=lr,test_idx=range(105,150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()
为了能化成二维图形,也没写PCA对变量降维,因此这个例子只选择了2个变量进行建模。同时,Logistic回归是可以做多分类的。
3. 正则化
在调用logistic回归包的时候,需要定义一个参数C,C是正则化系数的导数
1λ
1
λ
。参数penalty可以定义使用L1或者L2,默认为L2。sklearn文档
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None)
df_wine.columns = ['Class label', 'Alcohol',
'Malic acid', 'Ash','Alcalinity of ash', 'Magnesium',
'Total phenols', 'Flavanoids','Nonflavanoid phenols',
'Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']
print('Class labels', np.unique(df_wine['Class label']))
from sklearn.cross_validation import train_test_split
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
from sklearn.preprocessing import StandardScaler
stdsc = StandardScaler()
X_train_std = stdsc.fit_transform(X_train)
X_test_std = stdsc.transform(X_test)
lr = LogisticRegression(penalty='l1', C=0.1)
lr.fit(X_train_std, y_train)
print('Training accuracy:', lr.score(X_train_std, y_train))
#Training accuracy: 0.983870967742
print('Test accuracy:', lr.score(X_test_std, y_test))
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.subplot(111)
colors = ['blue', 'green', 'red', 'cyan',
'magenta', 'yellow', 'black',
'pink', 'lightgreen', 'lightblue',
'gray', 'indigo', 'orange']
weights, params = [], []
for c in np.arange(-4, 6,dtype=float):
lr = LogisticRegression(penalty='l1',
C=10**c,
random_state=0)
lr.fit(X_train_std, y_train)
weights.append(lr.coef_[1])
params.append(10**c)
weights = np.array(weights)
for column, color in zip(range(weights.shape[1]), colors):
plt.plot(params, weights[:, column],
label=df_wine.columns[column+1],
color=color)
plt.axhline(0, color='black', linestyle='--', linewidth=3)
plt.xlim([10**(-5), 10**5])
plt.ylabel('weight coefficient')
plt.xlabel('C')
plt.xscale('log')
plt.legend(loc='upper left')
ax.legend(loc='upper center',
bbox_to_anchor=(1.38, 1.03),
ncol=1, fancybox=True)
plt.show()
上图能看到,特征的系数与正则化系数之间的关系。
λ
λ
越大,C越小,特征系数逐渐减小为0。
λ
λ
越小,C越大,特征系数逐渐增加。
总结
这篇文章主要总结了一下已经了解的逻辑回归知识:逻辑回归的原理,损失函数,正则化,以及代码实现。