理论知识
Logistic回归算法基于Sigmoid函数,或者说Sigmoid就是逻辑回归函数。
为什么是sigmoid函数:
在logistic regression (LR)中,这个目标是什么呢?最大化条件似然度。考虑一个二值分类问题,训练数据是一堆(特征,标记)组合,(x1,y1), (x2,y2), .... 其中x是特征向量,y是类标记(y=1表示正类,y=0表示反类)。LR首先定义一个条件概率p(y|x;w)。 p(y|x;w)表示给定特征x,类标记y的概率分布,其中w是LR的模型参数(一个超平面)。有了这个条件概率,就可以在训练数据上定义一个似然函数,然后通过最大似然来学习w。这是LR模型的基本原理。
对于大多数(或者说所有)线性分类器,response value(响应值) <w,x> (w和x的内积) 代表了数据x属于正类(y=1)的confidence (置信度)。<w,x>越大,这个数据属于正类的可能性越大;<w,x>越小,属于反类的可能性越大。<w,x>在整个实数范围内取值。现在我们需要用一个函数把<w,x>从实数空间映射到条件概率p(y=1|x,w),并且希望<w,x>越大,p(y=1|x,w)越大;<w,x>越小,p(y=1|x,w)越小(等同于p(y=0|x,w)越大),而sigmoid函数恰好能实现这一功能(参见sigmoid的函数形状):首先,它的值域是(0,1),满足概率的要求;其次,它是一个单调上升函数。最终,p(y=1|x,w)=sigmoid (<w,x>). 综上,LR通过最大化类标记的条件似然度来学习一个线性分类器。为了定义这个条件概率,使用sigmoid 函数将线性分类器的响应值<w,x>映射到一个概率上。sigmoid的值域为(0,1),满足概率的要求;而且是一个单调上升函数,可将较大的<w,x>映射到较大的概率p(y=1|x,w)。sigmoid的这些良好性质恰好能满足LR的需求。
说到底源于sigmoid,或者说exponential family所具有的最佳性质,即maximum entropy的性质。虽然不清楚历史上孰先孰后,但这并不妨碍maximum entropy给了logistic regression一个很好的数学解释。为什么maximum entropy好呢?entropy翻译过来就是熵,所以maximum entropy也就是最大熵。熵原本是information theory中的概念,用在概率分布上可以表示这个分布中所包含的不确定度,熵越大不确定度越大。所以大家可以想象到,均匀分布熵最大,因为基本新数据是任何值的概率都均等。而我们现在关心的是,给定某些假设之后,熵最大的分布。也就是说这个分布应该在满足我假设的前提下越均匀越好。比如大家熟知的正态分布,正是假设已知mean和variance后熵最大的分布。回过来看logistic regression,这里假设了什么呢?首先,我们在建模预测 Y|X,并认为 Y|X 服从bernoulli distribution,所以我们只需要知道 P(Y|X);其次我们需要一个线性模型,所以 P(Y|X) = f(wx)。接下来我们就只需要知道 f 是什么就行了。而我们可以通过最大熵原则推出的这个 f,就是sigmoid。其实前面也有人剧透了bernoulli的exponential family形式,也即是 1/ (1 + e^-z)
ps:由于指数家族和广义线性模型公式推出来的就是sigmoid函数
最大嫡原理
image.png广义线性模型
image.pngimage.png
逻辑回归原理
其中涉及的数学原理和步骤如下:
(1)需要一个合适的分类函数来实现分类【单位阶跃函数、Sigmoid函数】
(2)损失函数(Cost函数)来表示预测值(h(x)h(x))与实际值(yy)的偏差(h−yh−y),要使得回归最佳拟合,那么偏差要尽可能小(偏差求和或取均值)。
(3)记J(ω)J(ω)表示回归系数为ωω时的偏差,那么求最佳回归参数ωω就转换成了求J(ω)J(ω)的最小值。【梯度下降法】
所以,接下来就围绕这几个步骤进行展开。
损失函数
image.pngimage.png
梯度上升法
python实现#
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
def load_data(path, header):
marks_df = pd.read_csv(path, header=header)
return marks_df
if __name__ == "__main__":
# load the data from the file
data = load_data("data/marks.txt", None)
# X = feature values, all the columns except the last column
X = data.iloc[:, :-1]
# y = target values, last column of the data frame
y = data.iloc[:, -1]
# filter out the applicants that got admitted
admitted = data.loc[y == 1]
# filter out the applicants that din't get admission
not_admitted = data.loc[y == 0]
# plots
plt.scatter(admitted.iloc[:, 0], admitted.iloc[:, 1], s=10, label='Admitted')
plt.scatter(not_admitted.iloc[:, 0], not_admitted.iloc[:, 1], s=10, label='Not Admitted')
plt.legend()
plt.show()
X = np.c_[np.ones((X.shape[0], 1)), X]
y = y[:, np.newaxis]
theta = np.zeros((X.shape[1], 1))
def sigmoid(x):
# Activation function used to map any real value between 0 and 1
return 1 / (1 + np.exp(-x))
def net_input(theta, x):
# Computes the weighted sum of inputs
return np.dot(x, theta)
def probability(theta, x):
# Returns the probability after passing through sigmoid
return sigmoid(net_input(theta, x))
def cost_function(self, theta, x, y):
# Computes the cost function for all the training samples
m = x.shape[0]
total_cost = -(1 / m) * np.sum(
y * np.log(probability(theta, x)) + (1 - y) * np.log(
1 - probability(theta, x)))
return total_cost
def gradient(self, theta, x, y):
# Computes the gradient of the cost function at the point theta
m = x.shape[0]
return (1 / m) * np.dot(x.T, sigmoid(net_input(theta, x)) - y)
def fit(self, x, y, theta):
opt_weights = fmin_tnc(func=cost_function, x0=theta,
fprime=gradient,args=(x, y.flatten()))
return opt_weights[0]
parameters = fit(X, y, theta)
x_values = [np.min(X[:, 1] - 5), np.max(X[:, 2] + 5)]
y_values = - (parameters[0] + np.dot(parameters[1], x_values)) / parameters[2]
plt.plot(x_values, y_values, label='Decision Boundary')
plt.xlabel('Marks in 1st Exam')
plt.ylabel('Marks in 2nd Exam')
plt.legend()
plt.show()
def predict(self, x):
theta = parameters[:, np.newaxis]
return probability(theta, x)
def accuracy(self, x, actual_classes, probab_threshold=0.5):
predicted_classes = (predict(x) >=
probab_threshold).astype(int)
predicted_classes = predicted_classes.flatten()
accuracy = np.mean(predicted_classes == actual_classes)
return accuracy * 100
accuracy(X, y.flatten())
算法优化#
把梯度下降改成随机梯度下降等,暂时pass,如果后面遇到再补习
优缺点
优点:
1、实现简单;
2、分类时计算量非常小,速度很快,存储资源低;
缺点:
1、容易欠拟合,一般准确度不太高
2、只能处理两分类问题(在此基础上衍生出来的softmax可以用于多分类),且必须线性可分;
reference:
https://zhuanlan.zhihu.com/p/24967776
https://www.zhihu.com/question/35322351
https://blog.csdn.net/lc013/article/details/55002463
https://blog.csdn.net/moxigandashu/article/details/72779856
https://towardsdatascience.com/building-a-logistic-regression-in-python-301d27367c24
网友评论