手書きアルゴリズム-リッジ回帰を達成するためのPythonコード
リッジ入門
前の2つの記事では、オーバーフィッティングと正規化を紹介し、L1とL2の正規化の原則と特性についてより包括的に説明しました。
リンク:原則分析-オーバーフィッティングと正規化
そして、なげなわ回帰を達成するためのpythonコード;
リンク:手書きのアルゴリズム-なげなわ回帰を達成するためのpythonコード
今日は、これに基づいて、比較的単純な
リッジ回帰について説明します。この記事では、主にPythonコード(L2正規用語を使用)のリッジ回帰を実装し、例を使用して原理を証明します。
リッジ回帰分析とPythonコードの実装
前の記事から生成されたデータセットを引用する:
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()
上記は、正常なデータセットと5つの異常なデータが追加された画像です。線形回帰を直接使用して適合させる場合:
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()
いくつかの異常なポイントデータのために、新しいフィット回帰線のパラメータは19ポイント以上から47ポイント以上に大幅に大きくなり、実際のデータ分布から外れ、モデルのパフォーマンスが低下します。
モデルを調整するためにL2正規用語を追加します。以下は、L2正規化の損失関数です。
方法1:リッジ回帰パラメータを解くための勾配降下法
前回の記事では、線形回帰の勾配とL2正規項の勾配を推定しました。この勾配は、2つを加算するか、忘れるか、または記述
します。次のようにpythonコードを記述します(つまり、元の線形回帰勾配にL2を加算します)。勾配):
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)
リッジ回帰を実現するためのridge()関数の例(以下のパラメーターはすべてデバッグ後のものであり、モデルを収束させ、反復回数を増やし続け、学習率を変更できることを確認しました。最終的なモデル係数は変更されません):
Lambdaパラメータが0の場合、つまりL2正規項が追加されていない場合、それは通常の線形回帰であり、パラメータ出力は同じで、47ポイントを超えます。
#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()
Lambda = 0.5の場合、パラメーターは31ポイント以上になります。
#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()
Lambda = 1.5の場合、パラメーターは18ポイントを超えます。これは、基本的に、外れ値を追加しないパラメーターと同じです。
#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()
Lambda = 20の場合、パラメータは2ポイントを超え、フィッティングラインはほぼ水平線になります。この時点では、フィッティングが大幅に不足しており、損失関数の値が非常に大きく、モデルがまったく収束していません。
#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()
適切なL2正規項パラメーターがオーバーフィットを防ぐことができることがわかります。
ラムダパラメーターがどんどん大きくなると、モデルパラメーターはどんどん小さくなり、ゆっくりとゼロに近づきます。
方法2:リッジ回帰を達成するための標準方程式法
次に、標準方程式法を使用してリッジ回帰を実現します。導出式は次のとおりです
。pythonコードは次のように実装されます。
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
操作の結果は次のとおりです。
基本的に結果は同じですが、この形式の方が簡潔で便利です。
比較するにはsklearnを呼び出します
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_)
sklearn OracleRidge:
1.アルファ値が増加する、つまり正規項の係数が増加すると、係数はますます0に近づきますが、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_)
概要:ここでは線形回帰シリーズを紹介しました。多くの概念が初めて導入されたため、読者が理解できるようにデータ例を補足し、同時にこれらの基本概念を手動で再現するために、非常に細心の注意を払って記述されています。明確であり、後で複雑なアルゴリズムを説明すると便利です。
次に、ロジスティック回帰を紹介します。