梯度下降法
logistic回归假设 采用了sigmoid函数,因为预测值即代表该例被分类为1的概率,预测值应规范在0-1之间以计算与实际值1/0的差距(分类算法如只含两类通常将结果分为1和0)。
sigmoid function
与此同时,采用常用对数函数来计算代价,使得预测值越接近实际值代价就越小越远离实际值代价就越大。
cost function
继续采用梯度下降算法来逼近拟合参数theta。
theta更新
【代码】
import numpy as np
import matplotlib.pyplot as plt
filepath='/Users/husir/Desktop/ex2data1.txt'
datafile=open(filepath, 'r')
data=datafile.readlines()
#print(*data)
#print(len(data))
Exam1score=[float(x.split(',')[0]) for x in data]
Exam2score=[float(x.split(',')[1]) for x in data]
IfAdmit=[int(x.split(',')[2]) for x in data]
#print(*Exam1score)
#print(*IfAdmit)
#print(len(IfAdmit))
for i in range(len(IfAdmit)):
plt.plot(Exam1score[i],Exam2score[i],'gx' if IfAdmit[i]==1 else 'ro')
plt.xlabel('Exam1score');
plt.ylabel('Exam2score');
# 绿叉是Admitted,红点是Not Admitted
散点图
两个特征的值域与分类值1/0相比太大,因此先进行特征缩放(之前忘了缩放所以theta参数变化的超慢超慢超慢,搞得我以为我过程写错了)
Exam1score=[p/100 for p in Exam1score]
Exam2score=[q/100 for q in Exam2score]
for i in range(len(IfAdmit)):
plt.plot(Exam1score[i],Exam2score[i],'gx' if IfAdmit[i]==1 else 'ro')
plt.xlabel('Exam1score');
plt.ylabel('Exam2score');
缩放后的散点图
m=len(IfAdmit)
x=np.ones((m,3))
y=np.ones((m,1))
for i in range(m):
x[i][1]=Exam1score[i]
x[i][2]=Exam2score[i]
y[i]=IfAdmit[i]
theta=np.ones((3,1))
alpha=1 #学习速率
iteration=1500 #迭代次数
h=np.zeros((m,1))
temp=np.zeros((m,3))
for k in range(iteration):
for i in range(m):
h[i]=1/(1+np.exp(-np.dot(theta.T,x[i]))) #这里的dot实际上是对一维数组(数组与矩阵不同)进行了点乘求和
temp[i]=(h[i]-y[i])*x[i]
theta-=alpha/m*(sum(temp).reshape(3,1))
print(theta)
得到theta值:
[[-13.25487861]
[ 11.09447317]
[ 10.48858765]]
最后绘制决策边界:
for i in range(len(IfAdmit)):
plt.plot(Exam1score[i],Exam2score[i],'gx' if IfAdmit[i]==1 else 'ro')
plt.xlabel('Exam1score')
plt.ylabel('Exam2score')
a=np.linspace(min(Exam1score),max(Exam1score),5)
predicty=-(theta[0]+theta[1]*a)/theta[2]
plt.plot(a,predicty)
决策边界
由于只考虑了三种特征(包括一个常数1),最后画出来的决策边界是线性的,如果多考虑一些会画出更贴合的决策边界(如x1x2,x1^2, x2^2等)。
补充
- 特征缩放很重要
- 上一次末尾写的矩阵点乘和乘法,并不准确。今天发现python的numpy定义出来的矩阵和数组是不同的东西。如下图所示。不同的创建方法
因为两者混着用实在不明智,且array足以包含matrix的操作,所以推荐全部使用数组来处理。
数组的点乘:np.multiply(a,b),a*b
数组的乘法:np.dot(a,b)(仅对非一维数组有效)
数组的点乘求和:np.dot(a1,b1)(仅对一维数组有效)(其实最后结果跟1*n的向量乘上n*1的向量效果一样)
最近有点累,但是要快些自我调节!不断进步才是yyds!