逻辑回归:原理及python实现
Table of Contents
逻辑回归概述
  逻辑斯蒂回归(Logistics Regression,LR)⼜叫逻辑回归或对数⼏率回归(Logit Regression),是⼀种⽤于⼆分类的线性模型。Sigmoid函数
Sigmoid函数
g(z)=
1
1+e−z
其图像如下,在x=0处函数值为0.5,x趋向于⽆穷时,函数值分别趋向0和1。
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')正则化的回归分析
X = np.linspace(-10,10)
y = []
for i in X:
y.append(1/(p(-i)))
plt.plot(X,y)
plt.plot(s(len(X))/2,'--',c='black',linewidth='0.8')
plt.xlabel('z')
plt.ylabel('g(z)')
plt.show()
⼆项逻辑回归
  线性回归⽤于解决回归问题,其输出z=wx T+b是实数,如何将线性回归模型加以改造使其可以⽤于分类呢?⼀个朴素的想法就是对线性回归的结果做⼀个变换
y=f(z)
使得
y∈{−1,1}
其中
z=Xθ
即把线性回归所得的函数值映射到{−1,1}。
  逻辑回归⾸先使⽤Sigmoid函数将线性回归的值映射到区间[0,1],然后将⼤于0.5(可调整)的值映射为类别1,⼩于0.5的值映射为类别-1。g(z)可以理解为分类为正例的概率,越靠近1,被分类为正例的概
率越⼤,在临界值0.5处最容易被误分类。
对数⼏率理解
  上⼀节说到,将g(z)理解为样本被分类为正例的概率。⼀个事件的⼏率(odds)是指该事件发⽣的概率与该事件不发⽣的概率的⽐值。则将
ln
g(z) 1−g(z)
称为对数⼏率(log odds)或logit函数,且将
z=Xθ代⼊sigmoid函数并变形有
ln
g(z)
1−g(z)=Xθ
因此,逻辑回归可以看作对对数⼏率(Logit)进⾏的线性回归,这也是对数⼏率回归名字的由来。
逻辑回归的参数优化及正则化
  上⼀节已经描述了逻辑回归的思路,即将线性回归的结果映射为分类变量,在读这⼀节之前,需要了解⼀下最⼤似然估计的思想。梯度下降法优化参数
最⼤似然法确定损失函数(对数损失)
对于每个样本点(x i,y i),假设y i=1,y i=0的概率分别为
P(y i=1|x i,θ)=gθ(x i)
P(y i=0|x i,θ)=1−gθ(x i)
将其合并为
P(y i|x i,θ)=gθ(x i)y i(1−gθ(x i))1−y i
假设每个样本点独⽴同分布,样本数为n,由最⼤似然法(MLE)构造似然函数得
L(θ)=
n
i=1P(y i|x i,θ)
由于似然函数表⽰的是取得现有样本的概率,应当予以最⼤化,因此,取似然函数的对数的相反数作为损失函数
J(θ)=−lnL(θ)=−
m
i=1(y i ln(gθ(x i))+(1−y i)ln(1−gθ(x i)))
损失函数的优化
对上⼀节的损失函数求导可得
∂J(θ)
∂θ=−
m
i=1(y i
∂gθ(x i)
∂θ
gθ(x i)
−(1−y i)
∂gθ(x i)
∂θ
1−gθ(x i)
)
对于函数
g(z)=
1
1+e−z
g′(z)=dg(z)
dz=
e−z
(1+e−z)2=
1
1+e−z
1+e−z−1
1+e−z=g(z)(1−g(z))
当z=x T iθ时
∂gθ(x i)
∂θ=g
θ(x i)(1−gθ(x i))
dz
dθ=g
θ
(x i)(1−gθ(x i))x i
∂J(θ)∂θ=
m
i=1x i(gθ(x i)−y i)=X(gθ(X)−y)
使⽤梯度下降法
θ=θ−αX T(gθ(X)−y)其中
X=x1
x2
...
x m
,y=
y1
y2
...
y m
正则化
  Logistic Regression也可以使⽤正则化,⽅法同样是在损失函数后增加正则化项。
J(θ)=−
m
i=1[y i ln(hθ(x i))+(1−y i)ln(1−hθ(x i))]+
1
2C||θ||2
2
+α||θ||1
逻辑回归的实现
sklearn实现
  sklearn中LogisticRegression默认使⽤L2正则化,参数penalty可修改正则化⽅式。下⾯是使⽤sklearn⾃带的乳腺癌数据集进⾏逻辑回归训练的代码,下图是不同正则化参数训练所得模型系数,可以看出skleran中正则化项C越⼩,正则化程度越强,参数的变换范围越⼩。sklearn中的C应该是上式中的C的相反数。
# 乳腺癌数据上使⽤Logistic Regression
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
del_selection import train_test_split
cancer = load_breast_cancer()
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,stratify = cancer.target,random_state=42)
for C,maker in zip([0.001,1,100],['o','^','v']):
logistic = LogisticRegression(C = C,penalty='l2',max_iter=100).fit(X_train,y_train)
print('训练精度(C={}):{}'.format(C,logistic.score(X_train,y_train)))
print('测试精度(C={}):{}'.format(C,logistic.score(X_test,y_test)))
plt.f_.T,maker,label = 'C={}'.format(C))
plt.xlabel('Coefficient Index')
plt.ylabel('Coefficient')
plt.legend()
plt.show()
训练精度(C=0.001):0.9530516431924883
测试精度(C=0.001):0.9440559440559441
训练精度(C=1):0.9460093896713615
测试精度(C=1):0.958041958041958
训练精度(C=100):0.9413145539906104
测试精度(C=100):
0.965034965034965
python从零实现
[][]
  下⾯是python从零实现的代码。同样的,先定义了⼀个LogistcReg类,并初始化参数,在fit过程中,未使⽤pytorch的⾃动求导⽽是直接利⽤上⾯推导出的公式来进⾏梯度下降。在类中还定义了,概率、评分、预测等⽅法⽤于输出相关数据。
import numpy as np
import random
import pandas as pd
from sklearn.linear_model import LogisticRegression
class LogisticReg:
def __init__(self, X, y, batch=10, learning_rate=0.01, epoch=3, threshhold_value=0.5,random_seeds=50):
self.random_seeds = random_seeds
self.features = np.insert(X,0,values = np.ones(X.shape[0]),axis=1)
self.labels = y
self.batch = batch
self.learning_rate = learning_rate
self.epoch = epoch
self.theta = al(0, 0.01, size=(self.features.shape[1],1))
self.threshhold_value = threshhold_value
random.seed(self.random_seeds)
def sigmoid(self, features):
return 1/(p(-np.dot(features, self.theta)))
def data_iter(self):
range_list = np.arange(self.features.shape[0])
random.shuffle(range_list)
for i in range(0, len(range_list),self.batch):
batch_indices = range_list[i:min(i+self.batch, len(range_list))]
yield self.features[batch_indices], self.labels[batch_indices].reshape(-1,1)
def fit(self):
for i in range(self.epoch):
for batch_features, batch_labels in self.data_iter():
self.theta -= self.learning_rate * np.dot(np.mat(batch_features).T,
self.sigmoid(batch_features) - batch_labels)
def pred_prob(self, pre_X):
pre_X = np.insert(pre_X,s(pre_X.shape[0]),axis=1)
return self.sigmoid(pre_X)
def predict(self, pre_X):
return self.pred_prob(pre_X) >= self.threshhold_value
def score(self, pre_y, true_y):
return sum(pre_y.flatten() == true_y.flatten())/len(pre_y)
def param(self):
return self.theta.flatten()
def main():
# 导⼊数据
data = pd.read_excel('../bankloan.xls')
display(data.head(3))
X = data.iloc[:, :-1].values
y = data.iloc[:, -1].values
logit = LogisticReg(X, y)
logit.fit()
y_pre = logit.predict(X)
print(f'前五⾏正例概率:\n{logit.pred_prob(X)[:5]}')
print(f'准确率:{logit.score(y_pre,y)}')
print(f'参数向量:{logit.param()}')
skl_LogReg = LogisticRegression(max_iter=1000).fit(X, y)
print(f'sklearn准确率:{skl_LogReg.score(X, y)}')
if __name__ == '__main__':
main()
年龄教育⼯龄地址收⼊负债率信⽤卡负债其他负债违约
0413********.311.359392  5.0086081
12711063117.3  1.362202  4.0007980
2401151455  5.50.856075  2.1689250
前五⾏正例概率:
[[2.71836750e-19]
[2.88481260e-09]
[3.29344356e-61]
[7.11139973e-53]
[1.00000000e+00]]
准确率:0.8042857142857143
参数向量:[-0.08272148 -1.48932592  0.15983636 -6.65078674 -2.42456947  0.43262372  4.64195568  3.20970401  0.85901102]
sklearn准确率:0.8085714285714286
Processing math: 100%

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。