- 技術 💻
逆行列とは|求め方(2×2公式・掃き出し法・余因子)をPythonで検算
結論
逆行列とは、掛けると単位行列 I になる行列で、A⁻¹ と書きます。行列式が0でない正方行列にだけあります。
この記事でわかること
- 2×2の公式と、3×3の掃き出し法の全7手順
- 余因子9個の計算と、NumPy・SymPyでの検算
- solveがinvより4〜5倍速い実測とエラー原文
逆行列は「数の逆数」を行列に広げたものです。3 × (1/3) = 1 と同じように、A × A⁻¹ = I(単位行列)になります。ただし、行列式が0の行列には逆行列がありません。
flowchart TD
A[正方行列 A] --> B{行列式 det A は 0 か}
B -->|0 でない| C[逆行列 A⁻¹ がある<br>A A⁻¹ = A⁻¹ A = I]
B -->|0| D[逆行列はない<br>特異行列]
C --> E[連立方程式は<br>solve で解く]
D --> F[擬似逆行列 pinv で<br>最小二乗の解]
急いでいる人向けに、よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| 2×2 の公式 | (1/(ad−bc)) × [[d, −b], [−c, a]] | 2×2 |
| 3×3 の求め方 | [A|I] を掃き出して [I|A⁻¹] にする | 掃き出し法 |
| 存在する条件 | 行列式 ≠ 0(=正則行列) | 存在条件 |
| 検算のしかた | A × A⁻¹ が単位行列になるか | 2×2 |
| (AB)⁻¹ | B⁻¹A⁻¹(順番が逆になる) | 性質 |
| Python で1行 | np.linalg.inv(A) |
Python |
| 連立方程式なら | inv より np.linalg.solve(A, b) |
solve |
| 正方でない・特異なら | 擬似逆行列 np.linalg.pinv(A) |
擬似逆行列 |
確認環境:Ubuntu 24.04・Python 3.11.15・NumPy 2.4.6・SciPy 1.17.1・SymPy 1.14.0(BLAS は OpenBLAS 0.3.31、速さの計測は1スレッド)。3×3 の掃き出し法の各手順と余因子9個を分数のまま計算して出力し、NumPy の inv・solve・pinv・cond、SymPy の inv、自作の掃き出し法の関数で同じ答えになることを確かめました。inv と solve の速さと誤差(100〜4000次)、特異行列のエラー原文、ヒルベルト行列で条件数と誤差が増える様子、擬似逆行列と最小二乗法の一致も実行し、出力をそのまま載せています。関数の仕様は NumPy(2.5 のマニュアル)・SciPy・SymPy の公式ドキュメントで、定義と性質は Wikipedia「逆行列」「擬似逆行列」・英語版 Wikipedia「Invertible matrix」「Moore–Penrose inverse」で確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「逆行列とは|求め方(2×2公式・掃き出し法・余因子)をPythonで検算」
逆行列とは(意味を数の逆数と図で)
この節では、逆行列が「何を元に戻す行列なのか」が分かります。
正方行列 A に対して、A X = X A = I(単位行列)を満たす行列 X を A の逆行列と呼び、A⁻¹(エー・インバース)と書きます。 英語では inverse matrix です。逆行列を持つ行列を正則行列(せいそくぎょうれつ)、または可逆行列と呼びます。
単位行列 I は、対角線が1で、ほかが0の正方行列です。数の「1」と同じで、どんな行列に掛けても相手を変えません(A I = I A = A)。
| 数の世界 | 行列の世界 |
|---|---|
| 1 | 単位行列 I |
| 3 の逆数 1/3(3 × 1/3 = 1) | A の逆行列 A⁻¹(A A⁻¹ = I) |
| 0 には逆数がない | 行列式が0の行列には逆行列がない |
| 3x = 6 なら x = 6 ÷ 3 | A x = b なら x = A⁻¹ b |
| 割り算 | 行列の割り算は無い。逆行列を掛ける |
行列を「ベクトルを別のベクトルに移す変換」と見ると、逆行列は「移したものを元に戻す変換」です。A = [[2, 1], [4, 3]] で確かめます。
flowchart TD
X[ベクトル x<br>例 1, 3] -->|A を掛ける| Y[ベクトル y = A x<br>例 5, 13]
Y -->|A⁻¹ を掛ける| Z[元の x に戻る<br>1, 3]
A は (1, 0) を (2, 4) に、(0, 1) を (1, 3) に移します。(1, 3) は (5, 13) に移り、A⁻¹ を掛けると (1, 3) に戻ります。この「元に戻す」ができない変換に、逆行列はありません(次の節)。
逆行列が使われる場面
1連立方程式を解く
A x = b を x = A⁻¹ b と書ける。数式で解の形を表すときの基本。プログラムで解くときは solve を使う。
2最小二乗法・回帰
回帰の係数は (XᵀX)⁻¹Xᵀy で表せる(正規方程式)。正方でない X には擬似逆行列を使う。
33D・ゲーム・画像
回転・拡大・移動の変換を元に戻す。カメラの座標からワールド座標へ戻す計算や、画像の射影変換の逆変換。
4統計・機械学習
多変量正規分布の式に共分散行列の逆行列が出る。マハラノビス距離、カルマンフィルター、ガウス過程など。
逆行列が存在する条件(行列式・正則・特異)
この節では、逆行列が「ある・ない」の見分け方と、行列式が0だと逆行列がない理由が分かります。
正方行列 A に逆行列があるのは、行列式 det A が0でないときだけです。 行列式が0の行列を特異行列(とくいぎょうれつ、singular matrix)と呼びます。正方でない行列(2×3 など)には、ふつうの逆行列はありません。
行列式が0だと逆行列がない理由
S = [[1, 2], [2, 4]] は、2行目が1行目のちょうど2倍で、行列式は 1×4 − 2×2 = 0 です。いくつかのベクトルを S で移しました。
[1, 0] -> [1 2]
[0, 1] -> [2 4]
[3, 0] -> [3 6]
[1, 1] -> [3 6]
[-1, 2] -> [3 6]
(3, 0)・(1, 1)・(−1, 2) という別々のベクトルが、どれも (3, 6) に移りました。 S は平面全体を直線 y = 2x の上に押しつぶすので、(3, 6) を見ても元がどれだったかを決められません。これが「元に戻す行列(逆行列)が作れない」ということです。
零行列 O(成分が全部0)も、すべてのベクトルを0に移すので逆行列がありません。np.linalg.inv(np.zeros((2, 2))) も LinAlgError: Singular matrix でした。
行列式は、変換で面積(3×3 なら体積)が何倍になるかを表します。A = [[2, 1], [4, 3]] の行列式は 2 で、面積を2倍にします。行列式が0の変換は、面積を0に押しつぶします。
逆行列があることと同じ意味の条件
次の条件は、n×n の正方行列ではどれも同じ意味です(英語版 Wikipedia「Invertible matrix」の一覧から主なもの)。どれか1つを確かめれば、逆行列があるかどうかが分かります。
| 条件 | 確かめ方の例 | S = [[1,2],[2,4]] |
|---|---|---|
| 行列式が0でない | np.linalg.det(A) |
0.0 |
| 階数(ランク)が n | np.linalg.matrix_rank(A) |
1 |
| 行基本変形で単位行列にできる | 掃き出し法で途中に0の行が出ない | 2行目が全部0になる |
| A x = b の解がちょうど1つ | どの b でも解が1つに決まる | 解なし、または無数 |
| A x = 0 の解が x = 0 だけ | 列(行)が1次独立 | x = (2, −1) も解 |
| 0 が固有値でない | np.linalg.eigvals(A) |
固有値に0がある |
2×2の逆行列の公式
この節では、2×2 の逆行列を一発で出す公式と、計算の例・検算のしかたが分かります。
A = [[a, b], [c, d]] で ad − bc ≠ 0 のとき、A⁻¹ = (1/(ad − bc)) × [[d, −b], [−c, a]] です。 覚え方は「a と d を入れ替え、b と c の符号を変えて、行列式で割る」です。
A = | a b | A⁻¹ = 1 | d −b |
| c d | ――――――― | −c a |
ad − bc
A = [[2, 1], [4, 3]] で計算します。
行列式を求める
ad − bc = 2×3 − 1×4 = 2。0でないので逆行列がある。
入れ替えて符号を変える
a と d を入れ替え、b と c の符号を変えると [[3, −1], [−4, 2]]。
行列式で割る
各成分を2で割って A⁻¹ = [[3/2, −1/2], [−2, 1]]。
検算する
A A⁻¹ の1行1列は 2×3/2 + 1×(−2) = 1、1行2列は 2×(−1/2) + 1×1 = 0。全部で単位行列になれば正しい。
NumPy と SymPy で同じ計算をすると、手計算と同じ答えになりました。
np.linalg.inv: [[ 1.5 -0.5]
[-2. 1. ]]
sympy : det 2 inv [[3/2, -1/2], [-2, 1]]
公式の「行列式で割る」から、行列式が0なら割れない=逆行列がない、ことも読み取れます。 なぜこの形になるかは、A に [[d, −b], [−c, a]] を掛けると [[ad − bc, 0], [0, ad − bc]] になることから分かります。これを ad − bc で割れば単位行列です。
3×3の逆行列の求め方①掃き出し法(行基本変形)
この節では、3×3 以上の逆行列を求めるいちばん一般的な方法、掃き出し法(ガウス・ジョルダン法)の全手順が分かります。
A の右に単位行列 I を並べた [A|I] を作り、行基本変形で左半分を単位行列にすると、右半分が A⁻¹ になります。 使ってよい操作(行基本変形)は次の3つだけです。
| 操作 | 書き方の例 | 注意 |
|---|---|---|
| ある行を0でない数で割る(掛ける) | R3 = R3 ÷ 2 | 0を掛けるのは不可 |
| ある行に、別の行の何倍かを足す(引く) | R3 = R3 − 4 × R1 | 引く行そのものは変えない |
| 2つの行を入れ替える | R1 ⇔ R2 | ピボットが0のときに使う |
例は A = [[0, 1, 2], [1, 0, 3], [4, −3, 8]] です。1行1列が0なので、行の入れ替えから始まります。Python の分数(fractions)で1手ずつ計算し、そのまま出力しました。
--- start [A | I]
[ 0 1 2 | 1 0 0 ]
[ 1 0 3 | 0 1 0 ]
[ 4 -3 8 | 0 0 1 ]
--- swap R1 <-> R2
[ 1 0 3 | 0 1 0 ]
[ 0 1 2 | 1 0 0 ]
[ 4 -3 8 | 0 0 1 ]
--- R3 = R3 - (4) x R1
[ 1 0 3 | 0 1 0 ]
[ 0 1 2 | 1 0 0 ]
[ 0 -3 -4 | 0 -4 1 ]
--- R3 = R3 - (-3) x R2
[ 1 0 3 | 0 1 0 ]
[ 0 1 2 | 1 0 0 ]
[ 0 0 2 | 3 -4 1 ]
--- R3 = R3 / 2
[ 1 0 3 | 0 1 0 ]
[ 0 1 2 | 1 0 0 ]
[ 0 0 1 | 3/2 -2 1/2 ]
--- R1 = R1 - (3) x R3
[ 1 0 0 | -9/2 7 -3/2 ]
[ 0 1 2 | 1 0 0 ]
[ 0 0 1 | 3/2 -2 1/2 ]
--- R2 = R2 - (2) x R3
[ 1 0 0 | -9/2 7 -3/2 ]
[ 0 1 0 | -2 4 -1 ]
[ 0 0 1 | 3/2 -2 1/2 ]
inverse: [['-9/2', '7', '-3/2'], ['-2', '4', '-1'], ['3/2', '-2', '1/2']]
A x Ainv = [['1', '0', '0'], ['0', '1', '0'], ['0', '0', '1']]
7回の操作で左半分が単位行列になり、右半分が逆行列です。
| −9/2 7 −3/2 | 1 | −9 14 −3 |
A⁻¹ = | −2 4 −1 | = ――― | −4 8 −2 |
| 3/2 −2 1/2 | 2 | 3 −4 1 |
手順を言葉でまとめると、1列目から順に「ピボット(対角の数)を1にする → 同じ列のほかの行を0にする」を繰り返すだけです。
[A|I] を作る
A の右に同じ大きさの単位行列を並べる。3×3 なら3行6列。
ピボットを決める
対角の位置が0なら、下の行で0でないものと入れ替える。例では1行1列が0なので R1 と R2 を入れ替えた。
ピボットを1にする
その行全体をピボットの数で割る。例の3列目では R3 を2で割った。
同じ列のほかを0にする
ほかの行から「ピボットの行 × その行の数」を引く。上の行も下の行も0にする。
次の列へ進み、検算する
全部の列が終わったら右半分が A⁻¹。A × A⁻¹ が単位行列になるかを確かめる。
途中で左半分のある行が全部0になったら、その行列には逆行列がありません。 S = [[1, 2], [2, 4]] では、R2 = R2 − 2 × R1 で2行目の左半分が [0, 0] になり、そこで止まります。逆行列があるかどうかの判定と計算を同時にできるのが、掃き出し法の強みです。
行基本変形は、どれも「基本行列」を左から掛けることと同じです。 たとえば R1 と R2 の入れ替えは、単位行列の1行目と2行目を入れ替えた行列 [[0, 1, 0], [1, 0, 0], [0, 0, 1]] を A に左から掛けることで、結果は [[1, 0, 3], [0, 1, 2], [4, −3, 8]] になりました。7回の操作の基本行列を全部掛けた積 E7 … E2 E1 が A を I にするので、その積が A⁻¹ です。[A|I] の右半分は、その積を I に掛けた結果を記録しています。
3×3の逆行列の求め方②余因子行列
この節では、行列式と余因子(よいんし)を使って逆行列を求める方法を、9個の余因子を全部計算して示します。
A⁻¹ = (1/det A) × adj A です。adj A(余因子行列)は、各成分の余因子を並べた行列を転置したものです。 2×2 の公式は、この式の2×2の場合です。
手順1:行列式を求める(サラスの方法)
A = [[0, 1, 2], [1, 0, 3], [4, −3, 8]] の行列式を、3×3 で使えるサラスの方法で計算します。
det A = 0×0×8 + 1×3×4 + 2×1×(−3) − 2×0×4 − 1×1×8 − 0×3×(−3)
= 0 + 12 − 6 − 0 − 8 − 0
= −2
手順2:余因子を9個求める
i 行 j 列の余因子 Cij は、「A から i 行と j 列を取り除いた 2×2 の行列式」に (−1)^(i+j) を掛けたものです。符号は市松模様(+ − + / − + − / + − +)になります。SymPy で1つずつ出力しました。
det A = -2
C11 = (-1)^2 x det[[0, 3], [-3, 8]] = 9
C12 = (-1)^3 x det[[1, 3], [4, 8]] = 4
C13 = (-1)^4 x det[[1, 0], [4, -3]] = -3
C21 = (-1)^3 x det[[1, 2], [-3, 8]] = -14
C22 = (-1)^4 x det[[0, 2], [4, 8]] = -8
C23 = (-1)^5 x det[[0, 1], [4, -3]] = 4
C31 = (-1)^4 x det[[1, 2], [0, 3]] = 3
C32 = (-1)^5 x det[[0, 2], [1, 3]] = 2
C33 = (-1)^6 x det[[0, 1], [1, 0]] = -1
cofactor matrix: [[9, 4, -3], [-14, -8, 4], [3, 2, -1]]
adj A (transpose): [[9, -14, 3], [4, -8, 2], [-3, 4, -1]]
A^-1 = adj/det: [[-9/2, 7, -3/2], [-2, 4, -1], [3/2, -2, 1/2]]
手順3:転置して行列式で割る
余因子を並べた行列 [[9, 4, −3], [−14, −8, 4], [3, 2, −1]] を転置(行と列を入れ替え)すると adj A です。転置を忘れるのがいちばん多い間違いです。 adj A を det A = −2 で割ると、掃き出し法と同じ A⁻¹ = [[−9/2, 7, −3/2], [−2, 4, −1], [3/2, −2, 1/2]] になりました。
掃き出し法と余因子、どちらを使うか
掃き出し法(ガウス・ジョルダン法)
4×4 以上でも同じ手順で進められる
逆行列が無いことも途中で分かる
計算の量は n³ に比例し、コンピューターの方法の土台
分数が途中で出やすく、写し間違いに注意
余因子行列
逆行列の各成分を式で書ける(理論・証明向き)
3×3 なら 2×2 の行列式9個で済み、分数が最後まで出ない
4×4 では 3×3 の行列式が16個必要で、急に大変になる
転置と符号の付け忘れが起きやすい
| 状況 | 選ぶ方法 |
|---|---|
| 2×2 | 公式(余因子の2×2版) |
| 3×3 を手で、分数を避けたい | 余因子行列 |
| 3×3 を手で、逆行列があるか分からない | 掃き出し法 |
| 4×4 以上を手で | 掃き出し法 |
| プログラムで数値を求める | np.linalg.inv(中身は LU 分解) |
| プログラムで分数のまま求める | SymPy の Matrix(A).inv() |
| 連立方程式を解きたい | 逆行列を作らず np.linalg.solve |
Wikipedia「逆行列」は、クラメルの公式(行列式を使う方法)は理論上は重要だが、逆行列の数値計算には向かない、と書いています。
逆行列の性質(公式一覧)
この節では、逆行列の計算でよく使う性質と、それが成り立つことを NumPy で確かめた結果が分かります。
| 性質 | 式 | 実行結果 |
|---|---|---|
| 積の逆行列 | (AB)⁻¹ = B⁻¹A⁻¹ | True(A⁻¹B⁻¹ とは False) |
| 転置の逆行列 | (Aᵀ)⁻¹ = (A⁻¹)ᵀ | True |
| 複素行列の随伴(共役転置) | (Aᴴ)⁻¹ = (A⁻¹)ᴴ | True(2×2 の複素行列) |
| 逆行列の逆行列 | (A⁻¹)⁻¹ = A | True |
| 定数倍 | (kA)⁻¹ = (1/k) A⁻¹ | True(k = 3) |
| 行列式 | det(A⁻¹) = 1 / det A | −0.4999999999999997 と −0.5 |
| 左右どちらから掛けても I | A⁻¹A = AA⁻¹ = I | True・True |
| 対角行列 | 対角成分の逆数を並べる | diag(2, 4, 5) → 0.5・0.25・0.2 |
| 回転行列 | 逆行列は転置と同じ | True |
| 冪零行列 N(Nⁿ = O) | (I − N)⁻¹ = I + N + … + Nⁿ⁻¹ | True(3×3 で I + N + N²) |
import numpy as np
inv = np.linalg.inv
A = np.array([[0, 1, 2], [1, 0, 3], [4, -3, 8.]])
B = np.array([[2, 1, 0], [1, 3, 1], [0, 1, 4.]])
print(np.allclose(inv(A @ B), inv(B) @ inv(A))) # True
print(np.allclose(inv(A @ B), inv(A) @ inv(B))) # False(順番が逆だと成り立たない)
print(np.allclose(inv(A.T), inv(A).T)) # True
(AB)⁻¹ は B⁻¹A⁻¹ で、掛ける順番が逆になります。 「靴下を履いてから靴を履いたら、脱ぐときは靴が先」と同じで、後からした変換を先に戻すためです。行列の積は順番を入れ替えると結果が変わるので、A⁻¹B⁻¹ では成り立ちませんでした。
行列式は 1/det A と一致しますが、浮動小数点の計算なので −0.5 ではなく −0.4999999999999997 と出ました。小数の比較は == ではなく np.allclose で行います。
逆行列で連立方程式を解く
この節では、連立方程式を行列で書き、逆行列で解く方法が分かります。
連立方程式は A x = b と書けます。A に逆行列があれば、両辺に左から A⁻¹ を掛けて x = A⁻¹ b です。 次の3元連立方程式を解きます。
y + 2z = 5 | 0 1 2 | | x | | 5 |
x + 3z = 7 → | 1 0 3 | | y | = | 7 |
4x − 3y + 8z = 15 | 4 −3 8 | | z | | 15 |
係数の行列は、前の節で逆行列を求めた A そのものです。A⁻¹ に b を掛けます。
x = −9/2 × 5 + 7 × 7 − 3/2 × 15 = −22.5 + 49 − 22.5 = 4
y = −2 × 5 + 4 × 7 − 1 × 15 = −10 + 28 − 15 = 3
z = 3/2 × 5 − 2 × 7 + 1/2 × 15 = 7.5 − 14 + 7.5 = 1
NumPy でも同じ答えになりました。
A = np.array([[0, 1, 2], [1, 0, 3], [4, -3, 8]])
b = np.array([5, 7, 15])
print(np.linalg.solve(A, b)) # [4. 3. 1.]
print(np.linalg.inv(A) @ b) # [4. 3. 1.]
2元連立方程式 2x + y = 5、4x + 3y = 13 も、2×2 の公式の例 A = [[2, 1], [4, 3]] で x = 1、y = 3 になりました(np.linalg.solve(B, [5, 13]) → [1. 3.])。
数式の上では x = A⁻¹ b ですが、プログラムで解くときは逆行列を作らずに solve を使います。 理由は後の節「inv より solve がよい理由」で実測します。
Pythonで逆行列を求める(NumPy・SymPy)
この節では、NumPy で逆行列を求めて検算するコードと、分数のまま求める方法が分かります。
import numpy as np
A = np.array([[0, 1, 2], [1, 0, 3], [4, -3, 8]])
Ai = np.linalg.inv(A) # 逆行列
print(Ai, Ai.dtype)
print(A @ Ai) # 検算(単位行列になるか)
print(np.allclose(A @ Ai, np.eye(3))) # True なら正しい
print(np.linalg.det(A), np.linalg.matrix_rank(A), np.linalg.cond(A))
[[-4.5 7. -1.5]
[-2. 4. -1. ]
[ 1.5 -2. 0.5]] float64
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
True
-2.0 3 99.38723879785424
整数の行列を渡しても、結果は小数(float64)で返ります。行列式 −2.0・階数 3・条件数 99.4 も一緒に確かめておくと、逆行列が信用できるかが分かります(条件数は後の節)。
| やりたいこと | 書き方 | 備考 |
|---|---|---|
| 逆行列 | np.linalg.inv(A) |
正方行列だけ |
| 連立方程式 A x = b | np.linalg.solve(A, b) |
逆行列を作らない |
| 擬似逆行列 | np.linalg.pinv(A) |
正方でなくてよい |
| 最小二乗の解 | np.linalg.lstsq(A, b) |
解が無い・無数でも使える |
| 行列式・階数・条件数 | det・matrix_rank・cond |
逆行列の前の確認 |
| 逆行列の2乗など | np.linalg.matrix_power(A, -2) |
負の指数は逆行列 |
| 分数のまま | sympy.Matrix(A).inv() |
手計算の答え合わせ向き |
| 小数を分数で見る | Fraction(x).limit_denominator() |
標準ライブラリ fractions |
手計算の答え合わせには、SymPy が分数のまま出すので便利です。
import sympy as sp
A = sp.Matrix([[0, 1, 2], [1, 0, 3], [4, -3, 8]])
print(A.det()) # -2
print(A.inv()) # Matrix([[-9/2, 7, -3/2], [-2, 4, -1], [3/2, -2, 1/2]])
print(A.adjugate()) # 余因子行列 Matrix([[9, -14, 3], [4, -8, 2], [-3, 4, -1]])
print(sp.Matrix.hstack(A, sp.eye(3)).rref()[0]) # [A | I] を掃き出した結果
NumPy の結果を分数で見るなら、標準ライブラリの fractions.Fraction(x).limit_denominator() を使います。上の Ai は [['-9/2', '7', '-3/2'], ['-2', '4', '-1'], ['3/2', '-2', '1/2']] と表示できました。配列の作り方や @(行列の積)の書き方は、関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。
掃き出し法を Python で書く(コピペで使える完成版)
ライブラリを使わずに、掃き出し法をそのまま書いた関数です。対角の数が0に近いと誤差が大きくなるので、各列で絶対値が最大の行と入れ替える「部分ピボット選択」を入れています。
def inverse(a, eps=1e-12):
"""正方行列 a(リストのリスト)の逆行列を、掃き出し法(部分ピボット選択つき)で返す。"""
n = len(a)
if any(len(row) != n for row in a):
raise ValueError("正方行列ではありません")
# [A | I] を作る
m = [list(map(float, row)) + [1.0 if i == j else 0.0 for j in range(n)]
for i, row in enumerate(a)]
for c in range(n):
# c 列目で絶対値が最大の行をピボットにして入れ替える(部分ピボット選択)
p = max(range(c, n), key=lambda r: abs(m[r][c]))
if abs(m[p][c]) < eps:
raise ValueError("逆行列はありません(特異行列)")
m[c], m[p] = m[p], m[c]
piv = m[c][c]
m[c] = [v / piv for v in m[c]] # ピボットを 1 にする
for r in range(n): # ほかの行の c 列目を 0 にする
if r != c and m[r][c] != 0.0:
k = m[r][c]
m[r] = [x - k * y for x, y in zip(m[r], m[c])]
return [row[n:] for row in m] # 右半分が逆行列
if __name__ == "__main__":
A = [[0, 1, 2], [1, 0, 3], [4, -3, 8]]
for row in inverse(A):
print(row)
try:
inverse([[1, 2], [2, 4]])
except ValueError as e:
print("ValueError:", e)
[-4.5, 7.0, -1.5]
[-2.0, 4.0, -1.0]
[1.5, -2.0, 0.5]
ValueError: 逆行列はありません(特異行列)
乱数の行列で NumPy の inv と比べると、差は最大でも 1e-13 程度(計算機の丸め誤差)で一致しました。速さは、3×3 では自作の方が速く、大きくなるほど NumPy が大きく上回りました。
n= 3 maxdiff 8.9e-16 pure python 0.05 ms numpy 0.089 ms
n= 10 maxdiff 7.8e-14 pure python 0.16 ms numpy 0.028 ms
n= 50 maxdiff 1.3e-13 pure python 11.06 ms numpy 0.162 ms
n=100 maxdiff 2.5e-14 pure python 87.35 ms numpy 0.593 ms
n=200 maxdiff 1.5e-14 pure python 764.00 ms numpy 2.479 ms
200×200 で約300倍の差です。仕組みを学ぶには自作、使うときは NumPy、と分けます。
inv より solve がよい理由(速さと誤差の実測)
この節では、連立方程式を inv(A) @ b ではなく solve(A, b) で解く理由が、速さと誤差の実測で分かります。
solve は逆行列を作らずに LU 分解で直接解くので、inv で逆行列を作ってから掛けるより速く、誤差も小さくなります。 NumPy のドキュメントは、solve は LAPACK の _gesv で計算すると書いています。英語版 Wikipedia「Invertible matrix」も、多くの実用の場面では連立方程式を解くのに逆行列は要らない、と書いています。
乱数の n×n 行列で、右辺 b が1本の連立方程式を解く時間(5回の最速、1スレッド)と、残差 ‖Ax − b‖ ÷ ‖b‖ を測りました。
import numpy as np, time
rng = np.random.default_rng(0)
A = rng.standard_normal((n, n)); b = rng.standard_normal(n)
x1 = np.linalg.inv(A) @ b # 逆行列を作ってから掛ける
x2 = np.linalg.solve(A, b) # 逆行列を作らずに解く
n= 100 inv@b 0.29 ms solve 0.08 ms ratio 3.6 resid inv 4.7e-14 solve 4.2e-14
n= 500 inv@b 16.17 ms solve 3.44 ms ratio 4.7 resid inv 1.4e-13 solve 5.9e-14
n= 1000 inv@b 109.14 ms solve 21.05 ms ratio 5.2 resid inv 2.0e-12 solve 1.0e-12
n= 2000 inv@b 545.99 ms solve 125.90 ms ratio 4.3 resid inv 1.3e-11 solve 7.2e-12
n= 4000 inv@b 3585.13 ms solve 885.21 ms ratio 4.1 resid inv 3.3e-11 solve 7.1e-12
どの大きさでも solve が3.6〜5.2倍速く、残差も同じか小さくなりました(4000次で 3.3e-11 と 7.1e-12)。 逆行列を作る計算は、LU 分解に加えて「単位行列の n 本の列それぞれについて解く」分が増えるためです。
右辺が何本もあるとき(b が行列)も、solve(A, B) にまとめて渡す方が速くなりました(2000次)。
| 右辺の本数 k | inv(A) @ B | solve(A, B) |
|---|---|---|
| 1 | 567.2 ms | 144.4 ms |
| 10 | 619.8 ms | 161.7 ms |
| 100 | 611.4 ms | 201.1 ms |
| 1000 | 1342.6 ms | 345.4 ms |
右辺があとから1本ずつ届く場合は、SciPy の lu_factor で一度だけ LU 分解しておき、lu_solve で解きます。2000次で、分解が 121.0 ms、その後は1本 1.54 ms でした。
連立方程式 A x = b を解くとき
逆行列そのものが欲しいとき(成分を見る・式に使う)だけ inv を使う
特異行列のエラー原文と直し方(Singular matrix)
この節では、逆行列の計算で出るエラーの原文と、原因・直し方が分かります。どれも NumPy 2.4.6・SciPy 1.17.1 で実際に出たものです。
>>> np.linalg.inv(np.array([[1, 2], [2, 4]]))
numpy.linalg.LinAlgError: Singular matrix
>>> np.linalg.inv(np.ones((2, 3)))
numpy.linalg.LinAlgError: Last 2 dimensions of the array must be square
>>> np.linalg.solve(A, [1, 2]) # A は 3×3
ValueError: solve1: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (m,m),(m)->(m) (size 2 is different from 3)
>>> A ** -1 # A は整数の配列
ValueError: Integers to negative integer powers are not allowed.
>>> scipy.linalg.inv(np.array([[1, 2], [2, 4.]]))
numpy.linalg.LinAlgError: A singular matrix detected: slice(s) [0] are singular.
| エラー・警告 | 原因 | 直し方 |
|---|---|---|
LinAlgError: Singular matrix |
行列式が0(行や列が他の組み合わせで書ける) | matrix_rank で階数を確かめる。解きたいなら lstsq か pinv |
LinAlgError: Last 2 dimensions of the array must be square |
正方でない行列を inv に渡した |
形を確かめる。最小二乗なら pinv・lstsq |
ValueError: solve1: ... mismatch in its core dimension 0 |
b の長さが A の行数と違う | b の形を (n,) か (n, k) にそろえる |
ValueError: Integers to negative integer powers are not allowed. |
A ** -1 は成分ごとの逆数で、整数では不可 |
np.linalg.inv(A) を使う |
UFuncTypeError: Cannot cast ufunc 'inv' input from dtype('<U21') ... |
文字列が混ざった | astype(float) で数値にする。CSV の読み込みを見直す |
結果が全部 nan |
入力に nan がある |
np.isnan(A).any() で確かめて欠損を除く |
LinAlgWarning: An ill-conditioned matrix detected: ... rcond = 1.33e-18.(SciPy) |
逆行列はあるが、ほぼ特異で誤差が大きい | 次の節の条件数を見る。スケールをそろえる・lstsq |
LinAlgError: A singular matrix detected: slice(s) [0] are singular.(SciPy) |
SciPy で特異行列を渡した | NumPy の Singular matrix と同じ対処 |
特に注意したいのは、A ** -1 や 1 / A は逆行列ではなく「成分ごとの逆数」になることです。小数の配列だとエラーにならず、RuntimeWarning: divide by zero encountered in reciprocal(1 / A では ... in divide)と警告を出して、0の成分が inf の行列を返しました。逆行列は np.linalg.inv(A) か np.linalg.matrix_power(A, -1) で求めます。np.matrix 型なら M.I でも逆行列が返りますが、NumPy のドキュメントは、このクラスは線形代数でも使うことを勧めず、ふつうの配列を使うよう書いています。
エラーが出ないのに答えがおかしい、という場合もあります。 NumPy のドキュメントは inv について「a が悪条件のときは LinAlgError が出ることも出ないこともあり、浮動小数点の誤差で結果が不正確になることがある」と書いています。これが次の節の条件数です。
条件数とは(誤差が大きくなる例)
この節では、逆行列や連立方程式の答えがどれくらい信用できるかを、条件数(じょうけんすう)という1つの数で判断する方法が分かります。
条件数は「入力の小さなずれが、答えで最大何倍のずれになるか」を表す数で、np.linalg.cond(A) で求めます。 1 に近いほど安定(良条件)、大きいほど不安定(悪条件)です。Wikipedia「条件数」は、条件数は問題そのものの性質で、計算の方法には依存しない、と説明しています。
2×2 で、b が 0.0001 ずれると答えが 1 ずれる
A = [[1, 1], [1, 1.0001]] は、行列式が 0.0001 で、ほぼ特異な行列です。右辺 b をわずかに変えて解きました。
cond 40002.000074915224 det 9.99999999999889e-05
inv [[ 10001. -10000.]
[-10000. 10000.]]
b [2, 2.0001] x [1. 1.]
b [2, 2.0002] x [0. 2.]
b [2.0001, 2.0001] x [2.0001 0. ]
b の2つ目が 0.0001 変わっただけで、答えが (1, 1) から (0, 2) に変わりました。 逆行列の成分が 10001・−10000 と大きく、b のずれが1万倍されるためです。測定値の誤差が 0.0001 あるなら、この連立方程式の答えはほとんど決まりません。
ヒルベルト行列で、条件数が大きいほど正しい桁が減る
ヒルベルト行列(i 行 j 列が 1/(i + j − 1))は、悪条件の例としてよく使われます。正解を x = (1, 1, …, 1) にして b = H x を作り、解き直した答えと正解の最大のずれを測りました。
from scipy.linalg import hilbert
H = hilbert(n); x_true = np.ones(n); b = H @ x_true
np.linalg.cond(H)
np.abs(np.linalg.inv(H) @ b - x_true).max()
np.abs(np.linalg.solve(H, b) - x_true).max()
n= 4 cond 1.6e+04 log10 4.2 err inv 1.8e-12 solve 5.4e-14 resid inv 8.2e-14 solve 0.0e+00 |inv(H)H-I|max 2.3e-13
n= 6 cond 1.5e+07 log10 7.2 err inv 2.0e-09 solve 6.6e-11 resid inv 8.1e-12 solve 1.5e-16 |inv(H)H-I|max 4.6e-10
n= 8 cond 1.5e+10 log10 10.2 err inv 2.9e-06 solve 7.2e-08 resid inv 7.1e-08 solve 6.0e-17 |inv(H)H-I|max 5.3e-07
n=10 cond 1.6e+13 log10 13.2 err inv 8.1e-03 solve 4.4e-05 resid inv 4.2e-05 solve 1.0e-16 |inv(H)H-I|max 1.2e-03
n=12 cond 1.6e+16 log10 16.2 err inv 7.1e+00 solve 2.8e-01 resid inv 2.7e-02 solve 1.1e-16 |inv(H)H-I|max 9.6e-01
n=13 cond 4.5e+18 log10 18.7 err inv 1.7e+03 solve 4.5e+01 resid inv 2.6e+00 solve 5.2e-16 |inv(H)H-I|max 1.8e+02
n=14 cond 3.2e+17 log10 17.5 err inv 1.2e+03 solve 7.5e+00 resid inv 1.1e+00 solve 4.8e-17 |inv(H)H-I|max 1.3e+02
条件数の桁数(log10)と、solve の答えで正しく残った桁数(−log10 誤差)を並べると、足して17前後(16.8〜17.6)になりました。
---
config:
xyChart:
width: 480
height: 300
---
xychart-beta
title "条件数の桁数(棒)と正しく残った桁数(線)"
x-axis "ヒルベルト行列の次数" [4, 6, 8, 10, 12]
y-axis "桁" 0 --> 18
bar [4.2, 7.2, 10.2, 13.2, 16.2]
line [13.3, 10.2, 7.1, 4.4, 0.6]
float64 の精度は約16桁(np.finfo(float).eps = 2.22e-16)で、条件数が 10 の k 乗なら、答えの正しい桁はおよそ 17 − k 桁まで減りました。 12次では条件数 1.6e+16 で、正しい桁がほぼ残らず、誤差 0.28 でした。それでも inv は12〜14次でエラーを出さずに値を返し、inv(H) @ H は単位行列から最大 180 もずれました。
inv と solve を比べると、どの次数でも solve の誤差が inv の約1/25〜1/180 で、残差(H x − b)は solve が常に 1e-16 前後でした。悪条件の行列ほど、逆行列を経由しない差が大きく出ます。
| 条件数 cond(A) | 読み方 | すること |
|---|---|---|
| 1〜1e3 程度 | 良条件。結果はほぼ信用できる | そのまま使う |
| 1e6〜1e10 | 6〜10桁ほど失う | 答えの桁数を意識する。solve を使う |
| 1e12 以上 | 正しい桁が数桁しか残らない | 変数のスケールをそろえる。モデルを見直す |
| 1e16 前後(1/eps)以上 | float64 では特異と同じ | lstsq・pinv・正則化(リッジ)を使う |
条件数を下げる方法として、変数の単位や大きさをそろえる(標準化)があります。多項式の当てはめで x をそろえると条件数が 1.9e+09 から 7.3e+02 に下がった実測は、関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。小数の計算で誤差が出るそもそもの理由は、関連記事「JavaScriptの小数計算誤差と丸め|toFixedの落とし穴と正しい対処法」で扱っています。
擬似逆行列(pinv)と最小二乗法の関係
この節では、正方でない行列や特異行列にも使える「擬似逆行列」と、それが最小二乗法の答えになる理由が分かります。
擬似逆行列(ムーア・ペンローズ一般化逆行列、A⁺ と書く)は、どんな形の行列にも1つだけ決まる「逆行列の代わり」です。 A が正則なら A⁺ = A⁻¹ です。英語版 Wikipedia によると、1920年に E. H. ムーア、1951年に A. ビエルハマー、1955年に R. ペンローズが独立に示しました。次の4つの条件をすべて満たす行列として決まります。
① A A⁺ A = A
② A⁺ A A⁺ = A⁺
③ (A A⁺)ᵀ = A A⁺
④ (A⁺ A)ᵀ = A⁺ A
正方でない行列:pinv の答えは最小二乗法の直線と同じ
最小二乗法の記事と同じ5点 (1, 2)・(2, 3)・(3, 5)・(4, 4)・(5, 6) で、直線 y = a x + b を当てはめます。X は5行2列で正方でないので、inv は使えません。
x = np.array([1, 2, 3, 4, 5.]); y = np.array([2, 3, 5, 4, 6.])
X = np.column_stack([x, np.ones(5)]) # 5×2
print(np.linalg.pinv(X) @ y) # 擬似逆行列
print(np.linalg.inv(X.T @ X) @ X.T @ y) # 正規方程式 (XᵀX)⁻¹Xᵀy
print(np.linalg.lstsq(X, y)[0]) # 最小二乗
pinv(X) shape (2, 5)
pinv(X)@y [0.9 1.3]
(XtX)^-1 Xt @y [0.9 1.3]
lstsq [0.9 1.3]
pinv == (XtX)^-1Xt: True
inv(X): LinAlgError Last 2 dimensions of the array must be square
3つとも a = 0.9、b = 1.3 で、最小二乗法の直線 y = 0.9x + 1.3 と同じになりました。 X の列が1次独立のとき、擬似逆行列は (XᵀX)⁻¹Xᵀ と同じ行列になります(True)。NumPy のドキュメントも、擬似逆行列を「A x = b の最小二乗問題を解く行列」と説明しています。pinv(X) @ X は 2×2 の単位行列(左逆行列)になりますが、X @ pinv(X) は 5×5 の単位行列にはなりません。
特異な正方行列:解が無数なら長さが最小の解
S = [[1, 2], [2, 4]] は特異行列で inv はエラーでしたが、pinv は答えを返します。
pinv(S)= [[0.04 0.08]
[0.08 0.16]] = S/25: True
S@Sp@S==S True
Sp@S@Sp==Sp True
(S@Sp)^T==S@Sp True
(Sp@S)^T==Sp@S True
min-norm solution of x+2y=3: [0.6 1.2] norm 1.3416407864998734 check [3. 6.]
other solution (3,0) norm 3.0 (1,1) norm 1.4142135623730951
inconsistent b=(3,5): pinv [0.52 1.04] S@x [2.6 5.2]
- 4つの条件はすべて True でした。
- S x = (3, 6) は「x + 2y = 3」と同じ式で、解は無数にあります。pinv は、その中で長さ(ノルム)が最小の (0.6, 1.2) を返しました。 (3, 0) は長さ 3.0、(1, 1) は 1.414 で、(0.6, 1.2) の 1.342 がいちばん短い解です。
- S x = (3, 5) は解がありません(矛盾)。pinv は S x が (3, 5) にいちばん近くなる (0.52, 1.04) を返し、S x は (2.6, 5.2) でした。
| 行列の状態 | 使うもの | 返ってくる答え |
|---|---|---|
| 正方で正則 | solve(または inv) |
ただ1つの解 |
| 縦長(式が多い)で列が1次独立 | lstsq・pinv |
最小二乗の解 |
| 解が無数(特異・横長) | pinv・lstsq |
長さが最小の解 |
| 解が無い(矛盾) | pinv・lstsq |
ずれの二乗和が最小の解 |
| ほぼ特異(条件数が大きい) | lstsq・pinv(rcond で小さい特異値を0に) |
安定した近似解 |
pinv は特異値分解(SVD)で計算し、特異値が「最大の特異値 × 1e-15」以下のものを0として扱います(rcond の既定値。NumPy 2.5 のマニュアル)。最小二乗法の公式・正規方程式・決定係数は、関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。
逆行列のよくある間違い
この節では、逆行列の手計算とプログラムで起こりやすい間違いを、確かめる順に並べます。
- 1先に行列式が0でないか確かめたかS = [[1,2],[2,4]] は det 0 で逆行列なし。NumPy は LinAlgError: Singular matrix
- 2余因子を並べたあと転置したか余因子の行列は [[9,4,−3],…]、転置した adj A は [[9,−14,3],…]。転置を忘れると別の行列になる
- 3余因子の符号 (−1)^(i+j) を付けたかC12 = (−1)³ × det[[1,3],[4,8]] = (−1) × (−4) = 4。符号は市松模様
- 4(AB)⁻¹ を A⁻¹B⁻¹ にしていないか正しくは B⁻¹A⁻¹。NumPy で A⁻¹B⁻¹ との比較は False だった
- 5A ** -1 や 1/A で逆行列を求めていないか成分ごとの逆数になる。逆行列は np.linalg.inv(A)
- 6連立方程式に inv(A) @ b を使っていないかsolve の方が4〜5倍速く、悪条件でも誤差が小さい
- 7エラーが出なければ正しい、と思っていないかヒルベルト12次は inv がエラーなしで誤差7.1の答えを返した。cond を見る
- 8最後に A × A⁻¹ = I で検算したか手計算は1成分ずつ、プログラムは np.allclose(A @ Ai, np.eye(n))
逆行列は、行列とベクトルの基本の計算(内積・行列の積)の上に成り立っています。内積と外積の公式と計算例は、関連記事「内積・外積とは|公式と計算例・使い道をNumPyで実演」で扱っています。ベクトルを数値の並びとして扱う考え方は、関連記事「エンベディングとは?ベクトル検索とコサイン類似度を計算例で解説」で扱っています。行列の計算が中心になる別の手法として、相関行列の固有値分解を使う主成分分析は、関連記事「主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演」で扱っています。
よくある質問
Q. 逆行列とは簡単に言うと何ですか? A. 掛けると単位行列 I になる行列で、「数の逆数」の行列版です。A × A⁻¹ = I で、A で移したベクトルを元に戻す働きをします。
Q. 逆行列の求め方で、いちばん簡単なのは? A. 2×2 なら公式 (1/(ad − bc)) × [[d, −b], [−c, a]] です。3×3 なら、分数を避けたいときは余因子行列、逆行列があるか分からないときや4×4 以上は掃き出し法が向いています。
Q. 逆行列が存在する条件は? A. 正方行列で、行列式が0でないことです。階数が n であること、A x = 0 の解が x = 0 だけであることなども同じ意味です。
Q. 逆行列が存在しないのはどんなときですか? A. 行列式が0のときと、正方でないときです。行列式が0になるのは、ある行(列)がほかの行(列)の組み合わせで書けるときで、S = [[1, 2], [2, 4]] は2行目が1行目の2倍です。
Q. 4×4 の逆行列はどう求めますか? A. 掃き出し法で、[A|I](4行8列)を同じ手順で掃き出します。例えば [[1,1,1,−1],[1,1,−1,1],[1,−1,1,1],[−1,1,1,1]] は行列式 −16 で、逆行列は元の行列を4で割ったものでした(SymPy で確認)。
Q. 逆行列の検算はどうしますか?
A. A × A⁻¹ を計算して単位行列になるかを確かめます。Python なら np.allclose(A @ Ai, np.eye(n)) が True になるかを見ます。
Q. 転置行列の逆行列は? A. (Aᵀ)⁻¹ = (A⁻¹)ᵀ で、逆行列を転置したものと同じです。回転行列のように「逆行列 = 転置」になる行列は直交行列と呼びます。
Q. Python(NumPy)で逆行列を求めるには?
A. np.linalg.inv(A) です。連立方程式を解くだけなら np.linalg.solve(A, b)、正方でない行列には np.linalg.pinv(A) を使います。分数で見たいときは SymPy の Matrix(A).inv() です。
Q. LinAlgError: Singular matrix と出たら?
A. 行列式が0の特異行列で、逆行列がありません。np.linalg.matrix_rank(A) で階数を確かめ、データの重複(同じ列が2つある等)を見直します。解が欲しいときは np.linalg.lstsq か pinv を使います。
Q. 擬似逆行列とは何ですか? A. 正方でない行列や特異行列にも1つだけ決まる、逆行列の代わりの行列です。A⁺ b は最小二乗の解(解が無数なら長さが最小の解)になり、5点の直線の当てはめでは y = 0.9x + 1.3 が求まりました。
Q. クラメルの公式と逆行列の関係は? A. クラメルの公式は、逆行列 (1/det A) × adj A を使って x = A⁻¹ b の各成分を行列式の比で書いたものです。Wikipedia「逆行列」は、理論上は重要だが数値計算には向かないと書いています。
まとめ
- 逆行列 A⁻¹ は、A A⁻¹ = A⁻¹ A = I(単位行列)になる行列。行列式が0でない正方行列(正則行列)にだけある。
- 2×2 は公式 (1/(ad − bc)) × [[d, −b], [−c, a]]。[[2, 1], [4, 3]] の逆行列は [[3/2, −1/2], [−2, 1]]。
- 3×3 は掃き出し法([A|I] → [I|A⁻¹]、例では7手)か、余因子9個を並べて転置し、行列式で割る。どちらも同じ答えになった。
- 性質:(AB)⁻¹ = B⁻¹A⁻¹、(Aᵀ)⁻¹ = (A⁻¹)ᵀ、det(A⁻¹) = 1/det A。
- 連立方程式は数式では x = A⁻¹ b だが、プログラムでは
solve。4000次でinvの4.1倍速く、残差も小さかった。 - 条件数が 10 の k 乗なら、正しい桁はおよそ 17 − k 桁(float64 の精度は約16桁)。
invはエラーを出さずに不正確な値を返すことがある。 - 正方でない・特異な行列には擬似逆行列
pinv。答えは最小二乗の解で、正規方程式 (XᵀX)⁻¹Xᵀy と一致した。
参考・出典
確認日はいずれも 2026年10月22日です。
- Wikipedia「逆行列」:https://ja.wikipedia.org/wiki/逆行列
- Wikipedia「擬似逆行列」:https://ja.wikipedia.org/wiki/擬似逆行列
- Wikipedia「条件数」:https://ja.wikipedia.org/wiki/条件数
- Wikipedia (English)「Invertible matrix」:https://en.wikipedia.org/wiki/Invertible_matrix
- Wikipedia (English)「Moore–Penrose inverse」:https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse
- NumPy「numpy.linalg.inv」:https://numpy.org/doc/stable/reference/generated/numpy.linalg.inv.html
- NumPy「numpy.linalg.solve」:https://numpy.org/doc/stable/reference/generated/numpy.linalg.solve.html
- NumPy「numpy.linalg.pinv」:https://numpy.org/doc/stable/reference/generated/numpy.linalg.pinv.html
- SciPy「scipy.linalg.lu_factor」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu_factor.html
- SymPy「Matrices」:https://docs.sympy.org/latest/modules/matrices/matrices.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「逆行列とは|求め方(2×2公式・掃き出し法・余因子)をPythonで検算」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。