VBAユーザがPython・Rを使ってみた：簡単なプログラムの例

# はじめに

機械学習の勉強を始めたVBAユーザです。
備忘録としてPython・Rの文法をVBAと比較しながらまとめていきたいと思います。

今回は、簡単なプログラムをそれぞれの言語で書いてみたいと思います。


**目次**

- [簡単なプログラムの例](#簡単なプログラムの例)
   - [偶数と奇数](#偶数と奇数)
      - [別の書き方](#別の書き方)
   - [素数](#素数)
   - [等差数列](#等差数列)
   - [等比数列](#等比数列)
   - [フィボナッチ数](#フィボナッチ数)


# 簡単なプログラムの例
簡単な定義の数列を書き出すプログラムの例です。

## 偶数と奇数
0から10までの[偶数](https://ja.wikipedia.org/wiki/偶数)（even number）と[奇数](https://ja.wikipedia.org/wiki/奇数)（odd number）をそれぞれ定義どおり計算して書き出すプログラムを書いてみます。
**定義：**
偶数は、2で割り切れる整数のこと。
奇数は、2で割り切れない整数のこと。

**Python**

```Python:Python3
# 0から10までの偶数を書き出す
for n in range(0, 10+1):
    if n % 2 == 0:
        print(n)
# 0
# 2
# 4
# 6
# 8
# 10

# 0から10までの奇数を書き出す
for n in range(0, 10+1):
    if n % 2 == 1:
        print(n)
# 1
# 3
# 5
# 7
# 9
```

**R**

```R:R
# 0から10までの偶数を書き出す
for (n in 0:10) {
  if (n %% 2 == 0) {
    print(n)
  }
}
# [1] 0
# [1] 2
# [1] 4
# [1] 6
# [1] 8
# [1] 10

# 0から10までの奇数を書き出す
for (n in 0:10) {
  if (n %% 2 == 1) {
    print(n)
  }
}
# [1] 1
# [1] 3
# [1] 5
# [1] 7
# [1] 9
```

**VBA**

```VBA:VBA
Dim n As Integer

' 0から10までの偶数を書き出す
For n = 0 To 10
  If n Mod 2 = 0 Then
    Debug.Print n
  End If
Next n
' 0
' 2
' 4
' 6
' 8
' 10

' 0から10までの奇数を書き出す
For n = 0 To 10
    If n Mod 2 = 1 Then
        Debug.Print n
    End If
Next n
' 1
' 3
' 5
' 7
' 9
```

### 別の書き方
いくつか別の書き方をしてみます。

#### リスト内包表記
Pythonの[リスト内包表記](https://docs.python.org/ja/3.5/tutorial/datastructures.html#list-comprehensions)を使うとこのように簡潔に書けます。

```Python:Python3
[n for n in range(0, 10+1) if n % 2 == 0]
# [0, 2, 4, 6, 8, 10]

[n for n in range(0, 10+1) if n % 2 == 1]
# [1, 3, 5, 7, 9]
```
これらはそれぞれ次のコードと等価です:

```Python:Python3
nums = []
for n in range(0, 10+1):
    if n % 2 == 0:
        nums.append(n)
nums
# [0, 2, 4, 6, 8, 10]

nums = []
for n in range(0, 10+1):
    if n % 2 == 1:
        nums.append(n)
nums
# [1, 3, 5, 7, 9]
```


#### ベクトルの演算
Rのベクトルの演算を使うとこのように書けます。

```R:R
v <- 0:10

v %% 2 == 0
#  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
v[v %% 2 == 0]
#  0  2  4  6  8 10

v %% 2 == 1
# FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
v[v %% 2 == 1]
#  1 3 5 7 9
```

Pythonでも、Numpy の numpy.ndarray を使うと同じように書けます。

```Python:Python3
import numpy as np
v = np.arange(0, 10+1)

print(v % 2 == 0)
# [ True False  True False  True False  True False  True False  True]
list(v[v % 2 == 0])
# [0, 2, 4, 6, 8]

print(v % 2 == 1)
# [False  True False  True False  True False  True False  True False]
list(v[v % 2 == 1])
# [1, 3, 5, 7, 9]
```

#### 等差数列として
定義からそのまま計算したものではなくなりますが、等差数列になることを考えれば、もちろんこのようにも書けます。

```Python:Python3
list(range(0, 10+1, 2))
# [0, 2, 4, 6, 8, 10]
list(np.arange(0, 10+1, 2))
# [0, 2, 4, 6, 8, 10]

list(range(1, 10+1, 2))
# [1, 3, 5, 7, 9]
list(np.arange(1, 10+1, 2))
# [1, 3, 5, 7, 9]
```

```R:R
seq(0, 10, by=2)
#  0  2  4  6  8 10
seq(1, 10, by=2)
# 1 3 5 7 9
```

#### 一般項を求めてリスト内包表記で
また、一般項を考えればもちろんこのようにも書けます。
$a_n = a_1 + (n-1)*2$

```Python:Python3
[0 + (n-1)*2 for n in range(1,10+1) if 0 + (n-1)*2 <= 10]
# [0, 2, 4, 6, 8, 10]

[1 + (n-1)*2 for n in range(1,10+1) if 1 + (n-1)*2 <= 10]
# [1, 3, 5, 7, 9]
```

#### 一般項を求めてベクトルの演算で
```Python:Python3
import numpy as np

v = 0 + np.arange(0, 10+1) * 2
list(v[v <= 10])
# [0, 2, 4, 6, 8, 10]

v = 1 + np.arange(0, 10+1) * 2
list(v[v <= 10])
# [1, 3, 5, 7, 9]
```

```R:R
v <- 0 + 0:10 * 2
v[v <= 10]
#  0  2  4  6  8 10

v <- 1 + 0:10 * 2
v[v <= 10]
# 1 3 5 7 9
```



## 素数
1から50までの[素数](https://ja.wikipedia.org/wiki/素数)（prime number）を書き出してみます。
**定義：**
素数は、1より大きい自然数で、正の約数が1と自分自身のみであるもののこと。正の約数の個数が2である自然数と言い換えることもできる。

**Python**

```Python:Python3
# 1から50までの素数を書き出す
for n in range(1, 50+1):
    count = 0
    for m in range(1, n+1):
        if n % m == 0:
            count += 1
    if count == 2:
        print(n, end=' ')
print()   # 改行
# 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 
```

**R**

```R:R
# 1から50までの素数を書き出す
for (n in 1:50) {
  count <- 0
  for (m in 1:n) {
    if (n %% m == 0) {
      count = count + 1
    }
  }
  if (count == 2) {
    cat(n, "")
  }
}
# 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 
```

**VBA**

```VBA:VBA
Dim n As Integer
Dim m As Integer
Dim count As Integer

' 1から50までの素数を書き出す
For n = 1 To 50
    count = 0
    For m = 1 To n
        If n Mod m = 0 Then
            count = count + 1
        End If
    Next m
    If count = 2 Then
        Debug.Print n;
    End If
Next n
Debug.Print ""   ' 改行
' 2  3  5  7  11  13  17  19  23  29  31  37  41  43  47
```


## 等差数列
初項 $a_1=1$、公差 $d=2$ の[等差数列](https://ja.wikipedia.org/wiki/等差数列)（arithmetic sequence）の最初の10項を書き出してみます。
**定義：**
初項 $a_1$、公差 $d$ の等差数列 $a_n$ は、次の漸化式で定義される：

```math
\begin{eqnarray*}
a_n &=& a_1 &(n = 1) \\
a_n &=& a_{n-1} + d \quad &(n \geq 2)
\end{eqnarray*} \\
```

**Python**

```Python:Python3
# 初項a1=1、公差d=2の等差数列の最初の10項を書き出す
a1 = 1
d = 2
for n in range(1, 10+1):
    if n == 1:
        an = a1
    else:
        an += d
    print(an, end=' ')
print()   # 改行
# 1 3 5 7 9 11 13 15 17 19 
```

**R**

```R:R
# 初項a1=1、公差d=2の等差数列の最初の10項を書き出す
a1 <- 1
d <- 2
for (n in 1:10) {
  if (n == 1) {
    an <- a1
  } else {
    an <- an + d
  }
  cat(an, "")
}
# 1 3 5 7 9 11 13 15 17 19 
```

**VBA**

```VBA:VBA
Dim n As Integer
Dim a1 As Integer
Dim d As Integer
Dim an As Integer

' 初項a1=1、公差d=2の等差数列の最初の10項を書き出す
a1 = 1
d = 2
For n = 1 To 10
    If n = 1 Then
        an = a1
    Else
        an = an + d
    End If
    Debug.Print an;
Next n
Debug.Print ""   ' 改行
' 1  3  5  7  9  11  13  15  17  19
```

### 別の書き方
別の書き方をしてみます。

#### 等比数列なので
Python、Rには等比数列を作る関数がありますので、

```Python:Python3
list(range(a1, a1+(10-1)*d+1, d))
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
```

```R:R
seq(a1, a1+(10-1)*d, by=2)
#  1  3  5  7  9 11 13 15 17 19
```

#### 一般項を求めてリスト内包表記で
一般項は $a_n = a_1 + (n-1)d$ ですので、

```Python:Python3
a1 = 1
d = 2
[a1 + (n-1)*d for n in range(1, 10+1)]
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
```

#### 一般項を求めてベクトルの演算で

```Python:Python3
a1 = 1
r = 2
import numpy as np
ns = np.arange(1, 10+1)
print(ns)
# [ 1  2  3  4  5  6  7  8  9 10]
v = a1 + (ns - 1) * d
list(v)
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

v = a1 + (np.arange(1, 10+1) - 1) * d
list(v)
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
```

```R:R
a1 <- 1
d <- 2
ns <- 1:10
a1 + (ns - 1) * d
#  1  3  5  7  9 11 13 15 17 19
a1 + (1:10 - 1) * d
#  1  3  5  7  9 11 13 15 17 19
```


## 等比数列
初項 $a_1=1$、公差 $r=2$ の[等比数列](https://ja.wikipedia.org/wiki/等比数列)（geometric sequence）の1000以下の項を書き出してみます。
**定義：**
初項 $a_1$、公比 $r$ の等差数列 $a_n$ は、次の漸化式で定義される：

```math
\begin{eqnarray*}
a_n &=& a_1 &(n = 1) \\
a_n &=& a_{n-1} * r \quad &(n \geq 2)
\end{eqnarray*} \\
```

**Python**

```Python:Python3
# 初項a1=1、公比r=2の等比数列の1000以下の項を書き出す
a1 = 1
r = 2
an = a1
while an <= 1000:
    print(an, end=' ')
    an *= r
print()   # 改行
# 1 2 4 8 16 32 64 128 256 512 
```

**R**

```R:R
# 初項a1=1、公比r=2の等比数列の1000以下の項を書き出す
a1 <- 1
r <- 2
an <- a1
while (an <= 1000) {
  cat(an, "")
  an <- an * r
}
# 1 2 4 8 16 32 64 128 256 512 
```

**VBA**

```VBA:VBA
Dim n As Integer
Dim a1 As Integer
Dim r As Integer
Dim an As Integer

' 初項a1=1、公比r=2の等比数列の1000以下の項を書き出す
a1 = 1
r = 2
an = a1
Do While an <= 1000
    Debug.Print an;
    an = an * r
Loop
Debug.Print ""   ' 改行
' 1  2  4  8  16  32  64  128  256  512
```

### 別の書き方
別の書き方をしてみます。

#### 一般項を求めてリスト内包表記で
一般項は $a_n = a_1 r^{n-1}$ ですので、

```Python:Python3
a1 = 1
r = 2
[a1 * r**(n-1) for n in range(1, 20+1) if a1 * r**(n-1) <= 1000]
# [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
```
注意）`range(1, 20+1)`の`20`は適当に大きな数。以下も同様。

#### 一般項を求めてベクトルの演算で

```Python:Python3
a1 = 1
r = 2
import numpy as np
ns = np.arange(1, 20+1)
print(ns)
# [ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20]
v = a1 * r**(ns - 1)
list(v[v <= 1000])
# [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

v = a1 * r**(np.arange(1, 20+1) - 1)
list(v[v <= 1000])
# [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
```

```R:R
a1 <- 1
r <- 2
ns <- 1:20
v <- a1 * r^(ns - 1)
v[v <= 1000]
#   1   2   4   8  16  32  64 128 256 512
v <- a1 * r^(1:20 - 1)
v[v <= 1000]
#   1   2   4   8  16  32  64 128 256 512
```


## フィボナッチ数
[フィボナッチ数](https://ja.wikipedia.org/wiki/フィボナッチ数)（Fibonacci number）を書き出す例です。[Python チュートリアル](https://docs.python.org/ja/3/tutorial/index.html) にある[例](https://docs.python.org/ja/3/tutorial/introduction.html#first-steps-towards-programming)です。
**定義：**
フィボナッチ数列 $F_n (n \geq 0)$ は、次の漸化式で定義される：

```math
\begin{eqnarray*}
F_0 &=& 0 &(n = 0) \\
F_1 &=& 1 &(n = 1) \\
F_{n+2} &=& F_n + F_{n+1} \quad &(n \geq 0)
\end{eqnarray*} \\
```

**Python**
Pythonでは、複数同時の代入 (multiple assignment) ができるので、他の言語より少し簡単に書けます。

```Python:Python3
# フィボナッチ数列の1000以下の項を書き出す
f0 = 0
f1 = 1
fn = f0
fnp1 = f1
while fn <= 1000:
    print(fn, end=' ')
    fnp2 = fn + fnp1
    fn = fnp1
    fnp1 = fnp2
print()   # 改行
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 

fn, fnp1 = f0, f1
while fn <= 1000:
    print(fn, end=' ')
    fn, fnp1 = fnp1, fn+fnp1
print()   # 改行
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
```

**R**

```R:R
# フィボナッチ数列の1000以下の項を書き出す
f0 <- 0
f1 <- 1
fn <- f0
fnp1 <- f1
while (fn <= 1000) {
  cat(fn, "")
  fnp2 <- fn + fnp1
  fn <- fnp1
  fnp1 <- fnp2
}
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
```

**VBA**

```VBA:VBA
Dim f0 As Integer
Dim f1 As Integer
Dim fn As Integer
Dim fnp1 As Integer
Dim fnp2 As Integer

' フィボナッチ数列の1000以下の項を書き出す
f0 = 0
f1 = 1
fn = f0
fnp1 = f1
Do While fn <= 1000
    Debug.Print fn;
    fnp2 = fn + fnp1
    fn = fnp1
    fnp1 = fnp2
Loop
Debug.Print ""   ' 改行
' 0  1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987
```