机器学习(三) 线性回归

  1. 明确要解决的问题-xxx的预测
  2. 数据收集与预处理
  3. 选择机器学习模型(这里选择线性回归)
  4. 通过梯度下降训练机器,确定模型内部参数
  5. 进行超参数调试和性能优化

一、数据收集与预处理

1.1读取数据
import numpy as np
import pandas as pd

df_ads = pd.read_csv('C:/Users/aaa/Desktop/python/data/advertising.csv') #df表示这是一个Pandas Dataframe格式数据
df_ads.head()

线性回归类问题中数据需要归一化吗_线性回归

1.2用相关热力图进行相关分析
import matplotlib.pyplot as plt
import seaborn as sns   #seaborn为统计学数据可视化工具库

#对所有的标签和特征两两显示其相关性的热力图
sns.heatmap(df_ads.corr(),cmap='YlGnBu',annot=True)
plt.show()

线性回归类问题中数据需要归一化吗_线性回归类问题中数据需要归一化吗_02

1.3数据的散点图
#显示销售额和各种广告投放金额的散点图
sns.pairplot(df_ads,
            x_vars=['wechat','weibo','others'],
            y_vars='sales',
            height=4,aspect=1,kind='scatter')
plt.show()

线性回归类问题中数据需要归一化吗_机器学习_03

#由散点图以及相关性热力图可知,wechat与sales相关度较高,所以暂时忽略其他变量
X = np.array(df_ads.wechat)
y = np.array(df_ads.sales)

#机器学习模型所读入的规范格式应该是2D张量,即矩阵,其中行是数据,列是特征
#所以将(200,)转化为(200,1)
X = X.reshape((len(X),1))
y = y.reshape((len(y),1))
print("张量X的阶:",X.ndim)
print("张量X的维度",X.shape)
print("张量X的内容",X)
1.4拆分数据集为训练集和测试集
#拆分数据集为训练集和测试集
#使用sklearn中的train_test_split,进行80%与20%的分割
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=0)
#test_size=0.2表示拆分出来的测试集占总样本量的20%

特征缩放对于机器学习非常重要,可以使训练效率最高
常见的归一化公式如下:
线性回归类问题中数据需要归一化吗_线性回归类问题中数据需要归一化吗_04
也可使用sklearn中preprocessing中的MinMaxScaler
这里自己定义一个归一化函数

#按照公式x'=(x-min(x)) / (max(x)-min(x))
def scaler(train,test):
    min=train.min(axis=0)
    max=train.max(axis=0)
    gap=max-min
    train-=min
    train/=gap
    test-=min
    test/=gap
    return train,test
    
#画出显示数据被压缩处理后的散点图
X_train ,X_test = scaler(X_train,X_test)
y_train ,y_test = scaler(y_train,y_test)

plt.plot(X_train,y_train,'r.',label='Training data')
plt.xlabel('wechat')
plt.ylabel('sales')
plt.legend()
plt.show()

线性回归类问题中数据需要归一化吗_线性回归_05

二、损失函数

用于回归的损失函数:

  • 均方误差(Mean Square Error ,MSE)函数,也叫平方损失或L2损失函数
  • 平均绝对误差(Mean Absolute Error,MAE)函数,也称L1损失函数
  • 平均偏差函数(mean bias error)函数

用于分类的损失函数:

  • 交叉熵损失(cross-entropy)函数
  • 多分类SVM损失(hinge loss)函数

定义损失函数L为:
线性回归类问题中数据需要归一化吗_线性回归_06
其中,(x,y)为样本,x是特征(wechat广告投放金额),y是标签(销售额),
h(x)是假设函数wx+b,
D指的是包含多个样本的数据集,
N是样本数量,N前面的常量2是为了在求梯度时抵消二次方后产生的系数,方便后续计算也不影响梯度下降的最终结果

def loss_function(X, y, weight, bias): # 手工定义一个MSE均方误差函数
    y_hat = weight*X + bias # 这是假设函数,其中已经应用了Python的广播功能
    loss = y_hat-y  # 求出每一个y’和训练集中真实的y之间的差异 
    cost = np.sum(loss**2)/(2*len(X)) # 这是均方误差函数的代码实现
    return cost # 返回当前模型的均方误差值

print ("当权重5,偏置3时,损失为:", 
loss_function(X_train, y_train, weight=5, bias=3))
print ("当权重100,偏置1时,损失为:", 
loss_function(X_train, y_train, weight=100, bias=1))

输出:
当权重5,偏置3时,损失为: 12.796390970780058
当权重100,偏置1时,损失为: 1577.9592615030556

三、梯度下降

关于梯度下降法理解 对于损失函数MSE,存在底部最低点,故选择其为损失函数。

梯度下降法的过程就是在程序中一点一点变化参数w和b,是损失值L逐渐趋于最低点。

线性回归类问题中数据需要归一化吗_线性回归_07


梯度下降法会沿着负梯度方向走一步,以降低损失

用数学语言描述梯度计算过程:

线性回归类问题中数据需要归一化吗_权重_08

代码:

y_hat=weight*X+bias 
loss=y_hat-y      #y与y'间的差值loss
derivative_wight=x.T.dot(loss)/len(X)     #对权重求导,len(X)是样本总数
derivative_bias=sum(loss)*1/len(X)       #对偏置求导,len(X)是样本总数

设学习速率为alpha,学习速率乘以损失曲线求导之后的微分值,就是一次梯度变化的步长,它控制梯度下降的节奏,或慢或快
w将在每一次迭代中被更新:
线性回归类问题中数据需要归一化吗_线性回归类问题中数据需要归一化吗_09
代码如下:

weight=weight-alpha*derivative_wight  #结合学习速率更新权重
bias=bias-alpha*derivative_bias   #结合学习速率更新偏置

定义梯度下降函数:

#定义梯度下降函数
def gradient_descent(X, y, w, b, lr, iter):   # 定义一个实现梯度下降的函数
    l_history = np.zeros(iter)    # 初始化记录梯度下降过程中损失的数组
    w_history = np.zeros(iter)    # 初始化记录梯度下降过程中权重的数组
    b_history = np.zeros(iter)    # 初始化记录梯度下降过程中偏置的数组
    for i in range(iter):        # 进行梯度下降的迭代,就是下多少级台阶
        y_hat  = w*X + b    # 这个是向量化运行实现的假设函数
        loss = y_hat-y      # 这是中间过程,求得的是假设函数预测的y和真正的y值间的差值
        derivative_w = X.T.dot(loss)/len(X)    # 对权重求导, len(X)是样本总数
        derivative_b = sum(loss)*1/len(X)   # 对偏置求导
        w = w - lr*derivative_w   # 结合下降速率alpha更新权重
        b = b - lr*derivative_b   # 结合下降速率alpha更新偏置
        l_history[i] = loss_function(X, y, w,b)   # 梯度下降过程中损失的历史
        w_history[i] = w    # 梯度下降过程中权重的历史
        b_history[i] = b    # 梯度下降过程中偏置的历史
    return l_history, w_history, b_history    # 返回梯度下降过程数据

四、一元线性回归调参

初始状态:

# 首先确定参数的初始值
iterations = 225; # 迭代250次
alpha = 0.5; # 此处初始学习速率设为0.5, 如果调整为1,你会看到不同的结果
weight = -5 # 权重
bias = 3 # 偏置
# 计算一下初始权重和偏置值所带来的损失
print ('当前损失:',loss_function(X_train, y_train, weight, bias))

# 绘制当前的函数模型
plt.plot(X_train, y_train,'r.', label='Training data') # 显示训练集散点图
line_X = np.linspace(X_train.min(), X_train.max(), 500) # X值域
line_y = [weight*xx + bias for xx in line_X] # 假设函数y_hat
plt.plot(line_X,line_y,'b--', label='Current hypothesis' ) #显示当前拟合
plt.xlabel('Wechat Ads') # X轴Label
plt.ylabel('Sales') # y轴Label
plt.legend() # 显示图例
plt.show() # 显示绘图

线性回归类问题中数据需要归一化吗_机器学习_10


进行梯度下降:

# 根据初始参数值,进行梯度下降,也就是开始训练机器,拟合函数
loss_history, weight_history, bias_history = gradient_descent(
             X_train, y_train, weight, bias, alpha, iterations)
plt.plot(loss_history,'g--',label='Loss Curve')
plt.xlabel('Iterations') # x轴Label
plt.ylabel('Loss') # y轴Label
plt.legend() # 显示图例
plt.show() # 显示损失曲线

线性回归类问题中数据需要归一化吗_梯度下降_11

# 绘制当前的函数模型
plt.plot(X_train, y_train,'r.', label='Training data') # 显示训练集散点图
line_X = np.linspace(X_train.min(), X_train.max(), 500) # X值域
# 关于weight_history[-1],这里的索引[-1],就代表迭代500次后的最后一个W值
line_y = [weight_history[-1]*xx + bias_history[-1] for xx in line_X] # 假设函数
plt.plot(line_X,line_y,'b--', label='Current hypothesis' ) # 显示当前函数
plt.xlabel('Wechat Ads') # x轴Label
plt.ylabel('Sales') # y轴Label
plt.legend() # 显示图例
plt.show() # 显示函数图像

线性回归类问题中数据需要归一化吗_机器学习_12


计算损失:

print ('当前损失:',loss_function(X_train, y_train, 
                  weight_history[-1], bias_history[-1]))
print ('当前权重:',weight_history[-1])
print ('当前偏置:',bias_history[-1])
print ('测试集损失:',loss_function(X_test, y_test, 
                    weight_history[-1], bias_history[-1]))

输出:
当前损失: 0.004656784743714472
当前权重: 0.6581321194241853
当前偏置: 0.17541401911198484
测试集损失: 0.004556706461254487

五、直接使用sklearn进行线性回归

建立模型:

from sklearn.linear_model import LinearRegression #导入线性回归算法模型
model = LinearRegression() #使用线性回归算法
model.fit(X_train, y_train) #用训练集数据,训练机器,拟合函数,确定参数

输出预测:

y_pred = model.predict(X_test) #预测测试集的Y值
print ('销量的真值(测试集)',y_test)
print ('预测的销量(测试集)',y_pred)
print("线性回归预测评分:", model.score(X_test, y_test)) #评估预测结果

还可采用线性岭回归算法:

from sklearn.linear_model import Ridge #导入线性岭回归算法模型 
model = Ridge() #使用线性回归算法
model.fit(X_train, y_train) #用训练集数据,训练机器,拟合函数,确定参数
y_pred = model.predict(X_test) #预测测试集的Y值
print("线性回归预测评分:", model.score(X_test, y_test)) #评估预测结果