STLSQとは何か?
アルゴリズム
STLSQ
フルランクの行列 と が与えられたとき、割と スパース な を見つけるスパース回帰問題を考えよう。STLSQsequentially Thresholded Least-Squares Algorithm は、「SINDy」Algorithm を提案したブルントンが使っていた方法で、名前の通り、 最小二乗法 を繰り返し利用し、各成分の 絶対値 が与えられたしきい値 より下がったら として扱い、その列(独立変数) を排除する仕組みになっている。
擬似コード
共通して、括弧で囲まれた上付きのテキスト は 番目を、 は から までの 自然数 の 集合 を示す。 は行列 の 擬似逆行列 であり、最小二乗法 によって得られる。インデックス集合 に対して、 はベクトル の該当インデックスだけを残したベクトル、 は行列 の該当列だけを残した行列である。
アルゴリズム: STLSQ | ||
---|---|---|
入力 | しきい値 が与えられる。 | |
1. | 実行回数 、 および を初期化する。 | |
2. | # は と同じ意味だ。 | |
3. | while do | |
4. | for do | |
5. | # 列 を削除 | |
6. | # 列を一つずつ更新 | |
7. | ||
8. | end for | |
9. | ||
10. | end while | |
11. | を満たさない全ての に対して を適用する | |
出力 | 各成分の 絶対値 の大きさが より大きい行列 を得る。 |
説明
特に STLSQ が 動的系 の微分係数から作られた行列 とライブラリ行列 に対して行われる場合、我々はそれを「SINDy」と呼ぶ1。一見するとSTLSQ自体がSINDyのために出たと言えるが、アルゴリズムの観点からはSTLSQ自体が動的系と全く関係なくそのまま作動できるため、「SINDy」という名前の代わりに言及されることもままある。
アルゴリズムの擬似コードを読めば分かるように、STLSQは一種の グリーディアルゴリズム だ。アルゴリズムの収束性が証明されたこと2とは別に、回帰分析の統計的側面から言えば正直、意味がないが、実装が簡単で収束速度が非常に速く、何はともあれ スパース回帰 を行うという点では疑いようのない有用な方法と言える。
コード
Matlab
以下は、ブルントン教授が自分の研究で使っている実際の Matlab コードだ3。
%% compute Sparse regression: sequential least squares
Xi = Theta\dXdt; % initial guess: Least-squares
% lambda is our sparsification knob.
for k=1:10
smallinds = (abs(Xi)<lambda); % find small coefficients
Xi(smallinds)=0; % and threshold
for ind = 1:n % n is state dimension
biginds = ˜smallinds(:,ind);
% Regress dynamics onto remaining terms to find sparse Xi
Xi(biginds,ind) = Theta(:,biginds)\dXdt(:,ind);
end
end
Python
def sparsifyDynamics(Theta,dXdt,lamb,n):
# Initial guess: Least-squares
Xi = np.linalg.lstsq(Theta,dXdt,rcond=None)[0]
for k in range(10):
smallinds = np.abs(Xi) < lamb # Find small coeffs.
Xi[smallinds]=0 # and threshold
for ind in range(n): # n is state dimension
biginds = smallinds[:,ind] == 0
# Regress onto remaining terms to find sparse Xi
Xi[biginds,ind] = np.linalg.lstsq(Theta[:,
biginds],dXdt[:,ind],rcond=None)[0]
return Xi
Julia
私が使っている Julia コードだ。
using SparseArrays
function STLSQ(Θ, dXdt, λ = 10^(-6))
if Θ isa AbstractSparseMatrix
Θ = Matrix(Θ)
end
Ξ = Θ \ dXdt
dim = size(Ξ, 2)
__🚫 = 0
while true
print(".")
🚫 = abs.(Ξ) .< λ
Ξ[🚫] .= 0
for j in 1:dim
i_ = .!🚫[:, j]
Ξ[i_, j] = Θ[:,i_] \ dXdt[:,j]
end
if __🚫 == 🚫 println("Stopped!"); break end # Early stopping
__🚫 = deepcopy(🚫)
end
println("MSE: ", sum(abs2, Θ * Ξ - dXdt) / length(dXdt))
return Ξ
end
Brunton. (2016). Discovering governing equations from data by sparse identification of nonlinear dynamical systems: https://doi.org/10.1073/pnas.1517384113 ↩︎
Zhang, L., & Schaeffer, H. (2019). On the convergence of the SINDy algorithm. Multiscale Modeling & Simulation, 17(3), 948-972. https://doi.org/10.1137/18M1189828 ↩︎
https://www.pnas.org/doi/suppl/10.1073/pnas.1517384113/suppl_file/pnas.1517384113.sapp.pdf ↩︎
Brunton. (2022). Data-Driven Science and Engineering : Machine Learning, Dynamical Systems, and Control(2nd Edition): p276. ↩︎