线性回归是机器学习中最经典的算法,因为后面的多层感知也是基于这些算法进行演变而来的,所以当我们完全了解了机器学习之后对于我们了解后面的算法是很有帮助的,尤其对于经典的,每一个机器学习模型都会用到的梯度下降,损失计算进行更深刻的认识是非常具有帮助的。
同时本次的博客将会把整个机器学习我认为比较经典的算法通通进行自己的手动实现,供大家进行参考和学习,那么我们就开始实现本次的第一个机器学习算法,线性回归吧。
线性回归的本质就是使用一组参数去拟合样本数据,在二维平面上就是使用y = kx + b这一条直线去拟合所有的样本点,那么我们要求的就是k和b这两个参数,如下图所示,就是线性回归拟合的结果在二维平面中。
在更高维的平面就是使用超平面去拟合更高维度的特征,同时本次的线性回归将会遵守sklearn的规范进行实现,通过使用面向对象的方式建立一个线性回归模型。
首先定义LinearRegression类,并且对类里面的所有方法进行定义:
我们定义4个函数,分别是__init__、__cost_function、__gradient_descent和fit这个四个函数同时init同来进行初始化操作。__cost_function用来计算损失(相当于神经网络中的前向计算)。__gradient_descent用来进行梯度下降(相当于神经网络中的反向传播)。
#线性回归
class LinearRegression:
#初始化线性回归
def __init__(self,alpha = 0.01,iterations = 1000):
pass
#损失函数计算 forward
def __cost_function(self,X,y,theta):
pass
#backward
#进行梯度下降
def __gradient_descent(self,X,y,theta):
pass
#训练
def fit(self,X,y,norm=False):
pass
之后我们对每一个函数进行实现,首先在__init__中需要对超参数进行初始化,我们的超参数一种有两个一个是学习率alpha、另一个是iterations最大迭代次数,这也正是线性回归需要的两个超参数,我们将这两个超参数变为这个类内部的变量,那么这样就变成了整个类内部的变量了:
import numpy as np
#线性回归
class LinearRegression:
#初始化线性回归
def __init__(self,alpha = 0.01,iterations = 1000):
self.alpha = alpha
self.iterations = iterations
之后我们需要编写前向计算和反向传播两个函数,前向计算使用theta和特征进行矩阵乘法,然后通过MSE进行损失计算。
#损失函数计算 forward
def __cost_function(self,X,y,theta):
m = y.size
#前向计算
error = np.dot(X,theta.T) - y
#计算损失
cost = 1/ (2*m) * np.dot(error.T,error)
return cost,error
反向传播的步骤就是迭代iterations次每次去更新我们需要优化的参数thetas,更新的方式就是对损失函数进行求导,然后沿着导数的方向进行移动,每次移动的步长就是我们的学习率了:
#进行梯度下降
def __gradient_descent(self,X,y,theta):
cost_array = np.zeros(self.iterations)
m = y.size
for i in range(self.iterations):
#计算损失
cost,error = self.__cost_function(X,y,theta)
#求导
theta = theta - self.alpha *np.mean(np.dot(X.T, error))
cost_array[i] = cost
return theta,cost_array
同时这两个方法为类内部的私有方法,外部不能直接调用,我们为外部调用编写一个方法就是fit方法,我们直接调用fit方法,然后fit来调用梯度下降方法,同时在fit中我们需要填写的参数是X,y代表需要训练的数据特征和训练数据的实际值,然后还会有的参数是norm,同时norm为一个boolean型的变量,如果为True那么我们需要对数据进行归一化,归一化的方法对应的就是sklearn中的StanderScaler,把数据归一化成服从标准正态分布的数据,如下代码所示:
def fit(self,X,y,norm=False):
if norm:
X = (X - X.mean()) / X.std()
之后就是编写fit的主要代码了,首先初始化theta,然后对theta进行梯度下降,最后将更新完成的theta进行返回:
def fit(self,X,y,norm=False):
if norm:
X = (X - X.mean()) / X.std()
X = np.c_[np.ones(X.shape[0]), X]
#初始化theta
theta = np.zeros(X.shape[1])
theta, cost_num = self.__gradient_descent(X, y, theta)
self.theta = theta
self.cost_num = cost_num
最后编写predict方法:
def predict(self,X):
if self.theta is not None:
return np.dot(X,self.theta.T)
最后我们整个的LinearRegression类如下所示:
class LinearRegression:
#初始化线性回归
def __init__(self,alpha = 0.0001,iterations = 1000):
self.alpha = alpha
self.iterations = iterations
# pass
self.theta = None
self.cost_num = None
#损失函数计算 forward
def __cost_function(self,X,y,theta):
m = y.size
#前向计算
error = np.dot(X,theta.T) - y
#计算损失
cost = 1/ (2*m) * np.dot(error.T,error)
return cost,error
#backward
#进行梯度下降
def __gradient_descent(self,X,y,theta):
cost_array = np.zeros(self.iterations)
m = y.size
for i in range(self.iterations):
#计算损失
cost,error = self.__cost_function(X,y,theta)
#求导
theta = theta - self.alpha *np.mean(np.dot(X.T, error))
cost_array[i] = cost
return theta,cost_array
#训练
def fit(self,X,y,norm=True):
X = (X - X.mean()) / X.std()
# X = np.c_[np.ones(X.shape[0]), X]
#初始化theta
theta = np.zeros(X.shape[1])
# initial_cost, _ = self.__cost_function(X, y, theta)
theta, cost_num = self.__gradient_descent(X, y, theta)
self.theta = theta
self.cost_num = cost_num
def predict(self,X):
X = (X - X.mean()) / X.std()
if self.theta is not None:
# X = np.c_[np.ones(X.shape[0]), X]
# print(X)
return np.dot(X,self.theta.T)
那么我们对我们编写的这个多元LinearRegression进行测试,使用sklearn生成回归数据:
from sklearn.datasets import make_regression
x, y = make_regression(n_samples=180, n_features=1, noise=10)
plt.scatter(x,y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
实例化LinearRegression并且进行训练:
lr = LinearRegression() lr.fit(x,y)
对训练结果进行绘图:
y_predict = lr.predict(x)
plt.scatter(x,y)
plt.plot(x,y_predict)
plt.xlabel('House Size')
plt.ylabel('House Price')
plt.show()



