エクセルで多変量正規乱数を生成する

エクセルで多変量正規乱数を発生する方法を考えてみたいと思います。

# 多変量正規乱数

M次元の多変量乱数はM次元空間の点です。その座標はベクトルであり、M個の成分はランダムで、一般的に独立同一に分布ししているわけではありません。多変量正規変数の特別な場合として多変量ガウス密度関数、

```math
N(x|\mu \Sigma)=\frac{1}{(2\pi)^{M/2}}\exp[-\frac{1}{2}(x-\mu)-\Sigma^{-1}(x-\mu)]
```
があります。$\mu$は分布の平均をあらわすベクトルです。$\Sigma$は対称な正定値行列で、分布の共分散を表します。$\mu$と$\Sigma$で規定される乱数$x$のベクトルを得る方法は平均ゼロ、分散１の独立な乱数ベクトル$y$を生成することからはじめます。$\Sigma$が正定値行列である場合には、それは下三角行列$L$とその転置行列に分解することができます。
$$ \Sigma=LL^T$$
これをコレスキー分解といいます。つぎに、乱数$x$は分散が１の独立した乱数からつぎの様に生成します。
$$ x = Ly+\mu$$
$x_i$は$y_i$の線形結合として作られます。$i$は要素を表します。平均と共分散によって定義された正規乱数の線形結合は正規分布にしたがいます。

## M=2　エクセルシート

まずM=2の場合を考えてみます。$x1$と$x2$の相関係数は
$$\rho=\frac{\text{Cov}(x_1,x_2)}{\sqrt{\text{Var}(x_1)}\sqrt{\text{var}(x_2)}}$$
Var, Covは分散と共分散を表します。平均ゼロ、分散１の独立な乱数$y_1$と$y_2$を生成し、$y_1$を$x_1$とし、$x_2=a_1y_1+a_2y_2$とします。

そうすると、

```math
\begin{eqnarray}
  \text{Cov}(x_1,x_2)&=& \text{Cov}(y_1,a_1y_1+a_2y_2)\\
                    &=& a_1\text{Cov}(y_1,y_1)+a_2\text{Cov}(y_1,y_2)\\
                    &=& a_1
\end{eqnarray}
```

また、

```math
\begin{eqnarray}
  \text{Var}(x_2)&=& \text{Var}(a_1y_1+a_2y_2)\\
                    &=& a_1^2\text{Var}(y_1)+a_2^2\text{Var}(y_2)\\
                    &=& a_1^2+a_2^2=1
\end{eqnarray}
```
よって、

```math
\begin{eqnarray}
　　\rho&=&\frac{\text{Cov}(x_1,x_2)}{\sqrt{\text{Var}(x_1)}\sqrt{\text{var}(x_2)}}\\
        &=&\frac{a_1}{a_1^2+a_2^2}\\
        &=&a_1
\end{eqnarray}
```
この式を$a_2$について解くと
$$a_2=\frac{\sqrt{1-\rho^2}}{\rho}a_1$$

したがって、

$$x_2=a_1y_1+a_2y_2=a_1y1+\frac{\sqrt{1-\rho^2}}{\rho}a_1=\rho y_1+\sqrt{1-\rho^2}y_2$$
となります。

### 例　$\rho=0.5$のときb=0.87でエクセルで22000個乱数生成した結果相関は0.496
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267055/e4842115-fb73-2716-b5e4-af4509daeecb.png)

## M＝3　エクセルシート

M＝3では、

```math
\begin{eqnarray}
x_1&=&y_1\\
x_2&=&a_{21}y_1+a_{22}y_2\\
x_3&=&a_{31}y_1+a_{32}y_2+a_{33}y3
\end{eqnarray}
```
とします。相関は３つあります。x1とx2、x2とx3、そしてx1とx3の間の相関です。それぞれを$\rho_{12},\rho_{23},\rho_{13}$
とします。

したがって
先ほどの計算から
$$x_2=\rho_{12} y_1+\sqrt{1-\rho_{12}^2}y_2$$
となります。また、


```math
\begin{eqnarray}
  \text{Cov}(x_2,x_3)&=& \text{Cov}(a_{21}y_1+a_{22}y_2,a_{31}y_1+a_{32}y_2+a_{33}y_3)\\
                    &=& a_{21}a_{31}\text{Cov}(y_1,y_1)+a_{31}a_{32}\text{Cov}(y_1,y_2)+a_{22}a_{32}\text{Cov}(y_2,y_2)\\
                    &+& a_{21}a_{33}\text{Cov}(y_1,y_3)+a_{22}a_{33}\text{Cov}(y_2,y_3)\\
                    &=& a_{21}a_{31}+a_{22}a_{32}\\
                    &=& \rho_{12}\rho_{13}+\sqrt{1-\rho_{12}}a_{32}\\
                    &=&\rho_{23}
\end{eqnarray}
```
よって
$$a_{32}=\frac{\rho_{23}-\rho_{12}\rho_{13}}{\sqrt{1-\rho_{12}}}=$$

```math
\begin{eqnarray}
  \text{Var}(x_3)&=& \text{Var}(a_{31}y_1+a_{32}y_2+a_{33}y_3)\\
                    &=& a_{31}^2\text{Var}(y_1)+a_{32}^2\text{Var}(y_2)+a_{33}^2\text{Var}(y_2)\\
                    &=& a_{31}^2+a_{32}^2+a_{33}^2\\
                    &=&\rho_{31}^2+\frac{(\rho_{23}-\rho_{12}\rho_{13})^2}{1-\rho_{12}}+a_{33}^2\\
                    &=&1
\end{eqnarray}
```
したがって、
$$a_{33}=\sqrt{1-\rho_{31}^2-\frac{(\rho_{23}-\rho_{12}\rho_{13})^2}{1-\rho_{12}}}$$

### 例 　$\rho_{12}=0.5$, $\rho_{13}=-0.1$, $\rho_{23}=0.7$のとき


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267055/73bf76bf-5a59-8a08-c847-8daffa13bb3e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267055/56fba124-1dca-260a-3c41-397963eec1fb.png)

## M=3 コレスキー分解をエクセルVBAで実行

エクセルVBAでコレスキー分解を行います。エクセルシートではなく、エクセルVBAを用います。Numerical Recipes Third edition のCのコードをエクセルVBAに変換したものを使います。詳しくはp.100 2.9 Cholesky Decompositionを参照してください。

```Excel
Option Explicit
Sub choldc(el() As Double, n As Long)
     Dim i As Long, j As Long, k As Long
     Dim sum As Double
    
     For i = 1 To n
        For j = i To n
            sum = el(i, j)
            For k = i - 1 To 1 Step -1
                sum = sum - el(i, k) * el(j, k)
            Next k
            If (i = j) Then
                If (sum <= 0#) Then
                    MsgBox "choldc failed"
                End If
                el(i, i) = Sqr(sum)
            Else
                el(j, i) = sum / el(i, i)
            End If
        Next j
    Next i
    For i = 1 To n
        For j = 0 To i - 1
            el(j, i) = 0
        Next j
    Next i

End Sub

Private Sub ボタン2_Click()
    Dim n As Long
    Dim el() As Double, b() As Double
    Dim i As Long, j As Long
   
    n = 3
    ReDim el(n, n)
    ReDim b(n, n)
   

   
    For i = 1 To n
        For j = 1 To i
            If i = j Then
                el(j, i) = 1
            Else
                el(j, i) = Worksheets("sheet3").Cells(i * 2 - 2, j)
            End If
        Next j
    Next i


    Call choldc(el, n)
   
   
    For j = 1 To n
        For i = j To n
            If i = 1 And j = 1 Then
            Else
                Worksheets("sheet3").Cells(i * 2 - 2 + 5, j) = el(i, j)
            End If
        Next i
    Next j
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267055/b3f45160-65f1-d945-c607-cdfc7f95d5e0.png)
エクセルシートのボタンを押すと実行されます。結果はSheet 2と同じです。

# 参考

[多変量正規分布に従う乱数生成の背景にはCholesky分解がいた](https://qiita.com/9uant/items/a323d82d5eb9f3a380df)
[Numerical Recipes in CのCholesky分解ルーチンをExcel VBAに移植](https://sci.tea-nifty.com/blog/2012/08/numerical-recip.html)
Numerical recipes in C