感谢B站Up 凩子白的讲解视频, 大多数的RLS算法介绍都是从各种专业领域角度讲解的(比如滤波器等角度), 对于缺乏专业背景的同学入门较难, 本文主要是以上提到的视频的文字化, 加入了自己的一些理解, 也许有一些地方不是那么严谨, 不过希望能帮助其他同学快速了解一下RLS算法的思想。
对于样本数据对儿
(
x
,
y
)
(\mathbf{x},y)
(x,y), 其中输入数据向量
x
=
[
x
11
,
x
12
,
.
.
.
,
x
1
m
]
T
∈
R
m
\mathbf{x}=[x_{11},x_{12},...,x_{1m}]^T \in \mathbb{R}^m
x=[x11,x12,...,x1m]T∈Rm, 输出样本为
y
∈
R
y\in \mathbb{R}
y∈R; 使用参数为
w
\mathbf{w}
w 的模型来拟合数据
(
x
,
y
)
(\mathbf{x},y)
(x,y)之间的真实映射关系; 认为模型
w
\mathbf{w}
w的输出为
y
y
y的估计值
y
^
∈
R
\hat{y}\in \mathbb{R}
y^∈R, 满足
y
^
∼
f
(
w
;
x
)
\hat{y} \sim f({\mathbf{w}};\mathbf{x})
y^∼f(w;x), 拟合模型满足如下形式
y
1
^
=
w
1
x
11
+
w
2
x
12
+
.
.
.
w
m
x
1
m
=
x
1
T
w
y
2
^
=
x
2
T
w
⋮
y
n
^
=
x
n
T
w
(1)
\hat{y_1}=w_1x_{11}+w_2x_{12}+...w_mx_{1m}=\mathbf{x_1^T}\mathbf{{w}}\\ \hat{y_2}=\mathbf{x_2^T }\mathbf{{w}}\\ \vdots\\ \hat{y_n}=\mathbf{x_n^T }\mathbf{{w}} \tag{1}
y1^=w1x11+w2x12+...wmx1m=x1Twy2^=x2Tw⋮yn^=xnTw(1)
最小二乘法的思路, 就是希望近似模型参数
w
\mathbf{{w}}
w在这
n
n
n个样本输入数据
X
n
×
m
=
[
x
1
,
x
2
,
.
.
.
,
x
n
]
T
X_{n\times m}=[\mathbf{x_1},\mathbf{x_2},...,\mathbf{x_n}]^T
Xn×m=[x1,x2,...,xn]T (以后简记为
X
X
X)上得出的估计值
y
^
=
[
y
1
^
,
y
2
^
,
.
.
.
,
y
n
^
]
T
\hat{\mathbf y}=[\hat{y_1},\hat{y_2},...,\hat{y_n}]^T
y^=[y1^,y2^,...,yn^]T 与ground truth 输出样本数据
y
=
[
y
1
,
y
2
,
.
.
.
,
y
n
]
T
\mathbf y=[y_1,y_2,...,y_n]^T
y=[y1,y2,...,yn]T 之间的差值平方和最小,即
w
=
arg
m
i
n
∑
i
=
1
n
(
y
i
−
y
i
^
)
2
=
arg
m
i
n
∑
i
=
1
n
(
y
i
−
x
i
T
w
)
2
=
arg
m
i
n
∥
y
−
X
w
∥
2
2
=
arg
m
i
n
E
(
w
)
(2)
{\mathbf{w}} =\arg min \sum\limits_{i=1}^n (y_i-\hat{y_i})^2\\ = \arg min \sum\limits_{i=1}^n (y_i-\mathbf{x_i^T }\mathbf{{w}})^2\\ =\arg min \begin{Vmatrix} \mathbf{y}-X\mathbf{w} \end{Vmatrix}_2^2\\ =\arg min\ E(\mathbf{w}) \tag{2}
w=argmini=1∑n(yi−yi^)2=argmini=1∑n(yi−xiTw)2=argmin
y−Xw
22=argmin E(w)(2)
误差
E
(
w
)
E(\mathbf{w})
E(w)对参数
w
\mathbf{w}
w 求梯度,
∇
w
E
=
∇
w
∥
y
−
X
w
∥
2
2
=
∇
w
[
(
y
−
X
w
)
T
(
y
−
X
w
)
]
=
2
X
T
(
y
−
X
w
)
(3)
\nabla_\mathbf{w} E =\nabla_\mathbf{w}\begin{Vmatrix} \mathbf{y}-X\mathbf{w} \end{Vmatrix}_2^2\\ =\nabla_\mathbf{w} \big[(\mathbf{y}-X\mathbf{w})^T(\mathbf{y}-X\mathbf{w})\big] \\ =2X^T(\mathbf{y}-X\mathbf{w}) \tag{3}
∇wE=∇w
y−Xw
22=∇w[(y−Xw)T(y−Xw)]=2XT(y−Xw)(3)
令
∇
w
E
=
0
\nabla_\mathbf{w} E=0
∇wE=0, 即可求出
w
=
X
−
1
y
=
(
X
T
X
)
−
1
X
T
y
(4)
\mathbf{w}=X^{-1}\mathbf{y}=(X^TX)^{-1}X^T\mathbf{y} \tag{4}
w=X−1y=(XTX)−1XTy(4)
注意, 公式
3
{3}
3中的
y
\mathbf y
y是样本数据, 将
X
−
1
X^{-1}
X−1表述为
(
X
T
X
)
−
1
X
T
(X^TX)^{-1}X^T
(XTX)−1XT的原因是矩阵
X
X
X不一定是
n
×
n
n\times n
n×n形状,因此不一定有逆矩阵, 而
X
T
X
X^TX
XTX的逆是存在的?
当一次性给出所有样本集合 ( X , y ) (X,\mathbf{y}) (X,y)时, 可以通过公式 4 {4} 4来直接计算出最优的拟合模型参数 w \mathbf{w} w , 然而, 在实际应用中, 这种直接计算法并不常见, 主要是因为公式中求逆部分 ( X T X ) − 1 (X^TX)^{-1} (XTX)−1 的计算量大, 在样本数据量大时计算量更是明显增大; 另外, 现实生活中,往往出现样本数据可能也并不是一次性给出, 而是不断给出新的样本数据, 以一种数据流的形式给出样本数据, 例如传感器随时间不断读取信号等, 这种情况下利用公式 4 {4} 4直接计算最优模型参数 w {\mathbf{w}} w 就需要每次进行直接计算, 也是不现实的.
因此, 为了利用最小误差平方和原则, 求解在大样本量, 或者数据流情况下的最优模型参数 w {\mathbf{w}} w, 一种方法可以将大样本分成多批次(batch), 计算旧模型在新批次样本上的梯度, 不断进行梯度下降来进行迭代求解(也可以将数据流当做一个个batch来梯度更新); 另一种则是解析的方法, 就是这里提到的递归最小二乘解法(RLS).
本质上, 递归最小二乘法RLS和梯度下降、直接计算法一样, 都是为了求解满足最小误差平方和原则的最优模型参数 w {\mathbf{w}} w, 只是在实现方式上有所不同.
如之前提到的, RLS的主要应用场景, 是假设输入样本数据 X X X在不断添加新数据, 例如 X = [ x 1 , x 2 , . . . , x n ] T → X ′ = [ x 1 , x 2 , . . . , x n , x n + 1 ] T X=[\mathbf{x_1},\mathbf{x_2},...,\mathbf{x_n}]^T\rightarrow X'=[\mathbf{x_1},\mathbf{x_2},...,\mathbf{x_n} , \mathbf{x_{n+1}}]^T X=[x1,x2,...,xn]T→X′=[x1,x2,...,xn,xn+1]T, y = [ y 1 , y 2 , . . . , y n ] T → y ′ = [ y 1 , y 2 , . . . , y n , y n + 1 ] T \mathbf y=[y_1,y_2,...,y_n]^T\rightarrow\mathbf y'=[y_1,y_2,...,y_n,y_{n+1}]^T y=[y1,y2,...,yn]T→y′=[y1,y2,...,yn,yn+1]T, 即, 以一种数据流的形式给定样本; 这种情况下最优模型参数也将发生变化 w → w ′ \mathbf{w}\rightarrow \mathbf{w}' w→w′, 那么如果使用公式 4 {4} 4 就必须不断一次次计算逆矩阵 ( X T X ) − 1 (X^TX)^{-1} (XTX)−1, 由于计算逆矩阵非常耗时, 上述的计算方法显然是不实用的, 因此希望找到一种以公式 4 {4} 4为基础的递归求解新参数 w ′ \mathbf{w'} w′的方法, 使得求解出的新模型 w ′ \mathbf{w'} w′在当前最新的样本集 ( X ′ , y ′ ) (X',\mathbf{y'}) (X′,y′)上仍然满足误差平方和最小原则.
假设, 我们手头已经有了一个在已有样本 ( X , y ) (X,\mathbf{y}) (X,y) 上满足最小误差平方和的模型参数 w \mathbf{w} w (至于最初的模型参数的获取见下文), 我们希望找到一种递推公式, 能够得到更新数据前后的参数 w → w ′ \mathbf{w}\rightarrow \mathbf{w'} w→w′之间的关系, 避免一次次重新计算逆矩阵 ( X T X ) − 1 (X^TX)^{-1} (XTX)−1, 就是RLS算法的主要动机.
对公式
4
{4}
4 进行分析, 定义
R
=
d
e
f
X
T
X
,
z
=
d
e
f
X
T
y
R\overset{\underset{def}{}}{=} X^TX, \mathbf{z} \overset{\underset{def}{}}{=} X^T\mathbf{{y}}
R=defXTX,z=defXTy ,则公式
4
{4}
4可改写为
w
=
R
−
1
⋅
z
(5)
\mathbf{w}=R^{-1}\cdot \mathbf{z} \tag{5}
w=R−1⋅z(5)
在发生数据更新后, 新的权重矩阵记为
w
′
\mathbf{w}'
w′ , 新数据矩阵为
X
′
X'
X′ 新矩阵
R
′
R'
R′ 公式
4
{4}
4可更新为
w
′
=
R
′
−
1
⋅
z
′
(6)
\mathbf{w'}=R'^{-1}\cdot \mathbf{z'} \tag{6}
w′=R′−1⋅z′(6)
在更新数据之后, 公式
4
{4}
4求解新权重矩阵
w
′
\mathbf{w}'
w′的主要计算量在于求逆部分
R
−
1
R^{-1}
R−1, 因此先对矩阵
R
R
R进行计算处理, 根据分块矩阵计算,可以得到更新后矩阵
R
′
R'
R′ 与更新前矩阵
R
R
R 之间的递推公式
R
′
=
X
′
T
X
′
=
[
X
T
∣
x
n
+
1
]
[
X
x
n
+
1
T
]
=
X
T
X
+
x
n
+
1
x
n
+
1
T
=
R
+
x
n
+
1
x
n
+
1
T
(7)
R' = {X'}^TX' = [X^T|\mathbf{x_{n+1}}] \begin{bmatrix} X\\ \hline {\mathbf{x_{n+1}}}^T \end{bmatrix} =X^TX+\mathbf{x_{n+1}}\mathbf{x_{n+1}}^T = R + \mathbf{x_{n+1}}\mathbf{x_{n+1}}^T \tag{7}
R′=X′TX′=[XT∣xn+1][Xxn+1T]=XTX+xn+1xn+1T=R+xn+1xn+1T(7)
在现实中, 新的数据往往比旧数据更有价值, 因此一般为公式
7
{7}
7添加遗忘因子
λ
≤
1
\lambda \leq 1
λ≤1, 这样越旧的数据在迭代过程中比重就越小, 即
R
′
=
λ
R
+
x
n
+
1
x
n
+
1
T
(8)
R'= \lambda R+\mathbf{x_{n+1}}\mathbf{x_{n+1}}^T \tag{8}
R′=λR+xn+1xn+1T(8)
公式 8 {8} 8表明了矩阵 R R R与 R ′ R' R′的迭代关系, 但是并不包含对求逆过程的处理, 我们更希望, 能够获得矩阵 R − 1 R^{-1} R−1与 R ′ − 1 {R'}^{-1} R′−1 之间的递推关系. 在计算地推关系前, 需要引入如下引理
Theorem 1 : 如果矩阵 A A A可以表示为如下形式
A = B − 1 + C D − 1 C T (9) A= B^{-1} + CD^{-1}C^T \tag{9} A=B−1+CD−1CT(9)
则逆矩阵 A − 1 A^{-1} A−1可以表示
A − 1 = B − B C ( D + C T B C ) − 1 C T B (10) A^{-1}=B-BC(D+C^TBC)^{-1}C^TB \tag{10} A−1=B−BC(D+CTBC)−1CTB(10)
将公式 9 {9} 9, 10 {10} 10相乘即可证明该引理
对比公式
8
{8}
8,
9
{9}
9令
A
=
d
e
f
R
′
,
B
=
d
e
f
(
λ
R
)
−
1
,
C
=
d
e
f
x
n
+
1
,
D
=
d
e
f
1
A\overset{\underset{def}{}}{=} R', B\overset{\underset{def}{}}{=}(\lambda R)^{-1}, C\overset{\underset{def}{}}{=} \mathbf{x_{n+1}},D \overset{\underset{def}{}}{=} 1
A=defR′,B=def(λR)−1,C=defxn+1,D=def1 则根据公式
10
{10}
10计算得到
R
′
−
1
{R'}^{-1}
R′−1 为
R
′
−
1
=
(
λ
R
)
−
1
−
(
λ
R
)
−
1
x
n
+
1
(
1
+
x
n
+
1
T
(
λ
R
)
−
1
x
n
+
1
)
−
1
x
n
+
1
T
(
λ
R
)
−
1
=
1
λ
R
−
1
−
1
λ
R
−
1
x
n
+
1
1
1
+
1
λ
x
n
+
1
T
R
−
1
x
n
+
1
x
n
+
1
T
1
λ
R
−
1
=
1
λ
R
−
1
−
1
λ
2
R
−
1
x
n
+
1
x
n
+
1
T
R
−
1
1
+
1
λ
x
n
+
1
T
R
−
1
x
n
+
1
=
1
λ
R
−
1
−
1
λ
R
−
1
x
n
+
1
x
n
+
1
T
R
−
1
λ
+
x
n
+
1
T
R
−
1
x
n
+
1
=
1
λ
R
−
1
−
1
λ
R
−
1
x
n
+
1
λ
+
x
n
+
1
T
R
−
1
x
n
+
1
x
n
+
1
T
R
−
1
(11)
{R'}^{-1} =(\lambda R)^{-1} - (\lambda R)^{-1}\mathbf{x_{n+1}}\big(1+\mathbf{x_{n+1}}^T(\lambda R)^{-1}\mathbf{x_{n+1}}\big)^{-1}\mathbf{x_{n+1}}^T(\lambda R)^{-1}\\ = \frac{1}{\lambda}R^{-1} - \frac{1}{\lambda}R^{-1}\mathbf{x_{n+1}}\frac{1}{1+\frac{1}{\lambda}\mathbf{x_{n+1}}^TR^{-1}\mathbf{x_{n+1}}}\mathbf{x_{n+1}}^T\frac{1}{\lambda}R^{-1}\\ =\frac{1}{\lambda}R^{-1} - \frac{\frac{1}{\lambda^2}R^{-1}\mathbf{x_{n+1}}\mathbf{x_{n+1}}^TR^{-1}}{1+\frac{1}{\lambda}\mathbf{x_{n+1}}^TR^{-1}\mathbf{x_{n+1}}}\\ =\frac{1}{\lambda}R^{-1} - \frac{\frac{1}{\lambda}R^{-1}\mathbf{x_{n+1}}\mathbf{x_{n+1}}^TR^{-1}}{\lambda+\mathbf{x_{n+1}}^TR^{-1}\mathbf{x_{n+1}}}\\ =\frac{1}{\lambda}R^{-1} - \frac{1}{\lambda}\frac{R^{-1}\mathbf{x_{n+1}}}{\lambda+\mathbf{x_{n+1}}^TR^{-1}\mathbf{x_{n+1}}}\mathbf{x_{n+1}}^TR^{-1} \tag{11}
R′−1=(λR)−1−(λR)−1xn+1(1+xn+1T(λR)−1xn+1)−1xn+1T(λR)−1=λ1R−1−λ1R−1xn+11+λ1xn+1TR−1xn+11xn+1Tλ1R−1=λ1R−1−1+λ1xn+1TR−1xn+1λ21R−1xn+1xn+1TR−1=λ1R−1−λ+xn+1TR−1xn+1λ1R−1xn+1xn+1TR−1=λ1R−1−λ1λ+xn+1TR−1xn+1R−1xn+1xn+1TR−1(11)
公式
11
{11}
11计算新的逆矩阵
R
′
−
1
R'^{-1}
R′−1的过程仅仅需要之前的旧的逆矩阵
R
−
1
R^{-1}
R−1 以及新添加的数据向量
x
n
+
1
\mathbf{x_{n+1}}
xn+1即可, 避免了直接求逆, 因此计算复杂度比直接求逆要小很多.
对公式
11
{11}
11作进一步简化, 令
P
′
=
d
e
f
R
′
−
1
,
P
=
d
e
f
R
−
1
P'\overset{\underset{def}{}}{=} R'^{-1},P\overset{\underset{def}{}}{=} R^{-1}
P′=defR′−1,P=defR−1, 定义增益向量
k
=
d
e
f
R
−
1
x
n
+
1
λ
+
x
n
+
1
T
R
−
1
x
n
+
1
k\overset{\underset{def}{}}{=} \frac{R^{-1}\mathbf{x_{n+1}}}{\lambda+\mathbf{x_{n+1}}^TR^{-1}\mathbf{x_{n+1}}}
k=defλ+xn+1TR−1xn+1R−1xn+1 可转变为
P
′
=
1
λ
P
−
1
λ
k
⋅
x
n
+
1
T
P
(12)
P' = \frac{1}{\lambda}P - \frac{1}{\lambda}k\cdot \mathbf{x_{n+1}}^TP \tag{12}
P′=λ1P−λ1k⋅xn+1TP(12)
需要指出的是, 对公式
12
{12}
12两侧都右乘向量
x
n
+
1
\mathbf{x}_{n+1}
xn+1恰好满足如下关系
P
′
x
n
+
1
=
1
λ
P
x
n
+
1
−
1
λ
P
x
n
+
1
x
n
+
1
T
P
x
n
+
1
λ
+
x
n
+
1
T
P
x
n
+
1
=
P
x
n
+
1
λ
+
x
n
+
1
T
P
x
n
+
1
=
k
(13)
P'\mathbf{x}_{n+1} = \frac{1}{\lambda}P\mathbf{x}_{n+1} -\frac{\frac{1}{\lambda} P\mathbf{x_{n+1}}\mathbf{x_{n+1}}^TP\mathbf{x_{n+1}}}{\lambda+\mathbf{x_{n+1}}^T P\mathbf{x_{n+1}}}\\ =\frac{P\mathbf{x_{n+1}}}{\lambda+\mathbf{x_{n+1}}^T P\mathbf{x_{n+1}}}\\ =k \tag{13}
P′xn+1=λ1Pxn+1−λ+xn+1TPxn+1λ1Pxn+1xn+1TPxn+1=λ+xn+1TPxn+1Pxn+1=k(13)
这样, 根据公式
12
{12}
12就得到了旧逆矩阵
P
P
P与更新后逆矩阵
P
′
P'
P′ 之间的递推关系; 重新表示公式
6
{6}
6为
w
′
=
P
′
⋅
z
′
(14)
\mathbf{w'}=P'\cdot \mathbf{z'} \tag{14}
w′=P′⋅z′(14)
对公式
6
{6}
6中的向量
z
′
\mathbf{z'}
z′同样利用分块矩阵计算
z
′
=
X
′
T
y
′
=
[
X
T
∣
x
n
+
1
]
[
y
y
n
+
1
]
=
X
T
y
+
x
n
+
1
y
n
+
1
=
z
+
x
n
+
1
y
n
+
1
(15)
\mathbf{z'} = {X'}^T\mathbf{{y'}} = [X^T|\mathbf{x_{n+1}}] \begin{bmatrix} \mathbf{{y}} \\ \hline {y}_{n+1} \end{bmatrix} =X^T\mathbf{{y}}+\mathbf{x_{n+1}}{y}_{n+1} = \mathbf{z}+\mathbf{x_{n+1}}{y}_{n+1} \tag{15}
z′=X′Ty′=[XT∣xn+1][yyn+1]=XTy+xn+1yn+1=z+xn+1yn+1(15)
添加遗忘因子
λ
≤
1
\lambda\leq 1
λ≤1 ,得到递推公式
z
′
=
λ
z
+
x
n
+
1
y
n
+
1
(16)
\mathbf{z'} =\lambda\mathbf{z}+\mathbf{x_{n+1}}{y}_{n+1} \tag{16}
z′=λz+xn+1yn+1(16)
结合公式
12
{12}
12,
13
{13}
13,
14
{14}
14,
16
{16}
16,进行多步推导可以得到
w
′
=
P
′
⋅
z
′
=
P
′
[
λ
z
+
x
n
+
1
y
n
+
1
]
=
λ
P
′
z
+
P
′
x
n
+
1
y
n
+
1
=
λ
[
1
λ
P
−
1
λ
k
⋅
x
n
+
1
T
P
]
z
+
P
′
x
n
+
1
y
n
+
1
=
P
z
−
k
⋅
x
n
+
1
T
P
z
+
P
′
x
n
+
1
y
n
+
1
=
P
z
−
k
⋅
x
n
+
1
T
P
z
+
k
⋅
y
n
+
1
=
w
−
k
(
x
n
+
1
T
w
−
y
n
+
1
)
(17)
\mathbf{w'} =P'\cdot \mathbf{z'}\\ =P'[\lambda\mathbf{z}+\mathbf{x_{n+1}}{y}_{n+1}] \\ =\lambda P'\mathbf{z}+P'\mathbf{x_{n+1}}{y}_{n+1}\\ =\lambda \bigg[\frac{1}{\lambda}P - \frac{1}{\lambda}k\cdot\mathbf{x_{n+1}}^T P \bigg]\mathbf{z}+ P'\mathbf{x_{n+1}}{y}_{n+1} \\ =P\mathbf{z} - k\cdot \mathbf{x_{n+1}}^T P\mathbf{z} + P'\mathbf{x_{n+1}}{y}_{n+1} \\ =P\mathbf{z} - k\cdot\mathbf{x_{n+1}}^T P\mathbf{z} + k\cdot {y}_{n+1} \\ =\mathbf{w}-k(\mathbf{x_{n+1}}^T\mathbf{w}-{y}_{n+1}) \tag{17}
w′=P′⋅z′=P′[λz+xn+1yn+1]=λP′z+P′xn+1yn+1=λ[λ1P−λ1k⋅xn+1TP]z+P′xn+1yn+1=Pz−k⋅xn+1TPz+P′xn+1yn+1=Pz−k⋅xn+1TPz+k⋅yn+1=w−k(xn+1Tw−yn+1)(17)
注意其中,
x
n
+
1
T
w
−
y
n
+
1
\mathbf{x_{n+1}}^T\mathbf{w}-{y}_{n+1}
xn+1Tw−yn+1 项中, 模型参数
w
\mathbf{w}
w是旧模型参数,如果定义
e
=
d
e
f
x
n
+
1
T
w
−
y
n
+
1
e\overset{\underset{def}{}}{=}\mathbf{x_{n+1}}^T\mathbf{w}-{y}_{n+1}
e=defxn+1Tw−yn+1 则公式
17
{17}
17可变形为
w
′
=
w
−
k
⋅
e
(18)
\mathbf{w'}=\mathbf{w}-k\cdot e \tag{18}
w′=w−k⋅e(18)
这就是RLS的最终计算目标.
RLS主要描述的是一种推理关系, 不断地在原来的旧最优模型参数上进行迭代得到最新模型参数; 那么最初进行迭代时, 需要一个初始的模型参数, 这个模型参数最好是满足最小平方和误差原则; 公式(5) 通过以上介绍, 可以改写为
w
=
P
⋅
z
(19)
\mathbf{w} = P\cdot \mathbf{z} \tag{19}
w=P⋅z(19)
其中,
z
=
d
e
f
X
T
y
\mathbf{z} \overset{\underset{def}{}}{=} X^T\mathbf{{y}}
z=defXTy 可通过已有样本计算得出, 初始的
P
P
P 一般取
P
=
k
⋅
I
(20)
P=k\cdot I \tag{20}
P=k⋅I(20)
同时, 初始
k
k
k取一个较大的数(保证
P
P
P不会在递归过程中减小为负).
RLS主要是在误差平方和最小的原则基础上, 提出一种解析的拟合模型参数 w \mathbf{w} w的迭代递推公式; 可以实现在新的样本数据到来时, 利用新的样本数据以及旧的最优模型参数来便捷地计算新的满足最小二乘最优模型参数, 从而避免直接计算方法中的逆矩阵运算.
[1] [知识梳理-04] Recursive Least Squares 递归最小二乘法 RLS_哔哩哔哩_bilibili
[2] 线性回归与递归最小二乘算法 (R.L.S algorithm) - 简书 (jianshu.com)
[3] 还有一个忘记了
假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
我有一个随机大小的散列,它可能有类似"100"的值,我想将其转换为整数。我知道我可以使用value.to_iifvalue.to_i.to_s==value来做到这一点,但我不确定我将如何在我的散列中递归地做到这一点,考虑到一个值可以是一个字符串,或一个数组(哈希或字符串),或另一个哈希。 最佳答案 这是一个非常简单的递归实现(尽管必须同时处理数组和散列会增加一些技巧)。deffixnumifyobjifobj.respond_to?:to_i#IfwecancastittoaFixnum,doit.obj.to_ielsifobj
我经常迷上ruby的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情
有没有人用ruby解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi
我有这个ruby代码:defget_sumnreturn0ifn似乎正在为999之前的值工作。当我尝试9999时,它给了我这个:stackleveltoodeep(SystemStackError)所以,我添加了这个:RubyVM::InstructionSequence.compile_option={:tailcall_optimization=>true,:trace_instruction=>false}但什么也没发生。我的ruby版本是:ruby1.9.3p392(2013-02-22revision39386)[x86_64-darwin12.2.1]我还增加了机器的堆栈大
构建一个深度优先的网络蜘蛛,这意味着它将访问第一页上的所有链接,然后转到每个链接,并访问所有第二页上的链接...你应该使用递归吗?我发现这是CPU密集型的。defrecursion()linkz_on_first_page.eachdo|link|recursion(link)endendrecursion(firstpage) 最佳答案 绝对不是,由于万维网的实际性质,您很快就会遇到问题。当您访问带有主导航部分的网站时,每个页面都链接到其他页面,您就进入了一个无限循环。您可以跟踪您处理了哪些链接,但即便如此,递归循环并不真正适合万
例如,如果我有YAML文件en:questions:new:'NewQuestion'other:recent:'Recent'old:'Old'这最终会变成一个json对象,例如{'questions.new':'NewQuestion','questions.other.recent':'Recent','questions.other.old':'Old'} 最佳答案 由于问题是关于在Rails应用程序上使用YAML文件进行i18n,因此值得注意i18ngem提供了一个辅助模块I18n::Backend::Flatten完全像
看来我正在回顾SO帖子中采取的步骤:Capybara,PoltergeistandPhantomjsandgivinganemptyresponseinbody.(如果你愿意,可以将其标记为重复,但我包含了一个最小的独立测试用例和版本号。)问题我做错了什么吗?我可以运行另一个可能有助于隔离问题的最小测试吗?文件:pgtest.rbrequire'rubygems'require'capybara'require'capybara/dsl'require'capybara/poltergeist'modulePGTestincludeCapybara::DSLextendselfdeft
我有这两个gcd函数的实现:defgcd1(a,b)ifa==baelsifa>bif(a%b)==0belsegcd1(a%b,b)endelseif(b%a)==0aelsegcd1(a,b%a)endendenddefgcd2(a,b)if(a==b)returnaelsifb>amin,max=a,belsemin,max=b,aendwhile(max%min)!=0min,max=max%min,minendminend函数gcd1是尾递归的,而gcd2使用while循环。我已经验证rubinius通过对阶乘函数进行基准测试来执行TCO,只有阶乘函数基准测试显示递归版本和迭