简单实现线性回归和逻辑回归的梯度下降算法(上)

1,086 阅读5分钟

大家好,自己也很久没有更新博客了,实在有点不好意思。由于去年一年准备考研,然后疫情期间又是准备毕设又是准备复试,所以耽搁了蛮久的。不过还好运气不错,考研上了岸,毕业也圆满完成,加上尘埃落定后,去西藏玩了大半个月,所以现在才开始重新学习起来。由于目前研究生的方向还未定,也就琢磨着把Python还有吴恩达的机器学习视频学习一遍。这两篇也是对自己这段时间摸鱼学习的一个小小总结吧。

上篇:线性回归

下篇:逻辑回归(基于kaggle的titanic题目)

线性回归(Liner Regression)

在上图中,蓝色的散点就是训练样本下的 XY 在直角坐标系上的表现,然后红色的曲线则是通过训练后,对训练样本的一个拟合曲线。对于后续给定的并且不在训练样本中的 X ,通过这个拟合曲线就能预测相应的 Y 值。

线性回归还是比较简单的,尤其是在二维的情况下,即简单的 XY ,在最简单的情况下拟合一个直线,即求出斜率和截距,或者像上图那样求解一个一元二次方程a*x**2 + b*x + c = y的参数:abc。在三维的情况下则是 XYZ ,这时则是拟合一个平面,或者拟合一个曲面。而在更高维的情况下,也可以简单的看作求解一个多元方程的各个位置上的参数。

我在线性回归这里就不详细解释一些数学公式了,吴恩达的视频大家都找得到,花点时间学习一下就能看懂背后的数学原理。接下来直接上代码。

准备数据

首先准备数据,由于线性回归比较简单,所以就直接使用随机数生成:

# 100个训练样本
m = 100
# 生成随机训练样本
X0 = np.ones((m,1))
X1 = np.random.rand(m,1)
X1.sort(0)
# 构造矩阵{X0,X1,X1**2}
X = np.hstack((X0,X1,X1**2))
Y = ( 2 + 3 * X1 + 4 * X1**2 ) + np.random.rand(m,1)

构造一个 X 矩阵,其维度为 m * 3X1 是随机生成 m 维的列向量,对 X1 进行排序,后续画图不会有线乱窜。最后在 Y 加上随机数即对数据加上一噪点。

开始训练

计算代价函数:

在介绍梯度计算前,首先先说下代价函数。

这是吴恩达视频中介绍线性回归的代价函数,其中 h 则是假设函数,即给定输入 x 的情况下,对结果的一个预测值。 y 则是训练样本中在给定输入 x 的情况下,结果的一个实际值。上面代价函数很好的表现了代价二字,在预测越偏离实际的情况下,代价函数的值越大,即代价越大,而在预测越接近实际的情况下,代价函数的值越小。所以我们要计算出代价函数值最小情况下的参数 theta ,也就是上述一元二次方程的abc。接下来上计算代价函数的代码。

# 计算当前theta在给定训练集下的代价
def calc_cost(theta,x,y):
    temp = np.dot(x,theta) - y
    temp = np.dot(np.transpose(temp),temp)
    return (1/2*m) * temp

由于线性回归比较简单,所以简单的训练样本 Xtheta 相乘则是一个预测函数的结果。

计算梯度:

以上则是代价函数的梯度,即对代价函数的各个 theta 求偏导数。

# 计算当前theta在给定训练集下的梯度
def calc_gradient(theta,x,y):
    temp = np.dot(x,theta) - y
    return (1/m) * np.dot(np.transpose(x),temp)

梯度则是一个 n+1 维的列向量,即每一个 theta 都有一个相应的偏导数。

梯度下降:

由于往梯度方向移动是递增最快的方向,而我们需要计算代价函数的最小值,所以我们往梯度的反方向移动,向极小值逼近。如果是凸函数,则能够逼近全局极小值,也就是最小值。

# 运行梯度下降算法
def gradient_descent(x,y,alpha):
    # n+1个特征,相应的n+1个theta
    theta = np.ones((x.shape[1],1))
    gradient = calc_gradient(theta,x,y)
	# 当所有theta的偏导数都小于1e-5则可以确定以及逼近到了全局最小值
    while not np.all(np.absolute(gradient) <= 1e-5):
    	# 计算代价函数
		# 计算代价函数用于确认在不同迭代次数下代价函数值的递减趋势
	    # temp_cost = calc_cost(theta,x,y)
	    # cost.append(temp_cost[0][0])
	    # 计算梯度
	    theta = theta - alpha * gradient
	    gradient = calc_gradient(theta,x,y)
    return theta

显示结果

训练完成后最后的 theta 如上图所示,由于加入了“噪点”,对参数的拟合还是有点误差的。

对散点的拟合则是如上图所示,虽然从数据上看对 theta 有点误差,但是从直观的图像上看还是比较拟合的。

逻辑回归(Logistic Regression)

由于逻辑回归不好自己随机生成训练样本,所以找上了kaggle的经典题目titanic。先给大家看看自己最好的训练结果:

由于今天比较晚了,又很久没写博客了,所以花了很多时间准备,下篇大概明天或者过几天就更新。