Excelで畳み込み(VBA?何それおいしいの?)

# はじめに

実験するとき何かと便利なExcel．だけど，たまにやりたいことがうまくできないことがある．けど，調べたら実はちゃんとやり方があたりしてびっくりしたり．

ExcelでVBAマクロを使わずに簡単に畳み込みを実現することができる．

# 行列演算

行列演算は普通に関数があるので簡単．積も逆行列も計算してくれる．
例えば，2×3の行列**A**と3×2の行列**B**を掛けて，2×2の行列**C**を作る場合．
A1:C2に**A**を，E1:F3に**B**を書く．結果の**C**はH1:I2に入るとする．

|       | A | B | C | D | E | F | G | H | I |
|------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| **1** | 1 | 2 | 3 |   | 7 | 8 |   |   |   |
| **2** | 4 | 5 | 6 |   | 9 |10 |   |   |   |
| **3** |   |   |   |   |11 |12 |   |   |   |


H1:I2を選択した状態でF2キーを押し，次の計算式を入力．

```
=MMULT(A1:C2,E1:F3)
```

入力後，Ctrl+Shift+Enterを押すと，目的の演算結果**C**がH1:I2で得られる．

|       | A | B | C | D | E | F | G | H | I |
|------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| **1** | 1 | 2 | 3 |   | 7 | 8 |   |58 |64 |
| **2** | 4 | 5 | 6 |   | 9 |10 |   |139|154|
| **3** |   |   |   |   |11 |12 |   |   |   |

特に問題は無い．これは誰もがやってる普通の操作だ．

# ベクトルの演算

行ベクトルと列ベクトルの内積はただの行列演算なので難しくはない．
Excelでの表記上，2個とも列ベクトルのように書いてあっても，計算したいことが内積であれば，1個目のベクトルをTRANSPOSE関数を使って転置するだけですむ．

のだが，実は別の解決手段がある．計算は2個のベクトルの要素ごとの積の総和であるということに注目する．

例えばA1:A3に1個目の（本当は行ベクトルのつもりだけど，表記上は）列ベクトル，B1:B3に2個目の列ベクトルが書いてあるとする．

|       | A | B | C |
|------:|:-:|:-:|:-:|
| **1** | 1 | 4 |   |
| **2** | 2 | 5 |   |
| **3** | 3 | 6 |   |
| **4** |   |   |   |


このとき，要素ごとの積をまずは求めてC1:C3セルに入れたい．C1セルに`=A1*B1`，C2セルに`=A2*B2`，C3セルに`=A3*B3`としてもよいのだが，今回はそうしない．C1:C3セルを選択した状態でF2キーを押し，次の計算式を入力．

```
=A1:A3*B1:B3
```

入力後，Ctrl+Shift+Enterを押すと，要素ごとの積がC1:C3に入るって寸法だ！[^1]

|       | A | B | C |
|------:|:-:|:-:|:-:|
| **1** | 1 | 4 | 4 |
| **2** | 2 | 5 |10 |
| **3** | 3 | 6 |18 |
| **4** |   |   |   |

求めた積の総和をC4セルに入れるとすると，C4セルに`=SUM(C1:C3)`と書くだけ．
めでたく行ベクトルと列ベクトルの内積を計算できた！

|       | A | B | C |
|------:|:-:|:-:|:-:|
| **1** | 1 | 4 | 4 |
| **2** | 2 | 5 |10 |
| **3** | 3 | 6 |18 |
| **4** |   |   |32 |

> いや，ちょっと待て．普通に行列演算で書けばセル1個ですんでいた計算を，一体何個のセルを使わせる気だ？

その解決はそんなに難しい話ではなく，C4セルに次のような計算式を入力するだけだ．

```
=SUM(A1:A3*B1:B3)
```

入力後，やはりCtrl+Shift+Enterを押すと，ちゃんと行ベクトルと列ベクトルの内積が取れてる！

# Excelで畳み込み

と，ここまでやると，どうも畳み込み演算が簡単にできそうな気がする．

例えばA1:D4に離散コサイン変換を想定した，4×4サイズのベース画像1個分を，A6:H13に8×8のグレースケール画像を想定した適当な数値を入れておく．

4×4ベース画像1個分

|       | A | B | C | D |
|------:|:-:|:-:|:-:|:-:|
| **1** | 1 | 1 | -1| -1|
| **2** | 1 | 1 | -1| -1|
| **3** | 1 | 1 | -1| -1|
| **4** | 1 | 1 | -1| -1|

8×8グレースケール画像

|       | A | B | C | D | E | F | G | H |
|------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| **6** | 10| 10| 10| 10|  0|  0|  0|  0|
| **7** | 10| 10| 10| 10|  0|  0|  0|  0|
| **8** | 10| 10| 10| 10|  0|  0|  0|  0|
| **9** | 10| 10| 10| 10|  0|  0|  0|  0|
| **10**|  0|  0| 10| 10| 10| 10|  0|  0|
| **11**|  0|  0| 10| 10| 10| 10|  0|  0|
| **12**|  0|  0| 10| 10| 10| 10|  0|  0|
| **13**|  0|  0| 10| 10| 10| 10|  0|  0|

B17セルに次のような計算式を入力．もちろん，最後はCtrl+Shift+Enterだ．

```
=SUM($A$1:$D$4*A6:D9)
```

|       | A | B | C | D | E | F | G | H |
|------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| **17**|   |  0|   |   |   |   |   |   |


するとまずは，一番左上の畳み込みが求まる．後は画像全体に対して実行するだけだ．これはいつものやりなれた操作，B17セルを選択して，選択枠の右下をドラッグして必要な大きさに（ここではF21セルまで）広げるだけだ．

|       | A | B | C | D | E | F | G | H |
|------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| **17**|   |  0| 40| 80| 40|  0|   |   |
| **18**|   |-20| 20| 60| 40| 20|   |   |
| **19**|   |-40|  0| 40| 40| 40|   |   |
| **20**|   |-60|-20| 20| 40| 60|   |   |
| **21**|   |-80|-40|  0| 40| 80|   |   |

# まとめ

行列[^2]の要素ごとの積をExcelでVBAマクロを使うことなく計算する手法を示した．
さらに応用として，VBAを使わずに畳み込みができることを示した．

通常の計算式は`=[セル1][演算子][セル2]`の形式だが，要素ごとの計算は`=[セルの範囲1][演算子][セルの範囲2]`とするだけだ．入力後はEnterではなく，Ctrl+Shift+Enterとすることも忘れてはならない．必要なのはこの2つなのだ．

---
[^1]: 複数セルを選択→F2→計算式入力→Ctrl+Shift+Enterは行列演算関数を使うときと同じ操作．これをやらないと，値を正常に表示できない．
[^2]: 行列と言っても，数学上，見た目が最も近いのが行列だったというだけで，行列の数学的な性質が特に必要だったわけではない．むしろベクトルの方が近い．