Algoritmo de escritura a mano-código Python para lograr la regresión de Ridge (término regular L2)

Introducción a Ridge

En los dos artículos anteriores, presentamos el sobreajuste y la regularización, y hablamos sobre los principios y características de la regularización L1 y L2 de manera más completa;
enlace: Análisis de principios : sobreajuste y regularización

Y código Python para lograr la regresión Lasso;
enlace: algoritmo escrito a mano-código Python para lograr la regresión Lasso

Hoy, sobre esta base, hablamos de la regresión Ridge, que es relativamente simple.
Este artículo implementa principalmente la regresión Ridge del código Python (con término regular L2), y usa ejemplos para probar el principio.

Análisis de regresión de Ridge e implementación de código Python

Citando el conjunto de datos generado del artículo anterior:

import numpy as np
from matplotlib import pyplot as plt
import sklearn.datasets

#生成100个一元回归数据集
x,y = sklearn.datasets.make_regression(n_features=1,noise=5,random_state=2020)
plt.scatter(x,y)
plt.show()

#加5个异常数据,为什么这么加,大家自己看一下生成的x,y的样子
a = np.linspace(1,2,5).reshape(-1,1)
b = np.array([350,380,410,430,480])

#生成加入异常数据后新的数据集
x_1 = np.r_[x,a]
y_1 = np.r_[y,b]

plt.scatter(x_1,y_1)
plt.show()

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Los anteriores son el conjunto de datos normales y la imagen con 5 datos anormales agregados. Si usa la regresión lineal directamente para ajustar:

class normal():
    def __init__(self):
        pass

    def fit(self,x,y):
        m=x.shape[0]
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        xMat=np.mat(X)
        yMat =np.mat(y.reshape(-1,1))

        xTx=xMat.T*xMat
        #xTx.I为xTx的逆矩阵
        ws=xTx.I*xMat.T*yMat
        
        #返回参数
        return ws
         


plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
clf1 =normal()
#拟合原始数据
w1 = clf1.fit(x,y)
#预测数据
y_pred = x * w1[1] + w1[0]

#拟合新数据
w2 = clf1.fit(x_1,y_1)
#预测数据
y_1_pred = x_1 * w2[1] + w2[0]

print('原始样本拟合参数:\n',w1)
print('\n')
print('新样本拟合参数:\n',w2)

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

Inserte la descripción de la imagen aquí
Debido a varios datos de puntos anormales, los nuevos parámetros de la línea de regresión ajustados se han vuelto mucho más grandes, de más de 19 puntos a más de 47 puntos; desviándose de la distribución de los datos reales, el rendimiento del modelo disminuye.

Agregamos el término regular L2 para ajustar el modelo. La siguiente es la función de pérdida de la regularización L2;
Inserte la descripción de la imagen aquí

Método 1: método de descenso de gradiente para resolver los parámetros de regresión de Ridge

En el artículo anterior, hemos deducido el gradiente de regresión lineal y el gradiente del término regular L2. El gradiente de esto es la suma de los dos, olvídelo o escríbelo:
Inserte la descripción de la imagen aquí
escribe el código de Python de la siguiente manera (es decir, agrega L2 al gradiente de regresión lineal original Degradado):

class ridge():
    def __init__(self):
        pass
    
    #梯度下降法迭代训练模型参数,x为特征数据,y为标签数据,a为学习率,epochs为迭代次数,Lambda为正则项参数
    def fit(self,x,y,a,epochs,Lambda):  
        #计算总数据量
        m=x.shape[0]
        #给x添加偏置项
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        #计算总特征数
        n = X.shape[1]
        #初始化W的值,要变成矩阵形式
        W=np.mat(np.ones((n,1)))
        #X转为矩阵形式
        xMat = np.mat(X)
        #y转为矩阵形式,这步非常重要,且要是m x 1的维度格式
        yMat =np.mat(y.reshape(-1,1))
        #循环epochs次
        for i in range(epochs):
            gradient = xMat.T*(xMat*W-yMat)/m + Lambda * W
            W=W-a * gradient
        return W
    def predict(self,x,w):  #这里的x也要加偏置,训练时x是什么维度的数据,预测也应该保持一样
        return np.dot(x,w)

función ridge () para lograr nuestra regresión Ridge, ejemplo (los siguientes parámetros son todos después de la depuración, confirmé que el modelo puede converger, continuar aumentando el número de iteraciones o cambiar la tasa de aprendizaje, los coeficientes finales del modelo no cambiarán):

Cuando el parámetro Lambda es 0, es decir, cuando no se agrega el término regular L2, es una regresión lineal ordinaria y el resultado del parámetro es el mismo, que es más de 47 puntos.

#Lambda=0时;
clf = ridge()
w = clf.fit(x_1,y_1,a = 0.001,epochs = 10000,Lambda=0)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

Inserte la descripción de la imagen aquí

Cuando Lambda = 0.5, el parámetro pasa a ser más de 31 puntos;

#Lambda=0.5时;
clf = ridge()
w = clf.fit(x_1,y_1,a = 0.001,epochs = 10000,Lambda=0.5)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

Inserte la descripción de la imagen aquí

Cuando Lambda = 1.5, el parámetro se convierte en más de 18 puntos, que es básicamente el mismo que el parámetro sin agregar valores atípicos;

#Lambda=1.5时;
clf = ridge()
w = clf.fit(x_1,y_1,a = 0.001,epochs = 10000,Lambda=1.5)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

Inserte la descripción de la imagen aquí

Cuando Lambda = 20, el parámetro tiene más de 2 puntos y la línea de ajuste es casi una línea horizontal. En este momento, está muy por debajo del ajuste, el valor de la función de pérdida es muy grande y el modelo no converge en absoluto;

#Lambda=20时;
clf = ridge()
w = clf.fit(x_1,y_1,a = 0.001,epochs = 10000,Lambda=20)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

Inserte la descripción de la imagen aquí
Se puede encontrar que los parámetros de término regular de L2 apropiados pueden evitar el ajuste excesivo;
cuando el parámetro Lambda se vuelve más y más grande, los parámetros del modelo se vuelven cada vez más pequeños, acercándose lentamente a cero.

Método 2: método de ecuación estándar para lograr la regresión de Ridge

A continuación, usamos el método de ecuación estándar para lograr la regresión de Ridge, la fórmula de derivación es la siguiente: El
Inserte la descripción de la imagen aquícódigo de Python se implementa de la siguiente manera:

class standard_ridge():
    def __init__(self):
        pass

    def fit(self,x,y,Lambda):
        m = x.shape[0]
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        xMat= np.mat(X)
        yMat = np.mat(y.reshape(-1,1))

        xTx = xMat.T * xMat
        #生成单位矩阵,2个矩阵行列相等才可以相加
        #前面的梯度下降法代码中,我们没有省掉m,因此,我们化简时,也不省掉m,最后形式就是在正则项梯度这里乘以m,其实不会造成本质影响
        rxTx = xTx + np.eye(xMat.shape[1]) * Lambda * m
        
        #rxTx.I为rxTx的逆矩阵
        w = rxTx.I * xMat.T * yMat
        
        return w

El siguiente es el resultado de la operación:
Inserte la descripción de la imagen aquí
básicamente el resultado es el mismo, pero este formulario es más conciso y conveniente.

Llame a sklearn para comparar

from sklearn.linear_model import Ridge
lr=Ridge(alpha=0)
lr.fit(x_1,y_1)
print('alpha=0时',lr.coef_,'\n')

lr=Ridge(alpha=40)
lr.fit(x_1,y_1)
print('alpha=40时',lr.coef_,'\n')

lr=Ridge(alpha=150)
lr.fit(x_1,y_1)
print('alpha=150时',lr.coef_,'\n')

lr=Ridge(alpha=2000)
lr.fit(x_1,y_1)
print('alpha=2000时',lr.coef_)

Inserte la descripción de la imagen aquí

sklearn 展示 Ridge :

1. A medida que aumenta el valor alfa, es decir, el coeficiente del término regular aumenta, el coeficiente se acerca cada vez más a 0, pero no hay igual a 0.

#用波士顿房价回归数据集展示
data =  sklearn.datasets.load_boston()
x =data['data']
y= data['target']

lr=Ridge(alpha=0)
lr.fit(x,y)
print('alpha=0时',lr.coef_,'\n')

lr=Ridge(alpha=10)
lr.fit(x,y)
print('alpha=10时',lr.coef_,'\n')

lr=Ridge(alpha=100)
lr.fit(x,y)
print('alpha=100时',lr.coef_,'\n')

lr=Ridge(alpha=1000)
lr.fit(x,y)
print('alpha=1000时',lr.coef_)

Inserte la descripción de la imagen aquí
Resumen: Hemos introducido la serie de regresión lineal aquí. Debido a que muchos conceptos se introducen por primera vez, están escritos muy meticulosamente, complementados con ejemplos de datos para garantizar que los lectores puedan entenderlos y, al mismo tiempo, reproducir manualmente estos conceptos básicos. Está claro y conviene explicar más adelante algoritmos complejos.

A continuación, presentaremos la regresión logística.

Supongo que te gusta

Origin blog.csdn.net/weixin_44700798/article/details/110738525
Recomendado
Clasificación