高校国語788336 views
いろは3010814 views
高校化学2924392 views
英語613639 views
ヒストリア290598 views
中学英語811710 views
数学講師2886227 views
LaTeX962153 views
教育149510 views
中学理科1630641 views
Help
Tools
NewsSpreadsheetCalendarBookkeepingSlidesTier ListPen ToolIllustrationCrayonWatercolorPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchSwirl EffectOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsRolling DiceCross SectionsMotion PathMechanicsWavesElectromagnetic WavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHPeriodic TableComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseMuscle ContractionHormones and HomeostasisRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic TheoryShogi StrategyPiano Rhythm Game

English

行列演算を純粋な Python で実装する|Python

線形代数の計算には NumPy を使うのが一般的だが、行列演算の原理を理解するために純粋な Python で実装してみよう。リストのリストで行列を表現し、基本的な演算を自前で書く。

行列の表現

行列は「リストのリスト」で表す。各要素のリストが行に対応する。

# 2×3 行列
A = [
    [1, 2, 3],
    [4, 5, 6]
]

# 要素へのアクセス(0 始まり)
print(A[0][1])  # 2(1 行目 2 列目)
print(A[1][2])  # 6(2 行目 3 列目)

行数と列数を取得する関数を用意しておくと便利だ。

def shape(A):
    """行列の形状 (行数, 列数) を返す"""
    return len(A), len(A[0])

A = [[1, 2, 3], [4, 5, 6]]
print(shape(A))  # (2, 3)

ゼロ行列と単位行列

よく使う特殊な行列を生成する関数を作る。

def zeros(m, n):
    """m×n のゼロ行列を生成"""
    return [[0 for _ in range(n)] for _ in range(m)]

def identity(n):
    """n×n の単位行列を生成"""
    return [[1 if i == j else 0 for j in range(n)] for i in range(n)]

print(zeros(2, 3))
# [[0, 0, 0], [0, 0, 0]]

print(identity(3))
# [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

行列の加算

同じサイズの行列同士を要素ごとに足す。

def add(A, B):
    """行列の加算 A + B"""
    m, n = shape(A)
    return [[A[i][j] + B[i][j] for j in range(n)] for i in range(m)]

A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
print(add(A, B))
# [[6, 8], [10, 12]]

スカラー倍

行列の全要素にスカラーを掛ける。

def scalar_mult(c, A):
    """スカラー倍 c * A"""
    m, n = shape(A)
    return [[c * A[i][j] for j in range(n)] for i in range(m)]

A = [[1, 2], [3, 4]]
print(scalar_mult(3, A))
# [[3, 6], [9, 12]]

行列の乗算

行列の積 は、 で定義される。 のとき、 になる。

def mult(A, B):
    """行列の乗算 A @ B"""
    m, n = shape(A)
    n2, p = shape(B)
    if n != n2:
        raise ValueError("行列のサイズが不一致")
    
    C = zeros(m, p)
    for i in range(m):
        for j in range(p):
            for k in range(n):
                C[i][j] += A[i][k] * B[k][j]
    return C

A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
print(mult(A, B))
# [[19, 22], [43, 50]]

この三重ループは の計算量を持つ。大きな行列では非効率だが、原理を理解するには十分だ。

転置

行と列を入れ替える。

def transpose(A):
    """転置行列 A^T"""
    m, n = shape(A)
    return [[A[i][j] for i in range(m)] for j in range(n)]

A = [[1, 2, 3], [4, 5, 6]]
print(transpose(A))
# [[1, 4], [2, 5], [3, 6]]

ベクトルと行列の積

ベクトルは 1 列の行列として扱える。列ベクトル と行列 の積 を計算する専用関数を作ると便利だ。

def matvec(A, x):
    """行列とベクトルの積 A @ x"""
    m, n = shape(A)
    if len(x) != n:
        raise ValueError("サイズ不一致")
    return [sum(A[i][j] * x[j] for j in range(n)) for i in range(m)]

A = [[1, 2], [3, 4], [5, 6]]
x = [1, 2]
print(matvec(A, x))
# [5, 11, 17]

内積

ベクトルの内積(ドット積)も基本的な演算だ。

def dot(u, v):
    """ベクトルの内積 u · v"""
    return sum(u[i] * v[i] for i in range(len(u)))

u = [1, 2, 3]
v = [4, 5, 6]
print(dot(u, v))  # 32(= 1*4 + 2*5 + 3*6)

行列式(2×2 と 3×3)

行列式は正方行列に対して定義されるスカラー値だ。2×2 と 3×3 の場合を実装する。

def det2(A):
    """2×2 行列の行列式"""
    return A[0][0] * A[1][1] - A[0][1] * A[1][0]

def det3(A):
    """3×3 行列の行列式(サラスの公式)"""
    return (A[0][0] * A[1][1] * A[2][2]
          + A[0][1] * A[1][2] * A[2][0]
          + A[0][2] * A[1][0] * A[2][1]
          - A[0][2] * A[1][1] * A[2][0]
          - A[0][1] * A[1][0] * A[2][2]
          - A[0][0] * A[1][2] * A[2][1])

A = [[1, 2], [3, 4]]
print(det2(A))  # -2

B = [[1, 2, 3], [4, 5, 6], [7, 8, 10]]
print(det3(B))  # -3

一般の 行列の行列式は、余因子展開やLU分解を使って計算する。

逆行列(2×2)

2×2 行列の逆行列は公式で計算できる。

def inv2(A):
    """2×2 行列の逆行列"""
    d = det2(A)
    if d == 0:
        raise ValueError("逆行列が存在しない(特異行列)")
    return [[A[1][1] / d, -A[0][1] / d],
            [-A[1][0] / d, A[0][0] / d]]

A = [[4, 7], [2, 6]]
A_inv = inv2(A)
print(A_inv)
# [[0.6, -0.7], [-0.2, 0.4]]

# 検算: A @ A^(-1) = I
print(mult(A, A_inv))
# [[1.0, 0.0], [0.0, 1.0]]
純粋な Python

原理の理解に最適。小さな行列向き。大きな行列では遅い。

NumPy

高度に最適化されている。実務では必ず NumPy を使う。

純粋な Python で実装することで、行列演算のアルゴリズムを深く理解できる。次のステップとして、連立方程式の解法(ガウス消去法)を学ぶとよい。