python机器学习——逻辑回归方法
背景与原理:
线性回归可以实现对连续结果的预测,但是现实生活中我们常见的另一种问题是分类问题,尤其是二分类问题,在这种情况下使用线性回归就不太合适了,我们实际上需要计算出的是一个在$[0,1]$之间的概率来告诉我们某样本属于某一类的概率,因此逻辑回归应运而生。
一般的逻辑回归就是在线性回归的基础上嵌套一个逻辑函数,把线性回归的结果转换成概率。
即我们定义$h_{\theta}(X)=P(y=1|X,\theta),1-h_{\theta}(X)=P(y=0|X,\theta)$,那么我们希望最大化预测正确的概率,即我们要最大化:
$\prod_{i=1}^{m}P(y=y_{i}|X_{i},\theta)$
那么也就是:
$\prod_{i=1}^{m}(h_{\theta}(X_{i})^{y_{i}}(1-h_{\theta}(X_{i}))^{1-y_{i}}$
这不好计算,两侧取对数再去取相反数就得到:
$J(\theta)=-\dfrac{1}{m}\sum_{i=1}^{m}y_{i}\log h_{\theta}(X_{i})+(1-y_{i})\log (1-h_{\theta}(X_{i}))$
这样我们只需最小化这个损失函数就可以了,仍然使用梯度下降法确定参数,我们有:
$\hat{\theta_{j}}=\theta_{j}-\alpha \dfrac{\partial J(\theta)}{\partial \theta_{j}}$
对上式求偏导,最后我们得到:
$\hat{\theta_{j}}=\theta_{j}-\alpha \dfrac{1}{m}\sum_{i=1}^{m}(h_{\theta}(X_{i})-y_{i})x_{ij}$
而我们的操作是在线性模型的基础上套上一个逻辑模型,也即我们的参数仍然是线性模型的参数$\theta$:
$z=\theta^{T}X$
在这个基础上套上一个逻辑函数,这里我们选择的是sigmoid函数,即:
$g(z)=\dfrac{1}{1+e^{-z}}$
于是我们最后的函数即为:
$h_{\theta}=\dfrac{1}{1+e^{-\theta^{T}X}}$
代码实现:
import numpy as np import math from scipy import stats import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression def sigmoid(z): return 1/(1+math.exp(-z)) def logical_regression(X,Y,theta,siz,alpha,eps): delt=1 while delt>eps: new_theta=np.zeros(3) for i in range(0,3): r=theta[i] for j in range(0,siz): d=alpha/siz*(sigmoid(theta[0]*X[0][j]+theta[1]*X[1][j]+theta[2]*X[2][j])-Y[j])*X[i][j] r-=d new_theta[i]=r print(new_theta[i]) delta=new_theta-theta delt=delta[0]**2+delta[1]**2+delta[2]**2 theta=new_theta return theta x=np.arange(0.,10.,0.02) y=5-2*x/3+np.random.randn(500) now=0 dataset=[] for i in range(0,500): typ = 0 if 2*x[i]+3*y[i] <= 15: if abs(np.random.randn(1)[0])<2: typ = 1 else: typ = 0 else: if abs(np.random.randn(1)[0]) < 2: typ = 0 else: typ = 1 dataset.append([x[i],y[i],typ]) X=(np.array(dataset)[:,0:2]).T x0=np.ones(500) X=np.vstack([x0,X]) Y=(np.array(dataset)[:,2]) theta=np.array([1,1,1]) my_theta=logical_regression(X,Y,theta,500,1e-2,1e-7) print(my_theta) for i in range(0,500): if Y[i]==1: plt.scatter(X[1,i],X[2,i],c='r') else: plt.scatter(X[1,i],X[2,i],c='b') plt.plot(x,-my_theta[1]/my_theta[2]*x-my_theta[0]/my_theta[2],c='g',linewidth=3) plt.show()
这个代码生成了一组以直线$2x+3y-15=0$为分界的数据,并且加入了一定的随机化,最后通过逻辑回归能够找出这条直线,当然这里的参数选取同样也很重要
小结与优化:
逻辑回归中在一定程度上存在欠拟合的问题,因为很多时候分界线并不是直线而是曲线,此时单纯的线性函数已经无法拟合边界了,一个解决方案是引入更多维度,比如把$[x_{1},x_{2}]$扩展成$[x_{1},x_{2},x_{1}^{2},x_{2}^{2}]$,这样就可以更好拟合二次曲线形成的边界,以此类推等。
而精度问题则可能是由于数据特征有缺失或数据空间太大等,遇到这种情况可以加入正则化的一项使模型缩减系数,有利于提高模型的泛化能力。