学⽣成绩预测模型_逻辑回归实战练习——根据学⽣成绩预测
是否被录取
前⾔:
在学习了梯度下降和逻辑回归的基本算法后,选取此案例来进⾏实践练习,本次练习主要通过python中的三⼤块pandas、numpy和matplotlib来实现,基本不涉及到sklearn库的调⽤,⼀⽅⾯是⾃⼰编写公式时可以加深对推导公式的理解,另⼀⽅⾯也是为了复习numpy 中的⼀些基本运算命令。
OK,Let's think
本次练习所涉及到的算法理论及分析思路均参考⾃吴恩达⽼师的《机器学习》和唐宇迪⽼师的《机器学习实践》
研究背景:
根据两次考试的结果来决定每个申请⼈的录取机会。现有申请⼈的历史数据,我们可以⽤它作为逻辑回归的训练集。我们将建⽴⼀个分类模型,根据考试成绩来估计⼊学概率。
⼀、数据预处理
数据预处理的⽬的在于对样本数据形成初步认识,从⽽决定数据清晰的内容
1. 数据预览
import
df.head()
从表中可以看出样本中有三⾏,分别是
Exam1(第⼀次考是成绩)
Exam2(第⼆次考是成绩)
Admitted(是否呗录取) 0表⽰不录取,1表⽰录取
2. 可视化预览
逻辑回归是典型的分类问题,从表中并不能直观的看出Admitted是否有明显的边界,因此可视化是个很好的⽅法。在可视化之前,我们先对Admitted定义新标签positive/negative
这⾥我是将positive和negative分别提取出来,然后画在同⼀个图中,当然也可以先groupby然后直接⽤Pandas画图:
高一自我总结#设定标签
positive=df[df['Admitted']==1] #'Admitted'==1 为正向类
negative=df[df['Admitted']==0] #'Admitted'==0 为负向类
#可视化数据预览
fig=plt.figure(figsize=(10,6))
ax=fig.add_subplot(1,1,1)
plt.scatter(x=positive['Exam 1'],y= positive['Exam 2'],marker='x',s=50,label='positive')
plt.scatter(x=negative['Exam 1'],y= negative['Exam 2'],marker='o',s=50,label='negative')
plt.legend()
ax.t_xlabel('Exam 1')
ax.t_ylabel('Exam 2')
从图中可以清晰的观察到positive和negative之间存在这明显的分界线,可以通过逻辑回归来拟合出⼀条回归线。
⼆、建⽴模型
1. 逻辑回归模型的假设函数(hypothesis)如下:
#sigmoid函数
def sigmoid(z):
return 1/(p(-z))
#假设函数h(x)
def model(X,theta):
return sigmoid(np.dot(X,theta.T))
这⾥我们需要添加⼀列x0(x0=1)的值,并把特征矩阵X和观测值y提取出来
#添加x0的特征值为1
df.inrt(0,'ones',1)
#转化为矩阵matrix
data=df.as_matrix()
cols=data.shape[1] #计算data的列数形容酒的成语
X=data[:,:cols-1]
y=data[:,cols-1:cols] #这⾥必须设置cols-1:cols,否则y的shape不对
#建⽴theta的矩阵
s([1,3])
建⽴好预测函数后我们可以试着去运⾏⼀下,这样可以加深对矩阵运算法则的印象
model(X,theta)
得到的是⼀个100X1的矩阵,值全部为0.5,这是因为我们给了theta⼀个初始值[0,0,0],这样z值全为0,在sigmoid函数中,当z=0是,其函数值(概率)为0.5
2. 代价函数和线性回归的代价函数不同:
#代价函数cost
def cost(X,y,theta):α氨基酸
left=np.multiply(-y, np.log(model(X,theta)))
right=np.multiply(1-y, np.log(1-model(X,theta)))依旧爱你
return np.sum(left-right)/ (len(X))
cost(X,y,theta)
再来检查⼀下运算结果:
cost(X,y,theta)
黄河造句
我个⼈对这个值的理解是当theta=[0,0,0]时,所有样本的平均误差为0.6931471805599453
3. 梯度下降的推导式与线性回归时⼀样的:
#计算梯度⽅向
def gradient(X,y,theta):
s_like(theta)
error=(model(X,theta)-y).ravel()
for j in range(len(theta.ravel())):
terms=(np.multiply(error,X[:,j]))
grad[0,j]=np.sum(terms)/(len(X))
return grad
值得注意的是,在编写此公式时需要⽤到ravel()——扁平化,例如:
model(X,theta)-y
结果是100X1的⼆维数组
(model(X,theta)-y).ravel()
结果是⼀个⼀维的数组
因此这⾥需要将⼆维转化为⼀维,从shape上也可以进⼀步确认。如果没有扁平化,那么error应该是⼀个(100,1)的⼆维数组,X[:,j]是⼀个⼀维数组,如果通过multiply对应相乘,那么得到的结果将会是⼀个100X100的⼆维数组,显然不是我们想要的结果。
4. 梯度下降停⽌的策略
梯度下降停⽌的策略有三种:
STOP_ITER = 0 根据迭代次数
STOP_COST = 1 根据代价函数的变化值
STOP_GRAD = 2 根据梯度变化
这⾥学到了⼀个⼩技巧是将三种策略当作不同的变量来使⽤⽽并⾮字符串
'''
type:停⽌策略
value:针对不同的策略具有不同含义的变量
threshold:阈值
'''
def stopcriterion(type,value,threshold):
if type==STOP_ITER:
#当迭代次数⼤于阈值就停⽌
return value > threshold
elif type==STOP_COST:
亮眼睛#两次迭代之间的差值⼩于阈值即可停⽌
return abs(value[-1]-value[-2]) < threshold
elif type==STOP_GRAD:
#梯度下降的⽅向⼩于阈值即可
#求范数,默认情况下=各值的平⽅和开根号
return (value) < threshold
停⽌策略由stopcriterion函数来完成,既然时停⽌,所以它只能⼀个判断条件⼆嫔妃值,所以在这⾥stopcriterion函数返回的时是⼀个布尔值,⽤于梯度下降求解时的循环停⽌的条件
5. 梯度下降⽅式:
全批量下降:每次选择所有样本进⾏迭代,速度慢
随机下降:每次选择⼀个样本迭代,不能保证收敛
⼩批量下降:选择部分样本进⾏迭代,实⽤
梯度下降⽅式的选择主要与选择迭代的样本数量(batchsize)有关,因此可以通过这⼀参数来选择下降⽅式
6. 特征缩放:
⽬的:将所有特征的尺度都缩放在-1 到1之间,这样可以帮助梯度下降算法更快的收敛
鼓励某人做某事⽅法:⽤特征值减去其均值,然后除以⽅差即可,这样所有数据的均值都为0,⽅差为1,但是对与X0这⼀特征值不需要进⾏缩放
#调⽤sklearn 会很⽅便
from sklearn import preprocessing as pp
scaled_py()
scaled_data[:,1:3]=pp.scale(data[:,1:3]) #对x0不进⾏缩放
7. 洗牌
在后续梯度下降的切结过程中会使⽤到⼩批量下降的⽅式,因此需要抽取⼀定量的样本,既然涉及到
抽样,那么洗牌是必不可少的⼯作,同时对于全批量下降来说也能打乱顺序,减⼩偶然性。
import numpy.random
def shuffleData(data):
np.random.shuffle(data) #洗牌
cols=data.shape[1] #提取data的列数
X=data[:,:cols-1] #提取特征矩阵X
y=data[:,cols-1:cols] #提取观测值y
return X, y
8. 梯度下降求解:
将上述已经建⽴好的函数与梯度下降迭代公式进⾏揉和即可,这⾥的难点是建⼀个复杂函数,既要包
含下降⽅式,⼜要包含停⽌策略,对新⼿来说不态友好,⾃⼰也是研究了很久,其核⼼思想还是通过循环和判断来完成:
身心疲惫data:样本数据
theta:先要给定⼀个初始化的theta向量,然后进⾏迭代
batchsize:选择迭代的样本数量
stoptype:停⽌策略
thresh:阈值
alpha:学习率