吴恩达逻辑回归总结
数据集地址:
课后习题题目
1、学生录取
在训练的初始阶段,我们将要构建一个逻辑回归模型来预测,某个学生是否被大学录取。
设想你是大学相关部分的管理者,想通过申请学生两次测试的评分,来决定他们是否被录取。
现在你拥有之前申请学生的可以用于训练逻辑回归的训练样本集。对于每一个训练样本,你有他们两次测试的评分和最后是被录取的结果。
2、线性不可分案例:假设你是工厂的生产主管,你有一些芯片在两次测试中的测试结果,测试结果决定是否芯片要被接受或抛弃。你有一些历史数据,帮助你构建一个逻辑回归模型。。
一、吴恩达逻辑回归理解
1.逻辑回归
逻辑回归主要是主要是用来处理分类任务,分类又包含二分类(Binary classification)和多分类(Multi-classclassification),逻辑回归主要用来处理二分类问题,在二分类分问题中又分为线性可分类问题和线性不可分类问题。
2.线性可分
2.1 假设函数
在线性回归模型问题中,我们只能预测连续的值,对于分类问题,我们需要输出0或1,即当假设函数大于等于0.5时,预测y=1,当假设函数小于0.5时,预测y=0。当假设函数超过1时,再用0.5作为阈值来预测目标函数便不恰当。为了使得假设函数的值可以超越[0,1]的范围,且该模型的输出变量始终处于[0,1]之间,引入逻辑函数g(Logistics Function)是一个常用的逻辑函数为S型函数(Sigmoid Function)。
假设函数(Hypothesis):
h
θ
(
x
)
=
g
(
X
θ
)
\\{h_\theta }(x) = g(X\theta )\,
hθ(x)=g(Xθ)
即:
h
θ
(
x
)
=
g
(
θ
0
+
θ
1
x
1
+
θ
2
x
2
)
\\{h_\theta }(x) = g({\theta _0} + {\theta _1}{x_1} + {\theta _2}{x_2} )\,
hθ(x)=g(θ0+θ1x1+θ2x2)
引入逻辑函数(Sigmoid函数):
g
(
z
)
=
1
1
+
e
−
z
\\g(z) = \frac{{\rm{1}}}{{{\rm{1 + }}{e^{ - z}}}}\,
g(z)=1+e−z1
2.2 代价函数(Cost Function)
线性回归的代价函数为:
J
(
θ
)
=
1
2
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
\\J(\theta ) = \frac{{\rm{1}}}{{{\rm{2m}}}}\sum\limits_{i = 1}^m {{{({h_\theta }({x^{(i)}}) - {y^{(i)}})}^2}} \,
J(θ)=2m1i=1∑m(hθ(x(i))−y(i))2
重新定义逻辑回归的代价函数:
J
(
θ
)
=
1
m
∑
i
=
1
m
C
o
s
t
(
h
θ
(
x
(
i
)
)
,
y
(
i
)
)
\\J(\theta ) = \frac{{\rm{1}}}{{\rm{m}}}\sum\limits_{i = 1}^m {Cost({h_\theta }({x^{(i)}}),} {y^{(i)}})\,
J(θ)=m1i=1∑mCost(hθ(x(i)),y(i))
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
{
−
log
(
h
θ
(
x
)
)
i
f
y
=
1
−
log
(
1
−
h
θ
(
x
)
)
i
f
y
=
0
\\Cost({h_\theta }({x}),{y}) = \left\{ \begin{array}{l}- \log ({h_\theta }(x))&if&y=1\\- \log (1 - {h_\theta }(x)) &if&y=0 \end{array} \right.\,
Cost(hθ(x),y)={−log(hθ(x))−log(1−hθ(x))ifify=1y=0
这个式子可以合并成:
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
−
y
×
log
(
h
θ
(
x
)
)
−
(
1
−
y
)
×
log
(
1
−
h
θ
(
x
)
)
\\Cost({h_\theta }(x),y) = - y{\rm{ \times }}\log ({h_\theta }(x)) - (1 - y){\rm{ \times }}\log (1 - {h_\theta }(x))\,
Cost(hθ(x),y)=−y×log(hθ(x))−(1−y)×log(1−hθ(x))
即,逻辑回归的代价函数:
J
(
θ
)
=
−
1
m
∑
i
=
1
m
[
y
(
i
)
log
(
h
θ
(
x
(
i
)
)
)
+
(
1
−
y
(
i
)
)
log
(
1
−
h
θ
(
x
(
i
)
)
)
]
\\J(\theta ) = - \frac{{\rm{1}}}{{\rm{m}}}\sum\limits_{i = 1}^m {[{y^{(i)}}\log ({h_\theta }({x^{(i)}}))} + (1 - {y^{(i)}})\log (1 - {h_\theta }({x^{(i)}}))]\,
J(θ)=−m1i=1∑m[y(i)log(hθ(x(i)))+(1−y(i))log(1−hθ(x(i)))]
注
:
h
θ
(
x
(
i
)
)
:
预
测
值
,
y
(
i
)
:
真
实
值
\\注:{h_\theta }({x^{(i)}})\,:预测值,{y^{(i)}}\,:真实值
注:hθ(x(i)):预测值,y(i):真实值
2.3 梯度下降(Gradient Descent)
根据上面的代价函数,为了拟合出参数,需要找出尽量让J(θ)取得最小值的参数θ。
如果给出一个新的样本,假如某个特征x,我们可以通过拟合训练样本的参数θ,来输出对假设的预测,这个输出实质上就是这个概率值:p(y=1|x;θ),就是在X=x,Θ=θ时,y=1的概率,说白了就是个条件概率。
梯度:
∂
J
(
θ
)
∂
θ
j
=
1
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
\\\frac{{\partial J(\theta )}}{{\partial {\theta _j}}} = \frac{{\rm{1}}}{{\rm{m}}}\sum\limits_{i = 1}^m {({h_\theta }({x^{(i)}}) - {y^{(i)}})} x_j^{(i)}\,
∂θj∂J(θ)=m1i=1∑m(hθ(x(i))−y(i))xj(i)
虽然这里的梯度和线性回归的梯度很像,但这里的假设函数却是不一样的。
2.4 决策边界
所谓决策边界即为Xθ = 0的一条直线,即:
θ
0
+
θ
1
x
1
+
θ
2
x
2
=
0
\\{\theta _0} + {\theta _1}{x_1} + {\theta _2}{x_2} = 0\,
θ0+θ1x1+θ2x2=0
即:
x
2
=
−
θ
0
θ
2
−
θ
1
θ
2
x
1
\\{x_2} = - \frac{{{\theta _0}}}{{{\theta _2}}} - \frac{{{\theta _1}}}{{{\theta _2}}}{x_1}\,
x2=−θ2θ0−θ2θ1x1
说白了,前面的一系列操作就是为了求出θ0、θ1、θ2。
3. 线性不可分
上面的图片可以看出,这个数据集不能像之前一样使用直线将两部分分割。而逻辑回归只适用于线性的分割,所以,这个数据集不适合直接使用逻辑回归。
3.1 特征映射
特征映射用于制造非线性回归复杂属性。通过循环将原本的输入值矩阵扩展成多项展开式的形式。这样做能够获得不同于线性回归的更加复杂、合理的目标函数。
二、代码演示
1.引入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as pltt
import scipy.optimize as opt
1、线性可分代码演示
1.读入数据
path = 'K:\python\吴恩达机器学习python作业代码\code\ex2-logistic regression/ex2data1.txt'
data1 = pd.read_csv(path,header=None,names=['Exam 1', 'Exam 2', 'Admitted'])
# 读取数据集data1
# print("查看数据集data1:",data1)
2.数据可视化
数据预处理:(将通过的和未通过的分开)
positive = data1[data1['Admitted'].isin([1])] # 将Admitted为1(即录取)的提取出来
negative = data1[data1['Admitted'].isin([0])] # 将Admitted为0(即未录取)的提取出来
# print('查看positive',positive)
# print('查看negative',negative)
数据可视化
fig, ax = plt.subplots(figsize=(9,6)) # 设置图片尺寸
ax.scatter(positive['Exam 1'], positive['Exam 2'],
s = 25,c = 'b',marker = 'o',label = 'Admitted') # 绘制positive的图像,s表示点的尺寸
ax.scatter(negative['Exam 1'], negative['Exam 2'],
s = 25,c = 'r',marker = 'x',label = 'Not Admitted') # 绘制negative的图像
ax.set_title("Datainit", fontsize=14) # 图名字,字号14
ax.set_xlabel("Exam 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Exam 2 Score", fontsize=10) # y轴标签,字号10
ax.tick_params(axis = 'both', which = 'major', labelsize = 10)
ax.legend(loc='lower right')
plt.show()
3.构造数据集(数据预处理)
def get_Xy(data1):
data1.insert(0, 'Ones', 1) # 在数据第一列插入1
cols = data1.shape[1] # 列数
X = data1.iloc[:, :cols - 1] # X是data1里的除最后列
y = data1.iloc[:, cols - 1:cols] # y是data1最后一列
theta = np.zeros(3) # 初始化一个一行三列的0矩阵
theta = theta.reshape(1,3) # 将0矩阵转化为一个行3列的矩阵
X = np.array(X.values)
y = np.array(y.values)
return X,y,theta
X,y,theta = get_Xy(data1) # 获取X,y,theta的数据集
print(X.shape,y.shape,theta.shape) # 查看X,y,theta的维度
维度:(100, 3) (100, 1) (1, 3)
4.构造sigmoid函数
def sigmoid(z):
return 1 / (1 + np.exp(-z)) # 定义igmoid Function
sigmoid函数可视化:
fig, ax = plt.subplots(figsize=(9,6)) # 设置图片尺寸
x1 = np.arange(-10, 10, 0.1)
ax.plot(x1, sigmoid(x1), c='r',label = 'g(z)') # 绘制g(z)的图像
ax.set_title("Sigmoid Function", fontsize=14) # 图名字,字号14
ax.set_xlabel("z", fontsize=10) # x轴标签,字号10
ax.set_ylabel("g(z)", fontsize=10) # y轴标签,字号10
ax.tick_params(axis = 'both', which = 'major', labelsize = 10) # 定义主参数
ax.legend(loc='lower right')
plt.show()
5.代价函数CostFunction(损失函数)
def costFunction(theta, X, y):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
return np.sum(first - second) / (len(X))
cost_init = costFunction(theta, X, y)
print(cost_init)
0.6931471805599453
6.梯度下降
实现梯度计算的函数(并没有更新θ)
def gradient(theta, X, y):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
parameters = int(theta.ravel().shape[1])
grad = np.zeros(parameters)
error = sigmoid(X * theta.T) - y
for i in range(parameters):
term = np.multiply(error, X[:, i])
grad[i] = np.sum(term) / len(X)
return grad
参数更新(科学计算法):
在此前的线性回归中,自己写代码实现的梯度下降。当时写了一个代价函数、计算了他的梯度,然后对他执行了梯度下降的步骤。这里,我们调用一个已有的库。这就是说,我们不用自己定义迭代次数和步长,功能会直接告诉我们最优解。Python中我们可以用scipy.optimize.fmin_tnc可以帮我们作这样的事。
result = opt.fmin_tnc(func=costFunction, x0=theta, fprime=gradient, args=(X, y))
print(result)
(array([-25.16131872, 0.20623159, 0.20147149]), 36, 0)
cost_init1 = costFunction(result[0], X, y)
print(cost_init1)
0.20349770158947425
7.决策边界
fig, ax = plt.subplots(figsize=(9,6))
ax.set_title("Decision Boundary", fontsize=14) # 图名字,字号14
ax.set_xlabel("Exam 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Exam 2 Score", fontsize=10) # y轴标签,字号10
plotting_x1 = np.linspace(30, 100, 100) # 定义x轴参数,即自变量
plotting_x2 = (- result[0][0] - result[0][1] * plotting_x1) / result[0][2] # 建立函数关系
ax.plot(plotting_x1, plotting_x2,c = 'g', label='Prediction')
ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted')
ax.legend(loc='lower left')
plt.show()
8.评价逻辑回归模型
8.1、评价方法1
当exam1 = 45,exam2 = 85时,求其录取的概率P1:
def hfunc1(theta, X):
return sigmoid(np.dot(theta.T, X))
P1 = hfunc1(result[0],[1,45,85])
print('P1=',P1)
P1= 0.776290625526598
8.1、评价方法2
这种评价θ的方法是看模型在训练集上的正确率怎样。写一个predict的函数,给出数据以及参数后,会返回“1”或者“0”。然后再把这个predict函数用于训练集上,看准确率怎样。
定义预测函数:
def predict(theta, X):
probability = sigmoid(X * theta.T)
return [1 if x >= 0.5 else 0 for x in probability]
统计预测正确率:
theta_min = np.matrix(result[0])
predictions = predict(theta_min, X)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
P = '{0}%'.format(accuracy)
print ('准确率P=',P)
准确率P = 89%
2、线性不可分代码演示
1.读入数据
path = 'K:\python\吴恩达机器学习python作业代码\code\ex2-logistic regression/ex2data2.txt'
data2 = pd.read_csv(path, header=None, names=['Test 1', 'Test 2', 'Accepted'])
# print("查看数据集data2:",data2)
2.数据可视化
数据预处理:(将通过的和未通过的分开)
positive2 = data2[data2['Admitted'].isin([1])] # 将Admitted为1(即录取)的提取出来
negative2 = data2[data2['Admitted'].isin([0])] # 将Admitted为0(即未录取)的提取出来
# print('查看positive',positive)
# print('查看negative',negative)
数据可视化
fig, ax = plt.subplots(figsize=(9,6)) # 设置图片尺寸
ax.scatter(positive2['Test 1'], positive2['Test 2'],
s = 25,c = 'b',marker = 'o',label = 'Admitted') # 绘制positive的图像,s表示点的尺寸
ax.scatter(negative2['Test 1'], negative2['Test 2'],
s = 25,c = 'r',marker = 'x',label = 'Not Admitted') # 绘制negative的图像
ax.set_title("Datainit", fontsize=14) # 图名字,字号14
ax.set_xlabel("Test 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Test 2 Score", fontsize=10) # y轴标签,字号10
ax.tick_params(axis = 'both', which = 'major', labelsize = 10)
ax.legend(loc='lower right')
plt.show()
3.特征映射
degree = 6
x1 = data2['Test 1']
x2 = data2['Test 2']
data2.insert(3, 'Ones', 1)
for i in range(1, degree+1):
for j in range(0, i+1):
data2['F' + str(i-j) + str(j)] = np.power(x1, i-j) * np.power(x2, j)
data2.drop('Test 1', axis=1, inplace=True)
data2.drop('Test 2', axis=1, inplace=True)
print(data2)
Accepted Ones F10 ... F24 F15 F06
0 1 1 0.051267 … 6.294709e-04 8.589398e-03 1.172060e-01
1 1 1 -0.092742 … 1.893054e-03 -1.398103e-02 1.032560e-01
2 1 1 -0.213710 … 1.048821e-02 -3.397345e-02 1.100469e-01
3 1 1 -0.375000 … 8.944062e-03 -1.197765e-02 1.604015e-02
4 1 1 -0.513250 … 1.238395e-02 -1.123519e-02 1.019299e-02
… … … … … … … …
113 0 1 -0.720620 … 4.374511e-02 -3.270412e-02 2.444980e-02
114 0 1 -0.593890 … 2.115493e-02 -1.762810e-02 1.468924e-02
115 0 1 -0.484450 … 2.340073e-01 -4.826843e-01 9.956280e-01
116 0 1 -0.006336 … 4.003286e-05 -6.313306e-03 9.956280e-01
117 0 1 0.632650 … 3.514745e-07 -1.700678e-08 8.229060e-10
4.正则化代价函数
def costReg(theta, X, y, learningRate):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
return np.sum(first - second) / len(X) + reg
5.正则化梯度函数
def gradientReg(theta, X, y, learningRate):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
parameters = int(theta.ravel().shape[1])
grad = np.zeros(parameters)
error = sigmoid(X * theta.T) - y
for i in range(parameters):
term = np.multiply(error, X[:, i])
if (i == 0):
grad[i] = np.sum(term) / len(X)
else:
grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:, i])
return grad
6.数据集预处理
# 初始化X,y,θ
cols = data2.shape[1]
X2 = data2.iloc[:,1:cols]
y2 = data2.iloc[:,0:1]
theta2 = np.zeros(cols-1)
# 进行类型转换
X2 = np.array(X2.values)
y2 = np.array(y2.values)
#λ设为1
learningRate = 1
costReg(theta2, X2, y2, learningRate)
print(costReg(theta2, X2, y2, learningRate))
0.6931471805599454
7.数据集预处理
result2 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate))
print(result2)
(array([ 1.27271027, 0.62529965, 1.18111686, -2.01987399, -0.9174319 ,
-1.43166929, 0.12393227, -0.36553118, -0.35725403, -0.17516291,
-1.45817009, -0.05098418, -0.61558554, -0.27469165, -1.19271298,
-0.2421784 , -0.20603299, -0.04466178, -0.2777895 , -0.29539514,
-0.45645981, -1.04319154, 0.02779373, -0.2924487 , 0.0155576 ,
-0.32742405, -0.1438915 , -0.92467487]), 32, 1)
使用第1部分中的预测函数来查方案在训练数据上的准确度:
theta_min = np.matrix(result2[0])
predictions = predict(theta_min, X2)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y2)]
accuracy = (sum(map(int, correct)) % len(correct))
print ('accuracy = {0}%'.format(accuracy))
accuracy = 98%
8.画出决策曲线
def hfunc2(theta, x1, x2):
temp = theta[0][0]
place = 0
for i in range(1, degree+1):
for j in range(0, i+1):
temp+= np.power(x1, i-j) * np.power(x2, j) * theta[0][place+1]
place+=1
return temp
def find_decision_boundary(theta):
t1 = np.linspace(-1, 1.5, 1000)
t2 = np.linspace(-1, 1.5, 1000)
cordinates = [(x, y) for x in t1 for y in t2]
x_cord, y_cord = zip(*cordinates)
h_val = pd.DataFrame({'x1':x_cord, 'x2':y_cord})
h_val['hval'] = hfunc2(theta, h_val['x1'], h_val['x2'])
decision = h_val[np.abs(h_val['hval']) < 2 * 10**-3]
return decision.x1, decision.x2
作图
fig, ax = plt.subplots(figsize=(9,6))
ax.set_title("Decision-making curve 1", fontsize=14) # 图名字,字号14
ax.set_xlabel("Test 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Test 2 Score", fontsize=10) # y轴标签,字号10
ax.scatter(positive2['Test 1'], positive2['Test 2'], s=50, c='b', marker='o', label='Accepted')
ax.scatter(negative2['Test 1'], negative2['Test 2'], s=50, c='r', marker='x', label='Rejected')
x, y = find_decision_boundary(result2)
plt.scatter(x, y, c='y', s=50, marker='o', label='Prediction')
ax.legend(loc='lower left')
plt.show()
9.λ=0时,决策曲线
learningRate2 = 0
result3 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate2))
``````c
fig, ax = plt.subplots(figsize=(9,6))
ax.set_title("Decision-making curve 2", fontsize=14) # 图名字,字号14
ax.set_xlabel("Test 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Test 2 Score", fontsize=10) # y轴标签,字号10
ax.scatter(positive2['Test 1'], positive2['Test 2'], s=50, c='b', marker='o', label='Accepted')
ax.scatter(negative2['Test 1'], negative2['Test 2'], s=50, c='r', marker='x', label='Rejected')
x, y = find_decision_boundary(result3)
plt.scatter(x, y, c='y', s=50, marker='o', label='Prediction')
ax.legend(loc='lower left')
plt.show()
10.λ=100时,决策曲线
learningRate2 = 100
result4 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate2))
``````c
fig, ax = plt.subplots(figsize=(9,6))
ax.set_title("Decision-making curve 3", fontsize=14) # 图名字,字号14
ax.set_xlabel("Test 1 Score", fontsize=10) # x轴标签,字号10
ax.set_ylabel("Test 2 Score", fontsize=10) # y轴标签,字号10
ax.scatter(positive2['Test 1'], positive2['Test 2'], s=50, c='b', marker='o', label='Accepted')
ax.scatter(negative2['Test 1'], negative2['Test 2'], s=50, c='r', marker='x', label='Rejected')
x, y = find_decision_boundary(result4)
plt.scatter(x, y, c='y', s=50, marker='o', label='Prediction')
ax.legend(loc='lower left')
plt.show()
总结
1. Scipy优化算法–scipy.optimize.fmin_tnc()
有约束的多元函数问题,提供梯度信息,使用截断牛顿法。
调用:
scipy.optimize.fmin_tnc(func, x0, fprime=None, args=(), approx_grad=0, bounds=None, epsilon=1e-08, scale=None, offset=None, messages=15, maxCGit=-1, maxfun=None, eta=-1, stepmx=0, accuracy=0, fmin=0, ftol=-1, xtol=-1, pgtol=-1, rescale=-1, disp=None, callback=None)
最常使用的参数:
调用参数 | 解释 |
---|---|
func | 优化的目标函数 |
x0 | 初值 |
fprime | 提供优化函数func的梯度函数,不然优化函数func必须返回函数值和梯度,或者设置approx_grad=True |
approx_grad | 如果设置为True,会给出近似梯度 |
args | 元组,是传递给优化函数的参数 |
返回参数 | 解释 |
---|---|
x | 数组,返回的优化问题目标值 |
nfeval | 整数,function evaluations的数目;在进行优化的时候,每当目标优化函数被调用一次,就算一个function evaluation。在一次迭代过程中会有多次function evaluation。这个参数不等同于迭代次数,而往往大于迭代次数。 |
rc | int,Return code, see below |
参考:https://docs.scipy.org/doc/scipy-1.2.1/reference/generated/scipy.optimize.minimize.html#scipy.optimize.minimize