您的位置:首页 > 编程语言 > Python开发

逻辑回归与二元分类——含python代码

2018-03-17 15:50 302 查看
  逻辑回归和线性回归的最终目标都是拟合一个线性函数 y=θTxy=θTx,使得我们的预测输出和真实输出之间的差异最小。它们的区别在于损失函数不一样,线性回归的损失函数(MSEMSE)是基于模型误差服从正态分布的假设推导出来的,而逻辑回归的损失函数则是基于极大似然的假设推导出来的,即所有样本结果的后验概率乘积最大。

预测函数

  因为我们利用超平面θTx=0θTx=0来分类,所以当一个样本落在超平面上,我们就可以认为该样本为正样本的概率等于负样本的概率,即:

(y=−1|x)=1" role="presentation">P(y=1|x)P(y=−1|x)=1P(y=1|x)P(y=−1|x)=1

对上式两边取对数:

lnP(y=1|x)P(y=−1|x)=0=θTxlnP(y=1|x)P(y=−1|x)=0=θTx

因为P(y=1|x)+P(y=−1|x)=1P(y=1|x)+P(y=−
1fff7
1|x)=1,所以可以得到:

lnP(y=1|x)1−P(y=1|x)=0=θTxlnP(y=1|x)1−P(y=1|x)=0=θTx

整理可得:

P(y=1|x)=eθTx1+eθTxP(y=1|x)=eθTx1+eθTx

所以P(y=−1|x)=1−P(y=1|x)=11+eθTxP(y=−1|x)=1−P(y=1|x)=11+eθTx,P(y=1|x)P(y=1|x)的分子分母同时除以eθTxeθTx得到11+e−θTx11+e−θTx,这就是sigmoidsigmoid函数的推导过程。其函数曲线如下图所示:



我们可以将其理解为一种非线性变换,目的是把(−∞,+∞)(−∞,+∞)的数值映射到0到1之间,我们将映射结果视为y=1y=1概率。sigmoidsigmoid函数有一个重要的性质:

f′(z)=f(z)(1−f(z))f′(z)=f(z)(1−f(z))

该性质在后面求偏导数的时候会用到。

目标函数

  我们令h(x)=11+e−θTxh(x)=11+e−θTx,由前面的推导可以将h(x)h(x)理解为样本点xx为正样本的概率P(y=1|x)P(y=1|x),即P(y=1|x)=h(x)P(y=1|x)=h(x)。根据极大似然估计的思想,各个样本的结果出现总概率(即后验概率乘积)需要达到最大值,即:

max{∏i=1NP(yi=ki|xi)}(ki=−1,1)max{∏i=1NP(yi=ki|xi)}(ki=−1,1)

因为1−h(x)=h(x)1−h(x)=h(x),所以上式取对数后可以得到:

max{∑i=1NlnP(yi=ki|xi)}===max{∑i=1Nln(h(yixi))}max{∑i=1Nln(11+e−yiθTx)}min{∑i=1Nln(1+e−yiθTx)}(1)(2)(3)(1)max{∑i=1NlnP(yi=ki|xi)}=max{∑i=1Nln(h(yixi))}(2)=max{∑i=1Nln(11+e−yiθTx)}(3)=min{∑i=1Nln(1+e−yiθTx)}

这便是逻辑回归的优化目标函数,它的最终形式表示为:

J=1N∑i=1Nln(1+e−yiθTx)J=1N∑i=1Nln(1+e−yiθTx)

在吴恩达的机器学习课程中,逻辑回归的目标函数形式为:

J=1N∑i=1N{−yiln(h(xi))−(1−yi)ln(1−h(xi))}J=1N∑i=1N{−yiln(h(xi))−(1−yi)ln(1−h(xi))}

是因为它将负样本yiyi表示为0,它和我们推导出来的结果本质是相同的。

梯度下降

  我们推导过程中有一步为:max{∑Ni=1ln(h(yixi))}max{∑i=1Nln(h(yixi))},为了方便利用sigmoid函数的求导性质sigmoid函数的求导性质,我们便把这个式子作为优化目标。要求一个凸函数的最大值,更新公式为:

θ=θ+∂∂θJθ=θ+∂∂θJ

令g(θTx)=h(x)=11+e−θTxg(θTx)=h(x)=11+e−θTx,优化目标可以变换为:J(θ)=max{∑Ni=1ln(g(yiθTxi))}J(θ)=max{∑i=1Nln(g(yiθTxi))},对我们的优化目标进行求导:

∂∂θJ===∑i=1N1g(yiθTxi)⋅∂∂θg(yiθTxi)∑i=1N1g(yiθTxi)⋅g(yiθTxi)(1−g(yiθTxi))⋅∂∂θ(yiθTxi)∑i=1N(1−g(yiθTxi))⋅yixi(4)(5)(6)(4)∂∂θJ=∑i=1N1g(yiθTxi)⋅∂∂θg(yiθTxi)(5)=∑i=1N1g(yiθTxi)⋅g(yiθTxi)(1−g(yiθTxi))⋅∂∂θ(yiθTxi)(6)=∑i=1N(1−g(yiθTxi))⋅yixi

所以梯度下降的更新方程为:

θ=θ+αN∑i=1N(1−g(yiθTxi))⋅yixiθ=θ+αN∑i=1N(1−g(yiθTxi))⋅yixi

代码块

自己用python撸了个逻辑回归,有问题请留言评论区:

import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import scale
from random import random
from numpy import random as nr
from sklearn.model_selection import train_test_split

def sigmoid(x):
return 1/(1+np.exp(-x))

def RandSam(train_data, train_target, sample_num):#随机采样传入训练函数进行迭代
data_num = train_data.shape[0]
if sample_num > data_num:
return -1
else:
data = []
target = []
for i in range(sample_num):
tmp = nr.randint(0,data_num)
data.append(train_data[tmp])
target.append(train_target[tmp])
return np.array(data),np.array(target)

class LogisticClassifier(object):
alpha = 0.01
circle = 1000
l2 = 0.01
weight = np.array([])
def __init__(self, learning_rate, circle_num, L2):
self.alpha = learning_rate
self.circle = circle_num
self.l2 = L2
def fit(self, train_data, train_target):
data_num = train_data.shape[0]
feature_size = train_data.shape[1]
ones = np.ones((data_num,1))
train_data = np.hstack((train_data,ones))
#Y = train_target
self.weight = np.round(np.random.normal(0,1,feature_size+1),2)
for i in range(self.circle):
delta = np.zeros((feature_size+1,))
X,Y = RandSam(train_data, train_target, 50)
for j in range(50):
delta += (1-sigmoid(Y[j]*np.dot(X[j],self.weight)))* \
Y[j]*X[j]
self.weight += self.alpha*delta-self.l2*self.weight

def predict(self, test_data):
data_num = test_data.shape[0]
ones = np.ones((data_num,1))
X = np.hstack((test_data,ones))
return sigmoid(np.dot(X,self.weight))

def evaluate(self, predict_target, test_target):
predict_target[predict_target>=0.5] = 1
predict_target[predict_target<0.5] = -1
return sum(predict_target==test_target)/len(predict_target)

if __name__ == "__main__":
cancer = load_breast_cancer()
xtr, xval, ytr, yval = train_test_split(cancer.data, cancer.target, \
test_size=0.2, random_state=7)
logistics = LogisticClassifier(0.01,2000, 0.01)
logistics.fit(xtr, ytr)
predict = logistics.predict(xval)
print('the accuracy is ',logistics.evaluate(predict, yval),'.')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息