Least Angle Regression

    xiaoxiao2022-07-03  131

    文章目录

    引一些基本的假设 LARS算法算法 与别的方法结合LARS与LASSO的关系LARS 与 Stagewise 代码

    Efron B, Hastie T, Johnstone I M, et al. Least angle regression[J]. Annals of Statistics, 2004, 32(2): 407-499.

    在回归分析中,我们常常需要选取部分特征,而不是全都要,所以有前向法,后退法之类的,再根据一些指标设置停止准则。作者提出了一种LARS的算法,能够在有限步迭代后获得很好的结果,而且这种算法能够和LASSO和stagewise结合,加速他们的算法。在我看来,更为重要的是,其背后的几何解释。

    可惜的是,证明实在太多,这方面的只是现在也不想去回顾了,就只能孤陋地把一些简单的东西记一下了。

    一些基本的假设

    上表,是作者进行比较实验的数据集,注意上面的符号: 令 X X X表示变量集,以 x i j x_{ij} xij表示其中的第ij个元素,即第i个病人的第j个指标,用 x i x_i xi表示第i个协变量,就是矩阵 X X X的第i列,用 y y y来表示应变量,且假设(事实上进行预处理,标准化): 线性回归,其系数假设为 β = ( β 1 , β 2 , … , β m ) ′ \beta=(\beta_1, \beta_2, \ldots, \beta_m)' β=(β1,β2,,βm),给出预测向量 μ \mu μ,则: μ = ∑ j = 1 m x j β j = X β , [ X n × m = ( x 1 , x 2 , … , x m ) ] \mu = \sum \limits_{j=1}^m x_j \beta_j = X\beta, \quad [X_{n\times m} = (x_1, x_2, \ldots, x_m)] μ=j=1mxjβj=Xβ,[Xn×m=(x1,x2,,xm)] 均方误差为: S ( β ) = ∥ y − μ ∥ 2 = ∑ i = 1 n ( y i − μ i ) 2 S(\beta) = \|y-\mu\|^2 = \sum \limits_{i=1}^n (y_i - \mu_i)^2 S(β)=yμ2=i=1n(yiμi)2

    T ( β ) T(\beta) T(β)表示 β \beta β ℓ 1 \ell_1 1范数: T ( β ) = ∑ j = 1 m ∣ β j ∣ . T(\beta) = \sum \limits_{j=1}^m |\beta_j|. T(β)=j=1mβj. 那么,Lasso通过下式求解: 而Forward Stagewise,以 μ ^ = 0 \widehat{\mu}=0 μ =0开始,令: 表示当前X与 y − μ ^ y-\widehat{\mu} yμ 的关系,其中 X ′ X' X表示 X X X的转置。 下一步,前进法选择当前关系中最大的部分: 注意到: c ^ j = x j ′ ( y − μ ^ o l d ) − ϵ ⋅ s i g n ( c ^ j ^ ) = c ^ j ^ − ϵ ⋅ s i g n ( c ^ j ^ ) \widehat{c}_j = x_j'(y - \widehat{\mu}_{old})-\epsilon \cdot sign(\widehat{c}_{\hat{j}})=\widehat{c}_{\hat{j}}-\epsilon \cdot sign(\widehat{c}_{\hat{j}}) c j=xj(yμ old)ϵsign(c j^)=c j^ϵsign(c j^) 所以,如果 ϵ = ∣ c ^ j ^ ∣ \epsilon=|\widehat{c}_{\hat{j}}| ϵ=c j^,那么 c ^ j = 0 \widehat{c}_j=0 c j=0,这个时候,stagewise就成了普通的前进法了,这个方法是过拟合的(不懂啊,照本宣科,所以 ϵ \epsilon ϵ改怎么选,我也不知道啊)。

    文章给了俩种方法的一个比较:

    俩个的效果是差不多的,但是,需要注意的是,这俩种方法的迭代次数是不定的。

    LARS算法

    我们从2个特征开始讨论, y ˉ \bar{y} yˉ y y y x 1 , x 2 x_1, x_2 x1,x2子空间的投影,以 μ ^ 0 = 0 \hat{\mu}_0=0 μ^0=0为起点,此时 y ˉ 2 \bar{y}_2 yˉ2 x 1 x_1 x1的角度更加小(以锐角为准),所以, μ ^ 1 = γ x 1 \hat{\mu}_1=\gamma x_1 μ^1=γx1,相当于我们选取了特征 x 1 x_1 x1, 也就是说 β 1 = γ \beta_1=\gamma β1=γ。 现在的问题是, γ \gamma γ该怎么选呢,LARS是这么选的, γ \gamma γ使得 y ˉ 2 − μ ^ 1 \bar{y}_2-\hat{\mu}_1 yˉ2μ^1 x 1 , x 2 x_1, x_2 x1,x2的角度相等,因为这个点俩个特征的重要性是一致的。接着 μ ^ 2 = μ ^ 1 + γ 2 u 2 \hat{\mu}_2=\hat{\mu}_1+\gamma_2 u_2 μ^2=μ^1+γ2u2, γ 2 u 2 = y ˉ 2 − μ ^ 1 \gamma_2u_2=\bar{y}_2-\hat{\mu}_1 γ2u2=yˉ2μ^1。 这么做,我们将 y y y在子空间中的投影 y ˉ 2 \bar{y}_2 yˉ2抵消了。

    为了将这种思想推广到更多特征,需要介绍一些符号和公式。

    注意,公式(2.6)中的 G A − 1 = G A − 1 G_{\mathcal{A}}^{-1}=\mathcal{G_A^{-1}} GA1=GA1

    假设 μ ^ A \widehat{\mu}_{\mathcal{A}} μ A是当前的LARS的估计,那么: 指示集 A \mathcal{A} A是由下式定义的: 令: 注意,这样子,就能令 s j x j ′ ( y − μ ^ A ) = ∣ c ^ j ∣ , j ∈ A s_jx_j'(y-\widehat{\mu}_{\mathcal{A}})=|\widehat{c}_j|, j\in \mathcal{A} sjxj(yμ A)=c j,jA X A , A A , u A X_{\mathcal{A}}, A_{\mathcal{A}}, u_{\mathcal{A}} XA,AA,uA依照上面定义,令: 于是,下一步的更新为: 现在的问题是 γ ^ \widehat{\gamma} γ 应该怎么选,我们先来考察 c j ( γ ) c_j(\gamma) cj(γ): 所以,对于 j ∈ A j \in \mathcal{A} jA, c j ( γ ) c_j(\gamma) cj(γ)的变换程度是一致的: γ ≥ 0 , A A ≥ 0 \gamma \ge 0, A_{\mathcal{A}}\ge0 γ0,AA0,(后者是公式所得,前者是为了减少相关度所必须的),所以,当 γ \gamma γ从0开始慢慢增大的时候, ∣ c j ( γ ) ∣ |c_j(\gamma)| cj(γ)也会慢慢变小,到一定程度,势必会有 j ∈ A c j \in \mathcal{A}^c jAc, 使得 C ^ − γ A A ≤ ∣ c j ( γ ) ∣ \widehat{C}-\gamma A_{\mathcal{A}} \le |c_j(\gamma)| C γAAcj(γ),换句话说,我们只要找到 C ^ − γ A A = ∣ c j ( γ ) ∣ , j ∈ A c \widehat{C}-\gamma A_{\mathcal{A}} = |c_j(\gamma)|, j \in \mathcal{A}^c C γAA=cj(γ),jAc的最小 γ \gamma γ,且 γ > 0 \gamma > 0 γ>0,否则, γ = 0 \gamma=0 γ=0 C ^ − γ A A = ∣ c j ( γ ) ∣ , j ∈ A c ⇒ C ^ − γ A A = c ^ j − γ a j ∣ − c ^ j + γ a j ⇒ γ = C ^ − c ^ j A A − a j ∣ C ^ − c ^ j A A + a j \widehat{C}-\gamma A_{\mathcal{A}} = |c_j(\gamma)|, j \in \mathcal{A}^c \\ \Rightarrow \quad \widehat{C}-\gamma A_{\mathcal{A}}=\widehat{c}_j-\gamma a_j | -\widehat{c}_j+\gamma a_j \\ \Rightarrow \gamma = \frac{\widehat{C}-\widehat{c}_j}{A_{\mathcal{A}}-a_j} |\frac{\widehat{C}-\widehat{c}_j}{A_{\mathcal{A}}+a_j} C γAA=cj(γ),jAcC γAA=c jγajc j+γajγ=AAajC c jAA+ajC c j 总结来说,就是: 其中 + + +表示,如果后半部分的结果均小于0,那么 γ ^ = 0 \widehat{\gamma}=0 γ =0。 这么做,我们就将 c j ( γ ) c_j(\gamma) cj(γ)一直降,降到有一个和他们一样,假设这个 j ∈ A c j \in \mathcal{A}^c jAc j ∗ j^* j,于是下一步更新的时候,我们需要将这个加入到 A \mathcal{A} A, A = A ∪ { j ∗ } \mathcal{A}= \mathcal{A} \cup \{j^*\} A=A{j}

    假设在LARS的第k步: 用 X k , G k , A k X_k, \mathcal{G}_k, A_k Xk,Gk,Ak μ k \mu_k μk是第k步的类似的定义,注意,我们省略了 A \mathcal{A} A。 用 y ˉ k \bar{y}_k yˉk来表示 y y y在子空间 L ( X k ) \mathcal{L}(X_k) L(Xk)的投影,既然 μ ^ k − 1 ∈ L ( X k − 1 ) \widehat{\mu}_{k-1}\in \mathcal{L}(X_{k-1}) μ k1L(Xk1)(因为起点为0),所以: 第一个等式后的第二项是 y − μ ^ k − 1 y-\widehat{\mu}_{k-1} yμ k1在子空间 L ( X k ) \mathcal{L}(X_k) L(Xk)中的投影,第二个等式从(2.6)可以推得: u k = X k A k G k − 1 1 k u_k = X_k A_k \mathcal{G}_k^{-1}1_k uk=XkAkGk11k 又根据(2.18)便可得证。根据(2.19)可得: 又 γ ^ k u k = μ ^ k − μ ^ k − 1 \widehat{\gamma}_ku_k = \widehat{\mu}_k-\widehat{\mu}_{k-1} γ kuk=μ kμ k1: 这说明,每一次更新时,变化的向量时沿着 ( ˉ y ) k − μ ^ k − 1 \bar(y)_k-\widehat{\mu}_{k-1} (ˉy)kμ k1的。 我们通过一个图片来展示:

    上图,我们要处理的时 y ˉ 3 \bar{y}_3 yˉ3,在以及处理 y ˉ 2 \bar{y}_2 yˉ2的基础上,我们看到,最后变化的量是在 y ˉ 3 − μ ^ 2 \bar{y}_3-\widehat{\mu}_2 yˉ3μ 2方向上。

    算法

    顺便整理下算法吧,以便以后用,符号就用自己的了:


    Input: 标准化后的 X = [ x 1 , x 2 , … , x m ] X = [x_1, x_2, \ldots, x_m] X=[x1,x2,,xm] y = [ y 1 , … , y n ] T y=[y_1, \ldots, y_n]^T y=[y1,,yn]T, 特征数 r r r; 令: μ A = 0 , β = [ 0 , 0 , … , 0 ] ∈ R m \mu_{\mathcal{A}}=0, \beta=[0, 0, \ldots, 0] \in \mathbb{R}^m μA=0,β=[0,0,,0]Rm; 计算 c = X T y c = X^Ty c=XTy, 找出其中绝对值最大的元素,令其指标集为 A \mathcal{A} A,最大值为 C C C,令 X A = [ … , s j x j , … ] j ∈ A X_{\mathcal{A}}=[\ldots, s_j x_j, \ldots]_{j \in \mathcal{A}} XA=[,sjxj,]jA, G A = X A T X A , A A = ( 1 A T G A − 1 1 A ) − 1 / 2 \mathcal{G_A}=X_{\mathcal{A}}^TX_{\mathcal{A}}, A_{\mathcal{A}}=(1_\mathcal{A}^T\mathcal{G_A}^{-1}1_{\mathcal{A}})^{-1/2} GA=XATXA,AA=(1ATGA11A)1/2, u A = X A w A , w A = A A G A − 1 1 A \mathrm{u}_{\mathcal{A}}=X_{\mathcal{A}}w_{\mathcal{A}},w_{\mathcal{A}}=A_{\mathcal{A}}\mathcal{G_A}^{-1}1_{\mathcal{A}} uA=XAwA,wA=AAGA11A For k = 1 , 2 , … , r k = 1, 2, \ldots, r k=1,2,,r: 1. 根据公式(2.13)计算 γ ^ \widehat{\gamma} γ ,记录相应的 j j j,如果 γ ^ = 0 \widehat{\gamma}=0 γ =0,停止迭代。 2. μ A = μ A + γ ^ u A \mu_\mathcal{A}=\mu_{\mathcal{A}}+\widehat{\gamma}\mathrm{u}_{\mathcal{A}} μA=μA+γ uA 3. β = β + γ ^ w A ⊗ s A \beta = \beta+\widehat{\gamma}w_{\mathcal{A}}\otimes s_{\mathcal{A}} β=β+γ wAsA 4. 更新 A = A ∪ { j } \mathcal{A}=\mathcal{A} \cup \{j\} A=A{j}, C = C − γ ^ A A C=C-\widehat{\gamma}A_{\mathcal{A}} C=Cγ AA, c = X T ( y − μ A ) c=X^T(y-\mu_\mathcal{A}) c=XT(yμA) 5. 更新 X A , G A , A A , u A X_{\mathcal{A}},\mathcal{G_A}, A_{\mathcal{A}}, \mathrm{u}_{\mathcal{A}} XA,GA,AA,uA 输出: β , μ A \beta, \mu_{\mathcal{A}} β,μA


    注意,上面的 w A ⊗ s A w_\mathcal{A}\otimes s_\mathcal{A} wAsA表示对于元素相乘, s A s_{\mathcal{A}} sA表示对应的符号。还有,如果 r = m r=m r=m,那么上面的迭代只能进行到 r − 1 r-1 r1步,最后一步可以根据公式(2.19)的分解来,在代码中予以了实现。

    不过,利用代码进行实验的时候,发现这俩个好像不大一样

    我感觉没有错。

    与别的方法结合

    LARS与LASSO的关系

    通过对 γ \gamma γ的调整, 利用LARS也能求解LASSO,证明并没有去看。

    可以证明,如果 β ^ \widehat{\beta} β 是通过LASSO求得的解,那么:

    d j = s j w A j , j ∈ A d_j = s_jw_{\mathcal{A}j}, j\in \mathcal{A} dj=sjwAj,jA,那么对于任意的 j ∈ A j \in \mathcal{A} jA: 因此, β j ( γ ) \beta_j({\gamma}) βj(γ)改变符号发生在: 第一次改变符号发生在: 如果,所有的 γ j \gamma_j γj均小于0,那么 γ ~ = + ∞ \widetilde{\gamma}=+\infty γ =+。 也就是说,如果 γ ~ < γ ^ \widetilde{\gamma}< \widehat{\gamma} γ <γ ,为了使得 β \beta β c c c符号保持一致,我们应当选择前者作为此次的更新步长,同时将 j j j A \mathcal{A} A中移除。

    LARS 与 Stagewise

    代码

    import numpy as np import matplotlib.pyplot as plt class LARS_LASSO: def __init__(self, data, response): self.__data = data self.__response = response self.n, self.m = self.data.shape self.mu = np.zeros(self.n, dtype=float) self.beta = np.zeros(self.m, dtype=float) self.compute_c() self.compute_index() self.compute_basic() self.progress_beta = [] self.progress_mu = [] @property def data(self): return self.__data @property def response(self): return self.__response def compute_c(self): """计算关系度c""" self.c = self.data.T @ (self.response-self.mu) def compute_index(self): """找出最大值C和指标集A,以及sj""" self.index = [np.argmax(np.abs(self.c))] newc = self.c[self.index] self.maxC = np.abs(newc[0]) sign = lambda x: 1. if x >= 0 else -1. self.s = np.array( [sign(item) for item in newc], dtype=float ) def compute_basic(self): """计算一些基本的东西 index_A: A_A index_w: w_A index_u: u_A """ index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) self.index_A = 1 / np.sqrt(np.sum(index_G_inv)) self.index_w = np.sum(index_G_inv, 1) * self.index_A self.index_u = index_X @ self.index_w def update_c(self): """更新c""" self.compute_c() def update_index(self, j): """更新指示集合 index: 指示集合A maxC: 最大的c s: 符号 """ if j in self.index: self.index.remove(j) else: self.index.append(j) self.index.sort() newc = self.c[self.index] self.maxC = np.abs(newc[0]) sign = lambda x: 1. if x >= 0 else -1. self.s = np.array( [sign(item) for item in newc], dtype=float ) def update_basic(self): """更新基本的东西""" self.compute_basic() def current_gamma(self): """找第一次改变符号的位置""" const = 999999999. d = self.s * self.index_w index_beta = self.beta[self.index] z = [] for i in range(len(d)): if -index_beta[i] * d[i] <= 0: z.append(const) else: z.append(-index_beta[i] / d[i]) z = np.array(z, dtype=float) label = np.argmin(z) themin = z[label] return themin, self.index[label] def step(self): """操作一步""" const = 9999999999. def divide(x, y): z = [] for i in range(len(x)): if x[i] * y[i] <= 0: z.append(const) else: z.append(x[i] / y[i]) return z complement_index = list(set(range(self.m)) - set(self.index)) a = self.data.T @ self.index_u complement_a = a[complement_index] complement_c = self.c[complement_index] index_reduce_a = self.index_A - complement_a index_plus_a = self.index_A + complement_a maxC_reduce_c = self.maxC - complement_c maxc_plus_c = self.maxC + complement_c min1 = divide(maxC_reduce_c, index_reduce_a) min2 = divide(maxc_plus_c, index_plus_a) totalmin = np.array( [min1, min2] ) allmin = np.min(totalmin, 0) min_beta, label2 = self.current_gamma() self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) try: label = np.argmin(allmin) except ValueError: index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) deltau = index_G_inv @ index_X.T @ (self.response - self.mu) self.mu = self.mu + index_X @ deltau self.beta = self.beta + deltau * self.s return 0 print(min_beta, allmin[label]) if min_beta < allmin[label]: gamma = min_beta j = label2 else: gamma = 0. if allmin[label] == const else allmin[label] j = complement_index[label] self.mu = self.mu + gamma * self.index_u self.beta[self.index] = self.beta[self.index] + (self.s * self.index_w) * gamma if self.life == 0: return 1 self.update_c() self.update_index(j) self.update_basic() return 1 def process(self, r=1): self.life = r for i in range(r): self.life -= 1 print("step:", i) self.step() self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) deltau = index_G_inv @ index_X.T @ (self.response - self.mu) self.mu = self.mu + index_X @ deltau self.beta[self.index] = self.beta[self.index] + deltau * self.s self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) def plot(self): """plot beta, error""" fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 5), constrained_layout=True) beta = np.array(self.progress_beta) mu = np.array(self.progress_mu) r, m = beta.shape error = np.sum((mu - self.response) ** 2, 1) x = np.arange(1, r+1) for i in range(m): y = beta[:, i] ax[0].plot(x, y, label="feature{0}".format(i)) ax[0].text(x[-1]+0.05, y[-1], str(i)) ax[0].set_title(r"$\beta$ with iterations") ax[0].set_xlabel(r"iterations") ax[0].set_ylabel(r"$\beta$") ax[0].legend(loc="best", ncol=2) ax[1].plot(x, error) ax[1].set_title("square error with iterations") ax[1].set_xlabel("iterations") ax[1].set_ylabel("square error") plt.show() data1 = np.loadtxt("C:\\Users\\pkavs\\Desktop\\diabetes.txt", dtype=float) mu = np.mean(data1, 0) std = np.std(data1, 0) data1 = (data1 - mu) / std data = data1[:, :10] response = data1[:, 10] test = LARS_LASSO(data, response) test.process(r=7) test.plot() print(test.progress_beta) """ 跟论文有出路,实验的时候并没有删除的过程,好像是要在 全部特征的基础上,再进行一步,不过机制不想改了,就这样吧 """ import numpy as np import matplotlib.pyplot as plt class LARS_LASSO: def __init__(self, data, response): self.__data = data self.__response = response self.n, self.m = self.data.shape self.mu = np.zeros(self.n, dtype=float) self.beta = np.zeros(self.m, dtype=float) self.compute_c() self.compute_index() self.compute_basic() self.progress_beta = [] self.progress_mu = [] @property def data(self): return self.__data @property def response(self): return self.__response def compute_c(self): """计算关系度c""" self.c = self.data.T @ (self.response-self.mu) def compute_index(self): """找出最大值C和指标集A,以及sj""" self.index = [np.argmax(np.abs(self.c))] newc = self.c[self.index] self.maxC = np.abs(newc[0]) sign = lambda x: 1. if x >= 0 else -1. self.s = np.array( [sign(item) for item in newc], dtype=float ) def compute_basic(self): """计算一些基本的东西 index_A: A_A index_w: w_A index_u: u_A """ index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) self.index_A = 1 / np.sqrt(np.sum(index_G_inv)) self.index_w = np.sum(index_G_inv, 1) * self.index_A self.index_u = index_X @ self.index_w def update_c(self): """更新c""" self.compute_c() def update_index(self, j): """更新指示集合 index: 指示集合A maxC: 最大的c s: 符号 """ if j in self.index: self.index.remove(j) else: self.index.append(j) self.index.sort() newc = self.c[self.index] self.maxC = np.abs(newc[0]) sign = lambda x: 1. if x >= 0 else -1. self.s = np.array( [sign(item) for item in newc], dtype=float ) def update_basic(self): """更新基本的东西""" self.compute_basic() def current_gamma(self): """找第一次改变符号的位置""" const = 999999999. d = self.s * self.index_w index_beta = self.beta[self.index] z = [] for i in range(len(d)): if -index_beta[i] * d[i] <= 0: z.append(const) else: z.append(-index_beta[i] / d[i]) z = np.array(z, dtype=float) label = np.argmin(z) themin = z[label] return themin, self.index[label] def step(self): """操作一步""" const = 9999999999. def divide(x, y): z = [] for i in range(len(x)): if x[i] * y[i] <= 0: z.append(const) else: z.append(x[i] / y[i]) return z complement_index = list(set(range(self.m)) - set(self.index)) a = self.data.T @ self.index_u complement_a = a[complement_index] complement_c = self.c[complement_index] index_reduce_a = self.index_A - complement_a index_plus_a = self.index_A + complement_a maxC_reduce_c = self.maxC - complement_c maxc_plus_c = self.maxC + complement_c min1 = divide(maxC_reduce_c, index_reduce_a) min2 = divide(maxc_plus_c, index_plus_a) totalmin = np.array( [min1, min2] ) allmin = np.min(totalmin, 0) min_beta, label2 = self.current_gamma() print(len(self.progress_beta)) self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) try: label = np.argmin(allmin) except ValueError: index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) deltau = index_G_inv @ index_X.T @ (self.response - self.mu) self.mu = self.mu + index_X @ deltau self.beta = self.beta + deltau * self.s return 0 if min_beta < allmin[label]: gamma = min_beta label = label2 else: gamma = 0. if allmin[label] == const else allmin[label] self.mu = self.mu + gamma * self.index_u self.beta[self.index] = self.beta[self.index] + (self.s * self.index_w) * gamma if self.life == 0: return 1 j = complement_index[label] self.update_c() self.update_index(j) self.update_basic() return 1 def process(self, r=1): self.life = r for i in range(r): self.life -= 1 print("step:", i) self.step() self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) index_X = self.data[:, self.index] * self.s index_G = index_X.T @ index_X index_G_inv = np.linalg.inv(index_G) deltau = index_G_inv @ index_X.T @ (self.response - self.mu) self.mu = self.mu + index_X @ deltau self.beta[self.index] = self.beta[self.index] + deltau * self.s self.progress_beta.append(np.array(self.beta)) self.progress_mu.append(np.array(self.mu)) def plot(self): """plot beta, error""" fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 5), constrained_layout=True) beta = np.array(self.progress_beta) mu = np.array(self.progress_mu) r, m = beta.shape error = np.sum((mu - self.response) ** 2, 1) x = np.arange(1, r+1) for i in range(m): y = beta[:, i] ax[0].plot(x, y, label="feature{0}".format(i)) ax[0].text(x[-1]+0.05, y[-1], str(i)) ax[0].set_title(r"$\beta$ with iterations") ax[0].set_xlabel(r"iterations") ax[0].set_ylabel(r"$\beta$") ax[0].legend(loc="best", ncol=2) ax[1].plot(x, error) ax[1].set_title("square error with iterations") ax[1].set_xlabel("iterations") ax[1].set_ylabel("square error") plt.show()
    最新回复(0)