一、引起过拟合的原因

  • 训练数据过少,训练数据的分布不能表示整体样本的分布。
  • 特征过多。特征太多其实也属于模型复杂。
  • 模型过于复杂。高阶多项式。

二、缓解过拟合的方法——正则化

    正则化的本质是使模型简单,解决了特征过多,模型过于复杂的问题。

    本质是对权重W的约束。y=wx,当w变小时,相应的x就没有意义了,相当于x变小了。

    通常的解释是,越小的权重,模型复杂度越低(例如特征X剧烈变化时,由于w很小,y的变化就会比较小),因此能够更简单有效的描绘数据,所以我们倾向于选择较小的权重。

三、岭回归(L2)与LASSO回归(L1)

  •  岭回归是基于L2惩罚项的模型,是在最小二乘代价函数中加入了权重的平方和。

       其中

  • LASSO回归:对于基于稀疏数据训练的模型,还有另外一种解决方案,即LASSO。基于正则化项的强度,某些权重可以为零(使得对应的权重 xi 失去作用),这也使得LASSO成为一种监督特征选择技术。

 

       其中

    一般回归分析中,w表示特征 x 的系数,是特征重要性的度量,表示输入特征 x 对输出 y 的影响度。正则化正是对系数 w 做了处理(限制)。

  •  L1正则化是指权重值向量 w 中各个元素的绝对值之和, 通常表示为 ||w||。
  •  L2正则化是指权值向量 w 中各个元素的平方和然后求平方根。(可以看到Ridge回归的L2正则化项有平方符号),通常表示为  ||w||2 。

    一般会在正则化项之前添加一个系数,这个系数需要由用户指定。

    L1和L2正则化的作用:

  • L1正则化可以产生稀疏权值矩阵的作用,即产生一个稀疏模型,用于特征选择。
  • L2正则化可以防止模型过拟合(overfitting);一定程度上,L1也可以防止过拟合。

    毕竟一个简单的解释的出现似乎不可能仅仅是因为巧合,我们猜测这个模型一定表达了关于这个现象的一些潜在真理。

    复杂模型往往容易学习到了一些局部噪声的影响(现实的数据总是有噪声的)。因此当 一个复杂模型(比如一个n次多项式模型)完美拟合了特定数据集的时候,这样的模型一般都不能很好泛化到其它数据集上,所以包含一定噪声的线性模型在预测中会有更好的表现。

 

 

    更倾向简单模型的想法,人们有时把它称作「奥卡姆剃刀」,并且就好像它是科学原理一样,热情地应用它。然而,它并不是一个普遍成立的科学原理。并不存在一个先验的符合逻辑的理由倾向于简单的模型,而不是复杂的模型。实际上,有时候更复杂的模型反而是正确的。

    需要根据现实的数据和应用来正确的判断,只是大多数情况下,在满足一定性能的前提下,选择更简单的模型。

    如下图所示,绿色表示真实的分布。M表示幂函数的幂次。虽然高次幂函数可以很好的拟合现有训练数据,但是泛化性能不好。相反如果倾向于用更简单的模型来拟合数据,可能直线也是一个可选的模型。但实际情况确实一个三次幂函数,既不是最简单的模型,也不是那个拟合最好的复杂模型。所以要根据现实场景来判断。

    

四、正则项作用原理的解读

    下面两个图,左侧图形使用了最高10次项的多项式拟合(没有加正则项)。虽然能够很好的拟合样本中的所有的点,但并不是理想的拟合,似乎泛化能力很弱。右侧图形在左侧图形基础上加上了L2正则项(Ridge Regression),得到了一个相对理想的模型。

 

    原因分析:

    对于一个十次多项式的假设和一个二次多项式的假设。

 

    H_10的假设是包含H_2的假设的。如果把H_10中的 w_3 … w_10等项都设为0,就得到H_2假设。可以理解为二次多项式就是十次多项式对w加上一些限制得到的。 也就是说,我们的目标是找出w_3 … w_10都为0的假设,就可以得出目标二次多项式。如果条件放宽松点,把w的长度规定在C以内,即,则会有更大的可能找出w_3 … w_10都为0的假设。这就是正则化的由来,把w限制在一定范围之内。

    我们求解的问题就是

    把上面两个带约束的假设化成图就是如下图所示(假设w是二维的)。L2是在W空间中加了一个球形区域的约束,在这个球形区域内找最优解,而L1就是在这个菱形区域找最优解。

    为什么L1正则化更容易将特征稀疏化?

     见下面这个图。

    

    不同颜色曲线为等高图,颜色越冷表示代价函数J(w1,w2)的值越小,由于被限制在L1的菱形范围内,所以等高线一旦接触到顶点,就满足了限制范围内的最小值,因为圈越往外,J值越大。

    因为四个顶点上更容易在极值点上被接触,而四个顶点上,会使得部分w为0。

    正则化的一般形式如下:

    越大,则最优解w可以落入的区域越小,越不容易发生过拟合。但是也越容易发生欠拟合。需要在实际使用中尝试不同参数,找出最好的 值。

    另外,L1正则项用于得到稀疏的w,L2正则项用于得到长度比较小的w,在实际使用过程中两者可以结合使用。

 

*******************************************************************************华丽的分割线**************************************************************************** 

源代码

boston_house  数据文件

# In[0]
import pandas as pd

# 绘制散点图,计算MSE, R2
def model_eval(y_train_pred, y_train, y_test_pred, y_test):
    # 绘制散点图
    plt.scatter(y_train_pred, y_train_pred - y_train,
                c=\'steelblue\', marker=\'o\', edgecolor=\'white\',
                label=\'Training_data\')
    plt.scatter(y_test_pred, y_test_pred-y_test,
                c=\'limegreen\', marker=\'s\', edgecolor=\'white\',
                label=\'Test_data\')
    plt.xlabel(\'Predicted values\')
    plt.ylabel(\'Residuals\')
    plt.legend(loc=\'upper left\')
    plt.hlines(y=0, xmin=-10, xmax=50, color=\'black\', lw=2)
    plt.xlim([-10, 50]) # 设置坐标轴的取值范围
    plt.tight_layout()
    plt.show()

    # 计算均方误差MSE、决定系数R2
    from sklearn.metrics import r2_score
    from sklearn.metrics import mean_squared_error
    print("MSE of train: %.2f, test, %.2f" % (
                        mean_squared_error(y_train, y_train_pred), 
                        mean_squared_error(y_test, y_test_pred)))

    print("R^2 of train: %.2f, test, %.2f" % (
                        r2_score(y_train, y_train_pred), 
                        r2_score(y_test, y_test_pred)))

# 从csv载入房价数据
def read_house_data(file_path):    
    df = pd.read_csv(file_path)

    df.columns = [\'row\', \'CRIM\', \'ZN\', \'INDUS\', \'CHAS\', 
                \'NOX\', \'RM\', \'AGE\', \'DIS\', \'RAD\', 
                \'TAX\', \'PTRATIO\', \'B\', \'LSTAT\', \'MEDV\']
    df.drop("row", axis=1, inplace=True) #删除第一列的行号
    X = df.iloc[:, :-1].values
    y = df[\'MEDV\'].values
    return X, y

# In[1]
X, y = read_house_data(\'boston_house.csv\')

# In[2]
from sklearn.model_selection import train_test_split



X_train, X_test, y_train, y_test = train_test_split(X, y,
                                    random_state=0, test_size=0.3)
# In[4]
# 开始训练
from sklearn.linear_model import LinearRegression
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

lr = LinearRegression()
lr.fit(X_train, y_train)
y_train_pred = lr.predict(X_train)  #训练数据的预测值
y_test_pred = lr.predict(X_test)    #测试数据的预测值

model_eval(y_train_pred, y_train, y_test_pred, y_test)

# In[7]
# Ridge regression 岭回归
from sklearn.linear_model import Ridge
ridge = Ridge(alpha=10)
ridge.fit(X_train, y_train)
y_train_pred = ridge.predict(X_train)
y_test_pred = ridge.predict(X_test)
print(ridge.coef_)
print(lr.coef_)
model_eval(y_train_pred, y_train, y_test_pred, y_test)


# In[8]
# Elastic Net regression
from sklearn.linear_model import ElasticNet
elanet = ElasticNet(alpha=0.1, l1_ratio=0.5) 
elanet.fit(X_train, y_train)
y_train_pred = elanet.predict(X_train)
y_test_pred = elanet.predict(X_test)
print(elanet.coef_)
print(lr.coef_)
model_eval(y_train_pred, y_train, y_test_pred, y_test)

 

版权声明:本文为aviator999原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/aviator999/p/10064674.html