不会用LaTeX太痛苦啦QAQ,有时间一定要好好练习一下。4月了,各种事情都多了起来,希望自己能保持学习的热情,保持竞赛的热情
逻辑回归简介
一、逻辑回归的定义
简单来说, 逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等。 注意,这里用的是“可能性”,而非数学上的“概率”,logisitc回归的结果并非数学定义中的概率值,不可以直接当做概率值来用。该结果往往用于和其他特征值加权求和,而非直接相乘。
二、逻辑回归与线性回归的关系
逻辑回归(Logistic Regression)与线性回归(Linear Regression)都是一种广义线性模型(generalized linear model)。逻辑回归假设因变量 y 服从伯努利分布,而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处,去除Sigmoid映射函数的话,逻辑回归算法就是一个线性回归。可以说,逻辑回归是以线性回归为理论支持的,但是逻辑回归通过Sigmoid函数引入了非线性因素,因此可以轻松处理0/1分类问题。
下面通过实际例子来说明二者的区别
- 分类任务:根据余额判断小明是否会去看电影
1.使用线性回归
这里我们建立一个基础框架
y=0时为负样本,则不去看电影
y=1时为正样本,则去看电影
对数据进行训练,很容易能得出一个线性方程(线性运算可看这里:线性方程求法)
对于这组数据我们进行如下总结
总结后发现,欸!好像预测的数据很准确耶,基本都预测对了。别激动,我们尝试增大数据量看看。
可以看出,当数据量增大后,直线的截距变小,预测开始出现错误,这时我们需要一个更准确的方法来处理数据。这时对于这类0/1的二分法就可以使用逻辑回归。
2. 逻辑回归
我们再用大的数据进行预测,如余额为-10和100时代入计算
可以看出即使数据变的很大,但预测结果依旧比较准确,这就是在0/1分类问题上逻辑回归的优势之处
当然,分类任务也会有更复杂的情况,这里我们将e^(-x)中的x换成g(x),而g(x)可以根据你需要的决策边界选择方程,如下图:
- 直线方程
- 曲线方程
当然后面也还可以有x3等等形成更高维度的预测。
对于线性回归方程,我们求解最小化损失函数J:
但对于逻辑回归函数而言,分类,标签,预测结果都是离散数据,使用上面的损失函数无法求取极小值点。对于逻辑回归有另外的最小化损失函数J:
三、实例一
学生各有2门考试成绩,通过数据训练,并预测学生exam1=75,exam2=60时是否能通过考试。比较一阶和二阶边界曲线的准确度
- 代码内容:
import pandas as pd
import numpy as np
data = pd.read_csv('exam_data.csv') #读取数据
data.head()
from matplotlib import pyplot as plt
figl = plt.figure()
mask = data.loc[:,'Pass'] == 1
plt.scatter(data.loc[:,'Exam1'][mask],data.loc[:,'Exam2'][mask])
plt.scatter(data.loc[:,'Exam1'][~mask],data.loc[:,'Exam2'][~mask],marker = '^')
plt.title('Exam1-Exma2')
plt.xlabel('Exam1')
plt.ylabel('Exam2')
plt.show() #画出原数据散点图
X = data.drop(['Pass'],axis=1)
y = data.loc[:,'Pass']
y.head()
X.head()
from sklearn.linear_model import LogisticRegression
LR = LogisticRegression() #建立逻辑回归模型
LR.fit(X,y)
y_predict = LR.predict(X)
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y,y_predict) #看准确度
print(accuracy)
y_test = LR.predict([[75,60]]) #预测新数据
print(y_test)
print('Passed' if y_test == 1 else 'falsed')
theta0 = LR.intercept_
theta1, theta2 = LR.coef_[0][0],LR.coef_[0][1]
X1 = data.loc[:,'Exam1']
X2 = data.loc[:,'Exam2']
X1.head()
X2_new = -(theta0+theta1*X1)/theta2 #求出x1和x2的边界曲线
print(X2_new)
fig4 = plt.figure()
plt.scatter(data.loc[:,'Exam1'][mask],data.loc[:,'Exam2'][mask])
plt.scatter(data.loc[:,'Exam1'][~mask],data.loc[:,'Exam2'][~mask]) #原数据散点图
plt.plot(X1,X2_new) #画出边界曲线
plt.title('Exam1-Exam2')
plt.xlabel('Exam1')
plt.ylabel('Exam2')
plt.show()
- 代码解析:
提示:对于建立模型以及读取数据等已在上一篇文章解释过了,这里主要解析逻辑回归函数的求解
figl = plt.figure()
mask = data.loc[:,'Pass'] == 1
plt.scatter(data.loc[:,'Exam1'][mask],data.loc[:,'Exam2'][mask])
plt.scatter(data.loc[:,'Exam1'][~mask],data.loc[:,'Exam2'][~mask],marker = '^')
plt.title('Exam1-Exma2')
plt.xlabel('Exam1')
plt.ylabel('Exam2')
plt.show() #画出原数据散点图
这里先画出原数据图,mask是检索Pass这一行的值,其作用是用来区分通过考试和不通过考试的数据,下面两个plt.scatter函数里,第一个函数用[mask],意味只画出mask==1的数据,也就是Pass = 1的情况。而第二个[~mask]是只画出 ~mask=1的数据,也就是Pass=0的情况
theta0 = LR.intercept_
theta1, theta2 = LR.coef_[0][0],LR.coef_[0][1]
X1 = data.loc[:,'Exam1']
X2 = data.loc[:,'Exam2']
X1.head()
X2_new = -(theta0+theta1*X1)/theta2 #求出x1和x2的边界曲线
print(X2_new)
我们先求解一阶方程,上面提及一阶方程为g(x)=θ0+θ1X1+θ2X2。当我们建立了Logistic Regression模型后,我们可以读取训练出来的方程系数,intercept_是截距,也就是θ0。coef_[][]则是θ1,θ2…。最后求解出边界曲线。
很容易看出有一些数据的分类还是不精确,这时我们可以建立二阶方程来提高准确度。
data = pd.read_csv('exam_data.csv')
data.head()
X1 = data.loc[:,'Exam1']
X2 = data.loc[:,'Exam2']
y = data.loc[:,'Pass']
X1_2 = X1*X1
X2_2 = X2*X2
X1_X2 = X1*X2
X_new = {'X1':X1, 'X2':X2, 'X1_2':X1_2, 'X2_2':X2_2, 'X1_X2':X1_X2}
X_new = pd.DataFrame(X_new)
print(X_new)
建立了二阶方程,则要引入θ3和θ4,二阶方程的求解可以用求根公式。这里要特别注意一下对x1进行排序,因为这是二阶方程,如果是一阶方程是一条直线,对先后顺序没那么讲究,因为怎么都是连出一条直线。但二阶不一样,二阶是一条曲线,如果不先排序计算,可能出现先算出x大的数据,再算x小的数据,又算x大的数据,来来回回连线会导致线特别乱。只需要排序好一个,另一个是根据排序好的计算出的。
- 不排序结果
theta0 = LR2.intercept_
theta1, theta2, theta3, theta4, theta5 = LR2.coef_[0][0],LR2.coef_[0][1],LR2.coef_[0][2],LR2.coef_[0][3],LR2.coef_[0][4]
X1_new = X1.sort_values() #对x1进行排序
print(X1,X1_new)
a = theta4
b = theta5*X1_new+theta2
c = theta0 + theta1*X1_new + theta3*X1_new*X1_new
X2_new_boundary = (-b+np.sqrt(b*b-4*a*c))/(2*a) #求根公式
mask=y==1
fig5 = plt.figure()
passed = plt.scatter(data.loc[:,'Exam1'][mask],data.loc[:,'Exam2'][mask])
failed = plt.scatter(data.loc[:,'Exam1'][~mask],data.loc[:,'Exam2'][~mask])
plt.plot(X1_new,X2_new_boundary) #画出边界曲线
plt.title('Exam1-Exam2')
plt.xlabel('Exam1')
plt.ylabel('Exam2')
plt.legend((passed,failed),('passed','failed'))
plt.plot(X1_new,X2_new_boundary,'r-')
plt.show()
四、实例二
基于数据检测芯片的好坏,建立二阶逻辑回归模型
代码如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
data = pd.read_csv('chip_test.csv') #读取数据
data.head()
X1 = data.loc[:,'test1']
X2 = data.loc[:,'test2']
y = data.loc[:,'pass']
X1_2 = X1*X1
X2_2 = X2*X2
X1_X2 = X1*X2
X_new = {'X1':X1, 'X2':X2, 'X1_2':X1_2, 'X2_2':X2_2, 'X1_X2':X1_X2}
X_new = pd.DataFrame(X_new)
print(X_new)
from sklearn.linear_model import LogisticRegression
LR2 = LogisticRegression() #建立逻辑回归模型
LR2.fit(X_new,y)
X1_new = X1.sort_values()
X2_boundary1 = []
X2_boundary2 = []
X2_boundary3 = []
X2_boundary4 = []
def f(x):
theta0 = LR2.intercept_
theta1,theta2,theta3,theta4,theta5 = LR2.coef_[0][0],LR2.coef_[0][1],LR2.coef_[0][2],LR2.coef_[0][3],LR2.coef_[0][4]
a = theta4
b = theta5*x+theta2
c = theta0 + theta1*x + theta3*x*x
X2_new_boundary = (-b+np.sqrt(b*b-4*a*c))/(2*a)
X2_new_boundary2 = (-b-np.sqrt(b*b-4*a*c))/(2*a)
return X2_new_boundary,X2_new_boundary2
# X1_range = [-1+x/10000 for x in range(0,20000)] #扩大x的范围
# X1_range = np.array(X1_range)
for x in X1_new:
X2_boundary1.append(f(x)[0])
X2_boundary2.append(f(x)[1])
# for x in X1_range:
# X2_boundary3.append(f(x)[0])
# X2_boundary4.append(f(x)[1])
mask = y == 1
fig5 = plt.figure() #画非完整曲线
passed = plt.scatter(data.loc[:,'test1'][mask], data.loc[:,'test2'][mask])
failed = plt.scatter(data.loc[:,'test1'][~mask], data.loc[:,'test2'][~mask])
plt.title('test1-test2')
plt.xlabel('test1')
plt.ylabel('test2')
plt.legend((passed,failed),('passed','failed'))
plt.plot(X1_new,X2_boundary1)
plt.plot(X1_new,X2_boundary2)
# fig4 = plt.figure() #画完整曲线
# passed = plt.scatter(data.loc[:,'test1'][mask], data.loc[:,'test2'][mask])
# failed = plt.scatter(data.loc[:,'test1'][~mask], data.loc[:,'test2'][~mask])
# plt.title('test1-test2')
# plt.xlabel('test1')
# plt.ylabel('test2')
# plt.legend((passed,failed),('passed','failed'))
# plt.plot(X1_range,X2_boundary3)
# plt.plot(X1_range,X2_boundary4)
- 代码解析:
首先我们可以把数据分类后展示到散点图看看
data = pd.read_csv('chip_test.csv') #读取数据
data.head()
...
...
passed = plt.scatter(data.loc[:,'test1'][mask], data.loc[:,'test2'][mask])
failed = plt.scatter(data.loc[:,'test1'][~mask], data.loc[:,'test2'][~mask])
...
可以看出这次的分类类似一个圆形,立即想到要用二阶方程。
于是我们边开始定义二阶方程和系数
data = pd.read_csv('chip_test.csv') #读取数据
data.head()
X1 = data.loc[:,'test1']
X2 = data.loc[:,'test2']
y = data.loc[:,'pass']
X1_2 = X1*X1
X2_2 = X2*X2
X1_X2 = X1*X2
X_new = {'X1':X1, 'X2':X2, 'X1_2':X1_2, 'X2_2':X2_2, 'X1_X2':X1_X2}
X_new = pd.DataFrame(X_new)
将定义好的系数使用DataFrame合并数据
- pd.DataFrame(X_new)
定义一个函数,对数据依次进行计算求解,每一组数据使用求根公式都会算出2个根,对应到图上就是上下两个边界
def f(x):
theta0 = LR2.intercept_
theta1,theta2,theta3,theta4,theta5 = LR2.coef_[0][0],LR2.coef_[0][1],LR2.coef_[0][2],LR2.coef_[0][3],LR2.coef_[0][4]
a = theta4
b = theta5*x+theta2
c = theta0 + theta1*x + theta3*x*x
X2_new_boundary = (-b+np.sqrt(b*b-4*a*c))/(2*a)
X2_new_boundary2 = (-b-np.sqrt(b*b-4*a*c))/(2*a)
return X2_new_boundary,X2_new_boundary2
将数据依次送入求解
for x in X1_new:
X2_boundary1.append(f(x)[0])
X2_boundary2.append(f(x)[1])
求解完成后,画出曲线和散点图
可以看出数据大致分好类了,但是图像的左右两边有缺口,这是x的数据量比较小的缘故,为了补上缺口,我们可以将x的数据量加大。
X1_range = [-1+x/10000 for x in range(0,20000)] #扩大x的范围
X1_range = np.array(X1_range)
之后与上边一样进行求根计算,画图。即可以得到完整图像。
总结
逻辑回归相比于线性回归有很多相似之处,也是机器学习的重要基础之一,文章是我学习以后的小总结,作为机器学习的小白文章中或有错误的地方,如果大佬看见了还希望可以指出,有什么问题都可以在评论区留言或私信,大家一起进步!