在之前的的线性回归中,我们尝试用一个公式来描述数据的分布情况,这个公式可以概括如下:
首先,逻辑回归不是一个回归模型,而是一个分类模型。这个分类模型的基本形态用来判断被预测数据属于0分类还是1分类。换言之,我们的数据标签只用两个,0和1。
在这用情况下,使用单纯的线性回归就会面临一个问题。根据特征预算得到的标签如何转换成0/1标签。
在数学上,使用一个sigmod函数对线性回归输出的标签进行再次运算,将线性回归的结果映射到一个(0,1)的区间内,然后,我们认为运算结果>0.5的数据标签为1,<0.5的数据标签为0(当然,0.5并不是绝对的,可以根据具体的需要进行调整。) 使用的sigmod函数如下:
现在,我们逻辑回归的基本构成就已经说完了。然而在线性回归中,有一个很重要的问题没有解决,如何才能得到 y=wwXX+b y = w w X X + b 中的参数呢? 在统计学和计算机中采取的不太相同的方式。
首先是统计学,一般采用最小二乘法对参数进行估计,公式为 ww=(XXTXX)−1XXy w w = ( X X T X X ) − 1 X X y 。公式的具体推导过程略去,请参考维基百科。
在计算机中,一般采用梯度下降法(也有更优化的随机梯度下降法,会在后续的内容中尝试进行解释。)
随机梯度下降法中,首先定义了一个损失函数——一个用来衡量预测结果和样本之间区别程度的函数,这个函数的定义一般上要求有两点(这两个要求是我的理解,如果有误,请留言指正,谢谢)。
在这里,我简单的定义了损失函数为 1/2(y−y^)2 1 / 2 ( y − y ^ ) 2 当我们有了损失函数之后,不妨思考一个问题,如果参数能够使得损失最小,就可以认为参数最优了,那么如何使得损失最小?我们怎么判断出参数最小了呢?
我们首先对损失函数进行求导,根据导函数,可以确定函数的梯度(可以理解为在欧式空间内函数值变化最快的方向),在函数梯度方向上,小小的进行一次前进(由学习速率决定,即learning_rate),得到新的参数w后,重新计算函数损失,不断迭代,最终可以得到损失为0的参数。这时,可以认为函数的损失最小了。注意,由于函数不一定只有一个极值点,所以,参数不一定为最优解。
在这里贴上一个简单的逻辑回归实现的代码:
# -*- coding:utf-8 -*-
import numpy as np
class LogisticRegression:
def __init__(self, n_iterations=3000, learning_rate=0.00004, regularization=None, gradient=True, alpha=0.5):
'''
:param n_iterations: 迭代次数
:param learning_rate: 学习速率
:param regularization: 是否使用正则
:param gradient: 是否使用梯度下降
'''
self.n_iterations = n_iterations
self.learning_rate = learning_rate
self.gradient = gradient
self.train_errors = []
if regularization == None:
self.regularization = lambda x: 0
self.regularization.grad = lambda x: 0
else:
self.regularization = regularization
self.alpha = alpha
# sigmod函数
def sigmoid(self, X):
return 1 / (1 + np.exp(X.dot(self.w)))
# 初始化w值
def __initialize_weights(self, n_features):
limit = 1 / np.sqrt(n_features)
w = np.random.uniform(-limit, limit, (n_features, 1))
b = 0
self.w = np.insert(w, 0, b, axis=0)
# print(self.w.shape)
# 使用梯度下降法或最小二乘法进行参数估计
def fit(self, X, y):
'''
:param X: 训练数据的自变量(特征)
:param y: 训练数据的因变量(标签)
:return: self
'''
m_samples, n_features = X.shape
self.__initialize_weights(n_features)
X = np.insert(X, 0, 1, axis=1)
y = np.reshape(y, (m_samples, 1))
self.train_errors = []
if self.gradient == True:
for i in range(self.n_iterations):
y_pred = X.dot(self.w)
loss = np.mean(0.5 * (y_pred - y) ** 2) + self.regularization(self.w)
self.train_errors.append(loss)
a_grad = X.T.dot(y_pred - y) + self.regularization.grad(self.w)
self.w = self.w - self.learning_rate * a_grad
else:
X = np.matrix(X)
y = np.matrix(y)
_coef = X.T.dot(X)
_coef = _coef.I
_coef = _coef.dot(X.T)
self.w = _coef.dot(y)
def predict(self, X):
X = np.insert(X, 0, 1, axis=1)
y_pred = X.dot(self.w)
y_pred[y_pred >= self.alpha] = 1
y_pred[y_pred < self.alpha] = 0
return y_pred
@property
def error(self):
return self.train_errors
完整代码见github
https://github.com/xudalin0609/dataAnalysisModels/blob/master/LogisticRegression.py