0Pricing
Pandas & NumPy Academy · レッスン

連立一次方程式を解く

np.linalg.solveでAx=bを解き、単純な逆行列の乗算による方法と数値的安定性を比較します。

「連立一次方程式を解く」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

連立一次方程式とは

連立一次方程式は、Ax = bという行列形式で表せます。ここでAは係数行列、xは未知数のベクトル、bは右辺ベクトルです。たとえば、未知数2つの方程式2本は、2×2行列の方程式として表せます。連立方程式を解くとは、Aにxを掛けるとbになるようなxを求めることです。NumPyのnp.linalg.solve(A, b)は、この計算を効率的かつ正確に処理します。

import numpy as np

# System: 2x + y = 5
#         x + 3y = 10
A = np.array([[2.0, 1.0],
              [1.0, 3.0]])
b = np.array([5.0, 10.0])

x = np.linalg.solve(A, b)
print('Solution x:', x)
print('Verify A @ x == b:', np.allclose(A @ x, b))

逆行列を使わない理由

数学的には、Ax = bの解はx = A⁻¹bです。しかし、np.linalg.inv(A) @ bを計算するよりも、np.linalg.solve(A, b)を直接呼び出すほうが高速で正確です。solve()は内部でLU分解を使用するため、必要な演算回数が少なく、浮動小数点誤差も蓄積しにくくなります。基本的なルールとして、Ax=bからxを求める場合は、必ずsolveを使い、invは使わないでください。

import numpy as np

A = np.random.rand(100, 100)
b = np.random.rand(100)

# Avoid this pattern
x_inv = np.linalg.inv(A) @ b

# Prefer this
x_solve = np.linalg.solve(A, b)

print('Max difference:', np.max(np.abs(x_inv - x_solve)))
# solve is faster AND more accurate

solve()の要件

np.linalg.solve(A, b)を使うには、Aが正方かつ非特異である必要があります。Aが特異(行列式が0)であれば、この関数はnp.linalg.LinAlgError: Singular matrixを発生させます。たとえば、ある方程式が別の方程式の定数倍になっている場合のように、行が線形従属であるとAは特異になります。solveを呼び出す前に、連立方程式が適切に定義されていることを必ず確認してください。Aが正方でない場合は、代わりにnp.linalg.lstsq()を使用します。

import numpy as np

# Well-posed system
A = np.array([[1.0, 2.0], [3.0, 4.0]])
b = np.array([5.0, 6.0])
print('Solution:', np.linalg.solve(A, b))

# Singular system (row 2 = 3 * row 1)
A_singular = np.array([[1.0, 2.0], [3.0, 6.0]])
try:
    np.linalg.solve(A_singular, b)
except np.linalg.LinAlgError as e:
    print('Error:', e)

内部で行われるLU分解

np.linalg.solveは内部でLU分解を適用します。つまり、Aを下三角行列Lと上三角行列Uに分解し、A = LUとします。すると、解を求める処理は、前進代入と後退代入という2つの単純な三角行列の求解になります。これは、ガウス消去を最初から繰り返すよりもはるかに効率的です。同じアルゴリズムが、MATLAB、FortranのLAPACK、そしてほぼすべての科学計算ライブラリで使われています。

import numpy as np
from scipy import linalg

A = np.array([[2.0, 1.0, -1.0],
              [-3.0, -1.0, 2.0],
              [-2.0, 1.0, 2.0]])
b = np.array([8.0, -11.0, -3.0])

# NumPy solve (uses LAPACK dgesv under the hood)
x = np.linalg.solve(A, b)
print('Solution:', x)
print('Check:', np.allclose(A @ x, b))

複数の右辺を持つ連立方程式を解く

np.linalg.solve(A, B)は、複数の列を持つ行列Bを処理し、各列に対する解を同時に求められます。Bの形状が(n, k)の場合、結果Xの形状も(n, k)になります。Xの各列は、Bの対応する列に対する解です。これは、同じ係数行列に対して異なる右辺を多数解く必要がある物理シミュレーションや機械学習で役立ちます。

import numpy as np

A = np.array([[3.0, 1.0],
              [1.0, 2.0]])

# Three right-hand side vectors at once
B = np.array([[9.0, 3.0, 6.0],
              [8.0, 4.0, 2.0]])

X = np.linalg.solve(A, B)
print('Solutions X shape:', X.shape)  # (2, 3)
print('Verify A @ X == B:', np.allclose(A @ X, B))

np.linalg.lstsq()による最小二乗法

連立方程式が過剰決定(未知数より方程式の数が多い)である場合、厳密な解は存在しません。np.linalg.lstsq(A, b)は、残差平方和||Ax - b||²を最小にするxを求めます。これは線形回帰が実際に計算しているものです。この関数は、解x、残差、ランク、特異値を返します。rcond=None引数は非推奨警告を抑制し、特異値を0として扱うためのしきい値を設定します。

import numpy as np

# Over-determined: 4 equations, 2 unknowns
A = np.array([[1.0, 1.0],
              [1.0, 2.0],
              [1.0, 3.0],
              [1.0, 4.0]])
b = np.array([2.0, 2.5, 3.5, 4.5])

x, residuals, rank, sv = np.linalg.lstsq(A, b, rcond=None)
print('Least-squares solution:', x)
print('Residuals:', residuals)
print('Rank:', rank)

線形回帰でsolve()を適用する

通常の最小二乗法の正規方程式はA.T @ A @ x = A.T @ bであり、np.linalg.solveで解ける正方行列の連立方程式です。A.T @ Aの条件が良好であれば、lstsqと同じ結果になります。実際には、lstsqはSVDを使用し、列がほぼ共線である場合でも安定しているため、こちらが推奨されます。ただし、正規方程式を知ることで、回帰の背後にある数学を理解できます。

import numpy as np

np.random.seed(0)
X = np.column_stack([np.ones(50), np.random.rand(50) * 10])
y = 3.0 + 2.0 * X[:, 1] + np.random.randn(50)

# Solve normal equations
coeffs = np.linalg.solve(X.T @ X, X.T @ y)
print('Intercept:', round(coeffs[0], 3))
print('Slope:', round(coeffs[1], 3))

条件数を確認する

解を求める前に、np.linalg.cond(A)で条件数を確認することをおすすめします。条件数が1に近い場合、連立方程式は良条件で、解の信頼性が高くなります。条件数が非常に大きい(例:1e12)場合、行列はほぼ特異です。このとき、bの小さな変化がxの大きな変化を引き起こし、解の数値的な信頼性が低くなる可能性があります。その場合は、正則化(リッジ回帰)を行うか、より堅牢なソルバーを使用することを検討してください。

import numpy as np

# Well-conditioned
A1 = np.array([[2.0, 1.0], [1.0, 3.0]])
print('Condition number (well):', np.linalg.cond(A1))

# Ill-conditioned (nearly linearly dependent rows)
A2 = np.array([[1.0, 1.0], [1.0, 1.0001]])
print('Condition number (ill):', np.linalg.cond(A2))

疎行列の連立方程式:linalgを使わない場合

Aのほとんどの要素が0である非常に大規模な疎行列の連立方程式では、行列全体を保存するとメモリを無駄に使い、密行列用のnp.linalg.solveも低速になります。SciPyにはscipy.sparseとscipy.sparse.linalg.spsolveが用意されており、疎性を利用して、有限要素モデルやネットワーク問題のような巨大な連立方程式を処理できます。行列が疎行列かどうかを判断することは、科学計算における重要な性能上の考慮事項です。

import numpy as np

# Dense solve is fine for small-to-medium systems
A = np.random.rand(200, 200)
b = np.random.rand(200)
x = np.linalg.solve(A, b)
print('Dense solve OK, solution shape:', x.shape)

# For large sparse systems, use scipy.sparse.linalg.spsolve instead
# from scipy.sparse.linalg import spsolve
# x = spsolve(A_sparse, b)

解ベクトルを解釈する

np.linalg.solve(A, b) で解ベクトル x を求めたら、必ず 検証してください。A @ x を計算し、np.allclose(A @ x, b) を使って b と比較します。浮動小数点演算では、完全に等しくなることはほとんどありません。allclose は、小さな許容誤差の範囲内で一致しているかを確認します。条件のよいシステムでは、残差 ||Ax - b|| は、問題のスケールにマシンイプシロンを掛けた値に近くなるはずです。

import numpy as np

A = np.array([[4.0, 3.0, 2.0],
              [1.0, 5.0, 3.0],
              [2.0, 1.0, 6.0]])
b = np.array([10.0, 20.0, 15.0])

x = np.linalg.solve(A, b)
print('Solution:', np.round(x, 4))

# Residual check
residual = np.linalg.norm(A @ x - b)
print('Residual ||Ax - b||:', residual)
print('Valid:', np.allclose(A @ x, b))

機械学習パイプラインでの解法

線形ソルバーは機械学習のさまざまな場面で使われています。線形回帰では正規方程式を解き、ガウス過程ではカーネル行列の連立方程式を解き、カルマンフィルターでは状態更新方程式を解きます。np.linalg.solve と lstsq を理解すれば、これらのアルゴリズムをゼロから実装し、結果が予想外になったときにデバッグできるようになります。NumPy の linalg モジュールには、実運用の科学技術計算ライブラリで使われているものと同じ数値計算ツールが用意されています。

import numpy as np

# Ridge regression: (X.T @ X + lambda * I) @ w = X.T @ y
np.random.seed(42)
X = np.random.rand(100, 5)
y = np.random.rand(100)
lambda_reg = 0.1
n_features = X.shape[1]

A = X.T @ X + lambda_reg * np.eye(n_features)
bvec = X.T @ y
w = np.linalg.solve(A, bvec)
print('Ridge regression weights:', np.round(w, 4))

理解度チェック

このレッスンで扱ったデータ分析の概念について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、np.linalg.solve(A, b) が LU 分解を使って正方線形システムを効率的に解くこと、np.linalg.lstsq() が過剰決定系に対する最小二乗解を求めること、そして条件数が数値的な安定性を示し、大きな値はほぼ特異な行列であることを警告することを学びました。次は、PCA や多くの ML アルゴリズムの基盤となる固有値と SVD について学びます。

よくある質問

「連立一次方程式を解く」レッスンは無料ですか?

はい。「連立一次方程式を解く」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「連立一次方程式を解く」で何を学びますか?

np.linalg.solveでAx=bを解き、単純な逆行列の乗算による方法と数値的安定性を比較します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「連立一次方程式を解く」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. np.matmulと@による行列の乗算
  2. 行列式、逆行列、転置行列
  3. 連立一次方程式を解く
  4. 固有値とSVDの概要
← Pandas & NumPy Academyに戻る