机器学习之深入逻辑回归

逻辑回归

为什么需要逻辑回归

  • 线性回归是不能解决分类问题的。线性回归实际上做了三个假设
  • 1.因变量Yi和自变量Xi之间呈线性相关
  • 2.自变量Xi与干扰项相互独立
  • 3.没被线性模型捕捉到的随机因素服务正态分布
  • 理论上来说,任何数据放在模型里面都会得到相应的参数估计,进而通过模型对数据进行预测。但是这并一定能保证模型效果,有时会得到”错且无用”的模型,因此建模的过程中需要不断提出假设和检验假设

什么是线性回归

  • 逻辑回归假设数据服从伯努利分布,通过极大似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类目的。

  • 原理是将样本的特征和样本发生的概率联系起来,即,预测的是样本发生的概率是多少。由于概率是一个数,因此被叫作”逻辑回归”

  • 逻辑回归是一个非线性模型,但是其背后是以线性回归为理论支撑,其提出一个与线性模型长相类似但不同的新公式: 假设特征X所对应的y值是在质数上裱花,那么久可以将结果y值取对数,作为其线性模型逼近的目标。也就是所谓的”对数线性回归”

  • 对数线性回归公式中,可以改写如下形式。实际上是求输入空间X到输出空间y的非线性函数映射。对数函数的作用是将线性回归模型的预测值与真实标记联系起来

  • 一般意义上的单调可微的“联系函数”:g(a) = ln(a).其本质就是给原来线性变换加上一个非线性变换(或者说映射),使得模拟的函数有非线性的属性,但本质上调参还是线性的,主体是内部线性的调参。那么对于解决分类问题的逻辑回归来说,我们需要找到一个“联系函数”,将线性回归模型的预测值与真实标记联系起来。将“概率”转换为“分类”的工具是“阶段函数”:

  • 对于上述阶梯函数不连续,不能作为“联系函数”g,因此使用对数几率函数来在一定程度上近似阶梯函数,将线性回归模型的预测值转换为分类所对应的概率(如下)

  • 如果另y为整理,1-y为负例,所谓的“几率”就是二者的比值y/(1-y) ,几率反映了样本X为整理的相对可能性(如y值分别预测为0,1的概率为0.4,0.6,若阈值设置为0.5,那么y就被预测为1)。对数几率即对几率取对数ln(y/(1-y)),对数几率实际上就是sigmod函数,将线性模型转换为分类。如图,可以看出,sigmod实际上就是用线性回归模型的预测结果取逼近真实值的对数几率,因此逻辑回归也被成为”对数几率回归”

  • 之所以用sigmod做假设函数,因为线性回归模型预测值为实数,而样本标记为(0,1),我们需要将二分类任务的真实性标记y与线性回归模型的预测值联系起来,也就是找到了广义线性模型中的联系函数。如果选择单位阶跃函数的话,它是不连续的不可微,而选择sigmod函数,他是连续的,而且能够将z转换为一个接近0或1的值

逻辑回归代码

  • 原生实现
    import  numpy as np
    \#计算回归函数的输出指标,根据分类问题对输出指标进行修改
    from  sklearn.metrics import  accuracy_score
    
    class LogisticRegressionWithSigmod:
    	def __init__(self):
    		"""
    		初始化类
    		"""
    		# 斜率
    		self.coef_ = None
    		self.intercept_ = None
    		self._theta = None
    
    	def _sigmoid(self, t):
    		"""
    		定义sigmod方法  1/(1+ e^(-t))
    		:param t: 线性模型 t
    		:return: sigmod表达式
    		"""
    		return 1./(1. + np.exp(-t))
    
    	def fit(self,X_train, y_train, eta = 0.01, n_iters=1e4):
    		"""
    		fit方法,内部使用梯度下降训练法 来训练 Logitstic Regression
    		参数:训练集特征集 X_train, 标签集y_train
    		输出:训练好的模型
    		:param X_train:
    		:param y_train:
    		:param eta:
    		:param n_iters:
    		:return:
    		"""
    		# 检查训练集数量和标签集数量相等
    		assert X_train.shape[0] == y_train.shape[0], "the size of X_train must be equal to the size of y_train"
    
    		def J(theta,X_b,y):
    			"""
    			定义逻辑回归的损失函数
    			:param theta: 参数theta
    			:param X_b: 构造好的矩阵X_b
    			:param y: 标签y
    			:return: 损失表达式
    			"""
    
    			# 定义逻辑回归的模型 y_hat
    			y_hat = self._sigmoid(X_b.dot(theta))
    			try:
    				# 选择损失函数的表达式
    				return - np.sum(y*np.log(y_hat)+(1-y)*np.log(y-y_hat))/len(y)
    			except:
    				return float('inf')
    
    			def dj(theta,X_b,y):
    				"""
    				损失函数的导数计算
    				:param theta: 参数theta
    				:param X_b: 构造好的矩阵X_b
    				:param y: 标签y
    				:return: 计算好的表达式
    				"""
    				return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y)
    
    			def gradient_descent(X_b, y, initial_theta, n_iters=1e4, epsilon=1e-8):
    				def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
    					theta = initial_theta
    					cur_iter = 0
    					while cur_iter < n_iters:
    						gradient = dJ(theta, X_b, y)
    						last_theta = theta
    						theta = theta - eta * gradient
    						if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
    							break
    						cur_iter += 1
    					return theta
    
    			X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
    			initial_theta = np.zeros(X_b.shape[1])
    			# 梯度下降的结果求出参数heta
    			self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)
    			# 第一个参数为截距
    			self.intercept_ = self._theta[0]
    			# 其他参数为各特征的系数
    			self.coef_ = self._theta[1:]
    			return self
    
    			"""
    			逻辑回归是根据概率进行分类的,因此先预测概率
    			参数:输入空间X_predict
    			输出:结果概率向量
    			"""
    
    			def predict_proba(self, X_predict):
    				"""给定待预测数据集X_predict,返回表示X_predict的结果概率向量"""
    				assert self.intercept_ is not None and self.coef_ is not None, \
    					"must fit before predict!"
    				assert X_predict.shape[1] == len(self.coef_), \
    					"the feature number of X_predict must be equal to X_train"
    
    				X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
    				# 将梯度下降得到的参数theta带入逻辑回归的表达式中
    				return self._sigmoid(X_b.dot(self._theta))
    
    			"""
    			使用X_predict的结果概率向量,将其转换为分类
    			参数:输入空间X_predict
    			输出:分类结果
    			"""
    
    			def predict(self, X_predict):
    				"""给定待预测数据集X_predict,返回表示X_predict的结果向量"""
    				assert self.intercept_ is not None and self.coef_ is not None, \
    					"must fit before predict!"
    				assert X_predict.shape[1] == len(self.coef_), \
    					"the feature number of X_predict must be equal to X_train"
    				# 得到概率
    				proba = self.predict_proba(X_predict)
    				# 判断概率是否大于0.5,然后将布尔表达式得到的向量,强转为int类型,即为0-1向量
    				return np.array(proba >= 0.5, dtype='int')
    
    			def score(self, X_test, y_test):
    				"""根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""
    
    				y_predict = self.predict(X_test)
    				return accuracy_score(y_test, y_predict)
    
    			def __repr__(self):
    				return "LogisticRegression()"
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值