情報学入門(データ演習) / 第 4 章

行列

数の表を掛ける ── そして二重ループの下ごしらえ

この章のねらい

1. 行列とは

行列(matrix)は、数を縦横に並べた表です。 横の並びを、縦の並びをといいます (Cells(行, 列) と同じ順です)。

Aabcd   Befgh

1.1 足し算 ── 同じ場所どうしを足す

ABa+eb+fc+gd+h

これは素直です。大きさが同じ行列どうしでしか足せません。

1.2 掛け算 ── 行と列を組み合わせる

ABabcd efghae+bgaf+bhce+dgcf+dh

規則は 1 つだけです。 答えの「ij 列」は、
左の行列の i 行目(橙)と右の行列の j 列目(青)を 先頭から順に掛けて、全部足す
上の例なら 1 行 1 列は a×eb×g です。

掛けられる条件。 元資料は 2×2 の場合だけを扱っているので触れていませんが、 一般には左の行列の「列の数」と右の行列の「行の数」が同じでなければ掛けられません。 (m×n)×(n×p)=(m×p)── 内側の n が一致し、 答えの大きさは外側だけで決まります。 §3 の工場の問題では(1×2)×(2×2)=(1×2)になっています。

動かす① 掛け算の規則を追う 答えのマスをクリック

2. Excel の関数で計算する

Excel には行列の積を求める MMULT 関数があります。 足し算はふつうに + で書けます。

元資料 6〜7 枚目の書き方
やること入れる式
2×2 の掛け算=MMULT(A1:B2, C1:D2)
2×2 の足し算=A1:B2 + C1:D2
行列を直接書く(配列定数)={2,10;4,13} ── , が列の区切り、; が行の区切り

元資料は答えを入れるとき CtrlShiftEnter を押すよう指示しています。 これは複数のセルにまたがる答えを返す式(配列数式)を確定するための操作で、 当時は必須でした。 しかし Microsoft 365 以降の Excel では不要になりました (「動的配列数式」の導入により、ふつうに Enter を押すだけで 答えが必要なだけのセルに自動で広がります)。 古い Excel や互換モードでは今も必要なので、両方を知っておいてください

この教材の処理系では MMULT は使えません。 数式を計算する仕組みを持っていないためです(第 2 章 §2)。 だから以下ではすべて VBA で計算します ── そしてそれは遠回りではありません。 MMULT は 2 つの行列を掛けるだけですが、 VBA で書ければ何段でも、どんな大きさでも、条件をつけても計算できます。

3. VBA で計算する

まず、規則をそのまま書き下してみます。2×2 なら答えは 4 つなので、4 行書けば済みます。

Sub Macro1()
    Dim a As Double, b As Double, c As Double, d As Double
    Dim e As Double, f As Double, g As Double, h As Double

    ' 行列 A を A1:B2 から、行列 B を D1:E2 から読む
    a = Cells(1, 1): b = Cells(1, 2)
    c = Cells(2, 1): d = Cells(2, 2)
    e = Cells(1, 4): f = Cells(1, 5)
    g = Cells(2, 4): h = Cells(2, 5)

    ' 答えを G1:H2 に書く
    Cells(1, 7) = a * e + b * g
    Cells(1, 8) = a * f + b * h
    Cells(2, 7) = c * e + d * g
    Cells(2, 8) = c * f + d * h

    Cells(4, 1) = "A × B を G1:H2 に入れました"
End Sub

4 つ書くのは我慢できますが、3×3 なら 9 つ、10×10 なら 100 個です。 しかも ah のような名前は 26 個で尽きます。 ──ここが、繰り返しと配列が必要になる理由です。

3.1 二重ループで書く

同じ計算を、行と列を数え上げる形に書き直します。 まだ習っていない For が出てきますが(第 7 章)、 「中に書いたことを、i を変えながら繰り返す」と読んでください。

Sub Macro2()
    Dim i As Integer, j As Integer, k As Integer
    Dim n As Integer
    Dim s As Double

    n = 2                        ' 行列の大きさ(2×2)

    ' i:答えの行、j:答えの列
    For i = 1 To n
        For j = 1 To n
            s = 0
            ' k:左の行列の列 = 右の行列の行
            For k = 1 To n
                s = s + Cells(i, k).Value * Cells(k, j + 3).Value
            Next k
            Cells(i, j + 6) = s
        Next j
    Next i

    Cells(4, 1) = "三重ループで A × B を求めました"
    Cells(5, 1) = "掛け算した回数"
    Cells(5, 2) = n * n * n
End Sub

ループが 3 つ入れ子になっています。 外の 2 つ(i, j)が「答えのどのマスを埋めるか」、 いちばん内側(k)が「掛けて足す」部分です。 だから掛け算の回数は n×n×n ── 大きさが 10 倍になると 1000 倍になります。 行列の掛け算が「重い計算」の代表とされるのはこのためで、 いまの機械学習の計算時間のほとんどは、実はこの三重ループです。

4. 工場の問題 ── 行列の積の正体

元資料 9・13 枚目の問題です。まず 1 問目。

法政工場では、車とトラックを製造しています。
車を作るためには、作業員 3 人とロボット 5 台必要です。
トラックを作るためには、作業員 4 人とロボット 8 台必要です。
車 2 台とトラック 3 台を作るために必要な作業員とロボットはいくらでしょう。

23 35482×3+3×42×5+3×81834

作業員 18 人、ロボット 34 台

続いて 2 問目(元資料 14・15 枚目)。

作業員は、サンドイッチを 2 個食べ、コーヒーを 3 杯飲みます。
ロボットは、サンドイッチを 6 個、コーヒーを 10 杯燃料として必要とします。
車 2 台とトラック 3 台を作るために必要なサンドイッチとコーヒーはいくらでしょう。

1834 23610240394

サンドイッチ 240 個、コーヒー 394 杯

ここに、行列の積のいちばん大事な意味が出ています。 元資料は 2 問を続けて計算するだけですが、この 2 問が並んでいることには理由があります。 行列は「単位の変換」で、行列の積は「変換をつなげること」なのです。

車・トラック(2, 3)
行列 A1 台あたりの
人とロボット
作業員・ロボット(18, 34)
行列 B1 人・1 台あたりの
食料と燃料
サンド・コーヒー(240, 394)

そして A×B を先に計算しておけば、 「車・トラック」から「サンドイッチ・コーヒー」へ一気に変換できます ── 途中の人数を経由しなくても同じ答えが出ます。 これが「行列の積」という演算があの形で定義されている理由です。 下で実際に確かめてください。

Sub Macro3()
    Dim i As Integer, j As Integer, k As Integer
    Dim s As Double
    Dim v(2) As Double          ' 作った台数(車, トラック)
    Dim A(2, 2) As Double       ' 1 台あたりの 人・ロボット
    Dim B(2, 2) As Double       ' 1 人・1 台あたりの サンド・コーヒー
    Dim w(2) As Double          ' 途中(作業員, ロボット)
    Dim x(2) As Double          ' 最後(サンド, コーヒー)
    Dim AB(2, 2) As Double      ' A と B を先に掛けたもの

    ' 読み込む
    v(1) = Cells(2, 1): v(2) = Cells(2, 2)
    For i = 1 To 2
        For j = 1 To 2
            A(i, j) = Cells(4 + i, j).Value
            B(i, j) = Cells(4 + i, j + 3).Value
        Next j
    Next i

    ' ① 途中を通る: v × A → w、 w × B → x
    For j = 1 To 2
        s = 0
        For k = 1 To 2
            s = s + v(k) * A(k, j)
        Next k
        w(j) = s
    Next j
    For j = 1 To 2
        s = 0
        For k = 1 To 2
            s = s + w(k) * B(k, j)
        Next k
        x(j) = s
    Next j

    Cells(8, 1) = "① 作業員":   Cells(8, 2) = w(1)
    Cells(9, 1) = "① ロボット": Cells(9, 2) = w(2)
    Cells(8, 4) = "① サンド":   Cells(8, 5) = x(1)
    Cells(9, 4) = "① コーヒー": Cells(9, 5) = x(2)

    ' ② A×B を先に計算して、v に一気に掛ける
    For i = 1 To 2
        For j = 1 To 2
            s = 0
            For k = 1 To 2
                s = s + A(i, k) * B(k, j)
            Next k
            AB(i, j) = s
            Cells(4 + i, j + 6) = s
        Next j
    Next i
    Cells(4, 7) = "A×B"

    For j = 1 To 2
        s = 0
        For k = 1 To 2
            s = s + v(k) * AB(k, j)
        Next k
        Cells(7 + j, 7) = s
    Next j
    Cells(7, 7) = "② 一気に"

    ' 一致しているか
    Cells(11, 1) = "①と②は同じか"
    If Cells(8, 5).Value = Cells(8, 7).Value And Cells(9, 5).Value = Cells(9, 7).Value Then
        Cells(11, 2) = "同じ(結合法則)"
        Cells(11, 2).Interior.Color = RGB(198, 239, 206)
    Else
        Cells(11, 2) = "違う"
        Cells(11, 2).Interior.Color = RGB(255, 199, 206)
    End If
End Sub

(v×ABv×(A×B) ── これを結合法則といいます。 「途中で人数を数えてから食料を計算する」のと「変換表をあらかじめ合成しておく」のが 同じ答えになる、ということです。 コンピュータグラフィックス(第 15 章)で、拡大・回転・移動をまとめて 1 つの行列にするのも、 まったく同じ性質を使っています。

4.1 順番は変えられない

足し算や掛け算と違って、行列の積は順番を入れかえられませんABBA)。元資料は触れていませんが、これは大事な性質です。 工場の例で考えれば当たり前で ── 「車 → 人 → 食料」の順に変換するのが正しいのに、 「車 → 食料 → 人」と掛けたら意味をなしません。 行列の積は「変換の順序」を表しているので、順番に意味があるのです。

Sub Macro4()
    Dim i As Integer, j As Integer, k As Integer
    Dim s As Double
    Dim onaji As Boolean

    ' A×B を G1:H2 に
    For i = 1 To 2
        For j = 1 To 2
            s = 0
            For k = 1 To 2
                s = s + Cells(i, k).Value * Cells(k, j + 3).Value
            Next k
            Cells(i, j + 6) = s
        Next j
    Next i
    Cells(4, 7) = "↑ A×B"

    ' B×A を G5:H6 に(左右を入れかえるだけ)
    For i = 1 To 2
        For j = 1 To 2
            s = 0
            For k = 1 To 2
                s = s + Cells(i, k + 3).Value * Cells(k, j).Value
            Next k
            Cells(i + 5, j + 6) = s
        Next j
    Next i
    Cells(8, 7) = "↑ B×A"

    onaji = True
    For i = 1 To 2
        For j = 1 To 2
            If Cells(i, j + 6).Value <> Cells(i + 5, j + 6).Value Then onaji = False
        Next j
    Next i

    Cells(4, 1) = "A×B と B×A は同じか"
    If onaji Then
        Cells(5, 1) = "同じだった(たまたま)"
    Else
        Cells(5, 1) = "違う ── 順番を変えられない"
        Cells(5, 1).Interior.Color = RGB(255, 235, 156)
    End If
End Sub

5. まとめ

  1. 行列の足し算は同じ場所どうし。大きさが同じでないと足せない
  2. 掛け算は左の行 × 右の列を掛けて全部足す。 (m×n)×(n×p)=(m×p
  3. Excel は MMULTMicrosoft 365 では Ctrl+Shift+Enter は不要になった
  4. VBA では三重ループ。掛け算の回数は n3 で、大きさに対して急に重くなる
  5. 行列は単位の変換、行列の積は変換の合成。 だから (vA)Bv(AB)(結合法則)
  6. ただし ABBA。変換の順序に意味があるから

章末問題

付録:元資料からの修正一覧

もとにしたのは「情報学入門(VBA)120-2019」全 15 枚です。

元資料この教材種別
配列数式の確定に CtrlShiftEnter を要求している Microsoft 365 以降では不要(動的配列数式)。古い Excel では今も必要なので両方を記述古い
2×2 の場合だけを扱い、掛けられる条件(左の列数=右の行数)に触れていない m×n)×(n×p)=(m×p)として明示。工場の問題が(1×2)×(2×2)であることも示した不足
工場の問題を 2 問続けて計算するが、2 問が並んでいる意味を説明していない 行列は単位の変換、積は変換の合成結合法則を実際に確かめるモデルを追加不足
ABBA(交換法則が成り立たない)に触れていない §4.1 として追加。工場の例で「順序に意味がある」ことと結びつけた不足
VBA での書き方が画面の画像で示されるだけで、一般化(二重・三重ループ)への道筋がない 規則そのままの 4 行版 → 三重ループ版と並べ、なぜループが必要かを示した。計算量 n3 にも言及不足
「型宣言は、省略すると Variant 型となる」(第 3 章と重複) 第 3 章に集約。この章では配列(Dim A(2, 2) As Double)の形で使った重複

元資料の計算はすべて正しいことを検算しました。 2×2 の積の展開(ae+bg など)、配列定数の書き方(, が列・; が行)、 =MMULT(A1:B2,C1:D2)=A1:B2+C1:D2、 工場の問題の答え(2 3)×(3 5 / 4 8)=(18 34)と(18 34)×(2 3 / 6 10)=(240 394)── いずれも正確です。