今天我们来开始入门机器学习,简单介绍一下线性回归模型
这几天一直有人问我拟合数据的问题,还有预测模型等问题,所以就想来开始一下这个我一直在准备的专栏--机器学习
线性回归是线性模型,例如,假设输入变量(x)和单个输出变量(y)之间存在线性关系的模型。
更具体地,可以根据输入变量(x)的线性组合来计算输出变量(y)。
所以我们希望算法学习假设的参数,以便能够建立方程进行预测 该方程以特征和参数作为输入,并预测其值作为输出。
要弄明白线性回归就要从背后的数学原理开始讲起
1.数学原理
从初中我们就开始接触方程,一开始是简单的y=kx+b,到后来越来越复杂。初中时有没有碰到这样一类问题呢?题目给出了一大堆商场每天的销售数量和利润让你从中得到函数去估计未来某个销售数量的利润。又或者是大学做大物实验画图的时候,老师总会说描点画线的要求是画一条直线,使每个点均匀的分布在这条直线的两边,且到直线的距离最短。那什么样的直线才是最适合的来预测这些数据特征(属性的)曲线呢?这就需要讲讲线性模型了。
首先是最基本的表达形式
其中X是自变量的各个属性,θ是参数
然后就是最重要的就是怎么才能使参数最优,也就是损失率降到最小。 这就需要谈谈损失率和损失函数了,在这里我们选择的损失函数是均方误差
有了损失函数那我们还要想办法使误差最小。怎么求一个函数的最小值呢,就需要另外一个很重要的算法,叫梯度下降。
梯度下降:梯度下降是一种用来寻找最小损失函数的迭代优化算法。查找局部最小损失函数使用梯度下降算法,以当前点函数的负梯度的一定比例的步数进行逼近。
下图表示我们从函数高点出发找到局部最小值的步骤。
函数的负梯度理解起来就是损失函数求导的负方向
然后每次更新的步长就是我们说的学习率,这样就可以通过迭代求出损失函数的最小值了,从而就得到了最优参数解。
这里有个问题,就是梯度下降容易陷入局部最小值而不是全局最小值,这就涉及到随机梯度下降等优化算法了,而且还有过拟合从而失去泛化能力
代码实现部分
首先是最基本的线性拟合方法
就拿帮别人做的个作业来举例子
import pandas as pd import numpy as np import math from scipy.optimize import leastsq import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False #导入数据 #平方英尺 x=[150,200,250,300,350,400,600] #房价 y=[6450,7450,8450,9450,11450,15450,18450] #训练集和测试集 x_train=np.array(x[0:5]) y_train=np.array(y[0:5]) x_test=np.array(x[5:7]) y_test=np.array(y[5:7]) def fun(p,x): k,b=p return k*x+b # 误差函数 def error(p,x,y): return np.sqrt((fun(p,x)-y)**2) #只用前五个数据进行预测 p0=[100,2] para=leastsq(error,p0,args=(x_train,y_train)) k,b=para[0] print("拟合的方程为:y={}x+{}".format(k,b)) #绘制拟合直线 plt.figure(figsize=(8,6)) plt.scatter(x,y,color="red",label="Point",linewidth=3) X=np.linspace(100,700,1000) Y=k*X+b plt.plot(X,Y,color="orange",label="拟合直线",linewidth=2) plt.xlabel('平方英尺') plt.ylabel('房价') plt.legend() plt.show() 复制代码
#画误差图 err1=[] for i in range(len(x_train)): err1.append(k*x_train[i]+b-y_train[i]) plt.figure(figsize=(10, 7)) plt.title('误差图') plt.plot(x_train,err1,'r',label='error', linewidth=3) plt.xlabel('x') plt.ylabel('error') plt.show()
然后自己仿着sklearn的线性模型写段代码,构建属于自己的线性模型训练器这里用到的数据集是2017年世界幸福指数和GPD的数据,可以在kaggle上下载,链接如下www.kaggle.com/unsdsn/worl…然后我们通过GDP指数去预测人们的幸福指数
import numpy as np import pandas as pd import matplotlib.pyplot as plt #导入数据 data = pd.read_csv('2017.csv') #查看数据集 data.info() data.head(10) 复制代码
#画出每一个属性的分布直方图 histohrams = data.hist(grid=False, figsize=(10, 10))
#切分训练集和测试集 #分出80%训练集,20%测试集 #这里没有用到sklearn的train_test_split train_data = data.sample(frac=0.8) test_data = data.drop(train_data.index) x_train = train_data[['Economy..GDP.per.Capita.']].values y_train = train_data[['Happiness.Score']].values x_test = test_data[['Economy..GDP.per.Capita.']].values y_test = test_data[['Happiness.Score']].values #绘制出散点图 plt.scatter(x_train, y_train, label='Training Dataset') plt.scatter(x_test, y_test, label='Test Dataset') plt.xlabel('Economy..GDP.per.Capita.') plt.ylabel('Happiness.Score') plt.title('Countries Happines') plt.legend() plt.show()
然后就是一些正则化防止过拟合的函数和归一化的函数了,这里就不贴了
#开始自己动手写一个线性回归模型 class self_LinearRegression: def __init__(self, data, labels, polynomial_degree=0, sinusoid_degree=0, normalize_data=True): (data_processed,features_mean,features_deviation)=prepare_for_training(data, polynomial_degree, sinusoid_degree, normalize_data) self.data = data_processed self.labels = labels self.features_mean = features_mean self.features_deviation = features_deviation self.polynomial_degree = polynomial_degree self.sinusoid_degree = sinusoid_degree self.normalize_data = normalize_data num_features = self.data.shape[1] self.theta = np.zeros((num_features, 1)) #训练 def train(self, alpha, lambda_param=0, num_iterations=500): cost_history = self.gradient_descent(alpha, lambda_param, num_iterations) return self.theta, cost_history #梯度下降 def gradient_descent(self, alpha, lambda_param, num_iterations): cost_history = [] for _ in range(num_iterations): self.gradient_step(alpha, lambda_param) cost_history.append(self.cost_function(self.data, self.labels, lambda_param)) return cost_history def gradient_step(self, alpha, lambda_param): num_examples = self.data.shape[0] predictions = self_LinearRegression.hypothesis(self.data, self.theta) delta = predictions - self.labels reg_param = 1 - alpha * lambda_param / num_examples theta = self.theta theta = theta * reg_param - alpha * (1 / num_examples) * (delta.T @ self.data).T theta[0] = theta[0] - alpha * (1 / num_examples) * (self.data[:, 0].T @ delta).T self.theta = theta #损失率 def get_cost(self, data, labels, lambda_param): data_processed = prepare_for_training( data, self.polynomial_degree, self.sinusoid_degree, self.normalize_data, )[0] return self.cost_function(data_processed, labels, lambda_param) def cost_function(self, data, labels, lambda_param): num_examples = data.shape[0] delta = self_LinearRegression.hypothesis(data, self.theta) - labels theta_cut = self.theta[1:, 0] reg_param = lambda_param * (theta_cut.T @ theta_cut) cost = (1 / 2 * num_examples) * (delta.T @ delta + reg_param) return cost[0][0] #预测 def predict(self, data): data_processed = prepare_for_training( data, self.polynomial_degree, self.sinusoid_degree, self.normalize_data, )[0] predictions = self_LinearRegression.hypothesis(data_processed, self.theta) return predictions @staticmethod def hypothesis(data, theta): predictions = data @ theta return predictions 复制代码
#现在开始训练自己做的线性回归模型 num_iterations = 500 #设置迭代次数 learning_rate = 0.01 #学习率 regularization_param = 0 #正则化参数 polynomial_degree = 0 sinusoid_degree = 0 linear_regression = self_LinearRegression(x_train, y_train, polynomial_degree, sinusoid_degree) (theta, cost_history) = linear_regression.train(learning_rate,regularization_param,num_iterations) #输出训练的损失率 print('最初损失率: {:.2f}'.format(cost_history[0])) print('最优损失率: {:.2f}'.format(cost_history[-1])) #输出模型参数 theta_table = pd.DataFrame({'自己的线性模型参数': theta.flatten()}) theta_table.head()
用自己写的模型训练得到的线性回归方程为:y=5.383319*x+0.892002
#画出梯度下降 plt.plot(range(num_iterations), cost_history) plt.xlabel('迭代次数') plt.ylabel('损失率') plt.title('损失率梯度下降图') plt.show()
#用自己构建的模型去进行预测,绘制出模型预测直线 predictions_num = 100 x_predictions = np.linspace(x_train.min(), x_train.max(), predictions_num).reshape(predictions_num, 1) y_predictions = linear_regression.predict(x_predictions) plt.scatter(x_train, y_train, label='训练数据') plt.scatter(x_test, y_test, label='测试数据') plt.plot(x_predictions, y_predictions, 'r', label='预测直线') plt.xlabel('Economy..GDP.per.Capita.') plt.ylabel('Happiness.Score') plt.title('Countries Happines') plt.legend() plt.show()
后用sklrean的LinearRegression也来训练预测一下
#用sklearn构建线性回归模型 from sklearn.linear_model import LinearRegression #创建模型 liner = LinearRegression() #拟合模型 liner.fit(x_train,y_train) #预测 y_predictions = liner.predict(x_predictions) plt.scatter(x_train, y_train, label='训练数据') plt.scatter(x_test, y_test, label='测试数据') plt.plot(x_predictions, y_predictions, 'r', label='预测直线') plt.xlabel('Economy..GDP.per.Capita.') plt.ylabel('Happiness.Score') plt.title('Countries Happines') plt.legend() plt.show() print("斜率为:",liner.coef_) print("截距为:",liner.intercept_) 复制代码