MATLABの配列操作からの入門〔※ 特にPython経験者向け〕

# はじめに

私は今まで科学計算や機械学習などはPythonを使ってきましたが、今仕事の関係でMATLABを使う必要になったのです。

私がPythonを使い始める前からMATLABのことは知っていたが、実際に使ったことないのでほとんどゼロから勉強です。

汎用性が高いPythonと違ってMATLABは数値解析に特化する言語なので、配列操作はほとんど全てで、どんな場面でも使うので配列の動作を理解することはとても重要です。

配列の扱いに関しては意外と色々Pythonのnumpyと似ていてPythonに慣れている人にとって勉強しやすくてすぐ飲み込みできますが、それでもある程度の違いや注意点も多くて、それを意識しながら使うのも重要です。

この記事は主にPythonを使っていた人に向いているMATLABの入門となります。

Pythonを使ったことない人でも読めると思いますが、ここでは主に「Pythonで普通にやっていることはMATLABならどうやる？」という見方で、基本などは省くので、Python経験を持ったらわかりやすいつもりです。

また、MATLABコードを載せるのと同時に、相当するPythonコードも一緒に載せるので、比較しながら理解していけます。

配列の他にMATLABはまだ色々面白いところがありますが、これを書いたら長くなるのでね今回は配列に関することだけ書きます。


# 本題 〜配列操作〜

## 配列の作成

### 1次元の配列の作成

MATLABの1次元の配列は`[ ]`で囲んだだけで簡単に作れます。各要素の間に空白` `かコンマ`,`どちら使っても同じです。
```matlab:matlab
ar = [7 6 5];
```
又は
```matlab:matlab
ar = [7,6,5];
```

空白` `で書いてもコンマ`,`で書いてもほとんど同じように使えますが、これからの例では全部空白` `で統一します。

:::note info
MATLABでは後ろのセミコロン`;`は「表示しないで動かす」ようにするための役割です。
`;`がなくてもコードの動きは変わりませんが、`;`がないと関数や代入の返り値が表示されます。それはPythonなどで`print`を使うのと似ています。
表示したいかどうかで使い分けしましょう。
:::

Pythonで配列を作る時にまずnumpyを`import`しておかないと使えない上に、配列を作る時も冗長です。
```python:python
import numpy as np
ar = np.array([7,6,5])
```

MATLABでは配列は基本的な機能なのですぐ使えるし、書き方も簡潔です。これを見るとMATLABの方が楽ですね。

### 2次元の配列の作成

MATLABでは`;`で挟むことで行を区分することになります。こうやって簡単に数行を持つ2次元の配列が作れます。
```matlab:matlab
[8 7 6 5; 3 4 5 6]
```
```:結果
     8     7     6     5
     3     4     5     6
```

または改行して書くことも同じような2次元配列ができます。こう書いた方がわかりやすいですね。
```matlab:matlab
[8 7 6 5
 3 4 5 6]
```

Pythonでは2重の`[ ]`で囲むことでできます。
```python:python
np.array([[8,7,6,5],[3,4,5,6]])
```
```:結果
array([[8, 7, 6, 5],
       [3, 4, 5, 6]])
```

:::note info 
ちなみにMATLABでは1次元の配列を特に「ベクトル」と呼び、2次元の配列を「行列」と呼びます。
更に横に並ぶベクトルは「行ベクトル」と呼び、縦に並ぶベクトルは「列ベクトル」と呼びます。
公式サイトでもこの呼び方がよく使われているから資料を読むには覚えておく必要がありますね。
:::

### 3次元以上の配列の作成

1、2次元配列なら簡単に作れるMATLABですが、3次元以上は直接作る方法がないので、意外と面倒な気もします。

一行のコードで書きたい場合[`cat`](https://jp.mathworks.com/help/matlab/ref/double.cat.html)関数によって作るという方法があります。
```matlab:matlab
cat(3,[1 2 3 4;5 6 7 8],[9 8 7 6; 5 4 3 2])
```
結果はこんな風に表示されます。
```:結果
ans(:,:,1) =

     1     2     3     4
     5     6     7     8


ans(:,:,2) =

     9     8     7     6
     5     4     3     2
```

後で説明しますが、[`cat`](https://jp.mathworks.com/help/matlab/ref/double.cat.html)は配列の連結に使う関数です。`cat(3,`の`3`という数値は「3つ目の次元」で結合するという意味です。

Pythonでは3重の`[ ]`で作れます。これの方が直感的かもしれません。
```python:python
np.array([[[1,2,3,4],[5,6,7,8]],[[9,8,7,6],[5,4,3,2]]])
```
```:結果
array([[[1, 2, 3, 4],
        [5, 6, 7, 8]],

       [[9, 8, 7, 6],
        [5, 4, 3, 2]]])
```

ただしこれは上述のMATLABと同じにはならない。MATLABの`cat`では新しい軸は最後の方に加えるから。

それと同じものを作るには`dstack`を使います。
```python:python
np.dstack([[[1,2,3,4],[5,6,7,8]],[[9,8,7,6],[5,4,3,2]]])
```
```:結果
array([[[1, 9],
        [2, 8],
        [3, 7],
        [4, 6]],

       [[5, 5],
        [6, 4],
        [7, 3],
        [8, 2]]])
```

表示の仕方は違うが、これこそが上述のMATLABと同じ3次元配列です。


## 配列の連結

`cat`関数は配列の連結に使いますが、2次元での連結の場合は関数を使わなくても連結できます。

配列を`[]`で囲んだら横方向に並んで連結することになります。
```matlab:matlab
ar1 = [1 1;3 3];
ar2 = [2 2;4 4];
[ar1 ar2]
```
```:結果
     1     1     2     2
     3     3     4     4
```

`cat`関数ではこう書きます。
```matlab:matlab
cat(2,ar1,ar2)
```

その他にも[`horzcat`](https://jp.mathworks.com/help/matlab/ref/double.horzcat.html)という関数が使えます。
```matlab:matlab
horzcat(ar1,ar2)
```

これはPythonの`hstack`と同じです。
```python:python
ar1 = np.array([[1,1],[3,3]])
ar2 = np.array([[2,2],[4,4]])
np.hstack([ar1,ar2])
```
```:結果
array([[1, 1, 2, 2],
       [3, 3, 4, 4]])
```

もし`;`で挟んだら縦方向での連結となります。
```matlab:matlab
[ar1;ar2]
```
```:結果
     1     1
     3     3
     2     2
     4     4
```

`cat`関数ではこう書きます。
```matlab:matlab
cat(1,ar1,ar2)
```

又は[`vertcat`](https://jp.mathworks.com/help/matlab/ref/double.vertcat.html)という関数も使えます。
```matlab:matlab
vertcat(ar1,ar2)
```

Pythonでは`vstack`。
```python:python
np.vstack([ar1,ar2])
```
```:結果
array([[1, 1],
       [3, 3],
       [2, 2],
       [4, 4]])
```


## 同じ値が並ぶ配列を作る

「0」しかない指定サイズの配列を作りたければ`zeros`という関数が使えます。

```matlab:matlab
zeros(3,4,2)
```
```:結果
ans(:,:,1) =

     0     0     0     0
     0     0     0     0
     0     0     0     0


ans(:,:,2) =

     0     0     0     0
     0     0     0     0
     0     0     0     0
```

又は各次元のサイズを収める配列を入力として使うこともできます。こう書いても上記と同じ結果
```matlab:matlab
zeros([3 4 2])
```

ただし、数字n一つしか入れない場合は勝手にn×nの行列になってしまいます。
```matlab:matlab
zeros(3)
```

```:結果
     0     0     0
     0     0     0
     0     0     0
```

1次元の配列が欲しい場合`(1,n)`と書きます。
```matlab:matlab
zeros(1,3)
```

```:結果
     0     0     0
```

同じように、「1」いっぱいの配列の場合は`ones`
```matlab:matlab
ones(4,3)
```

```:結果
     1     1     1
     1     1     1
     1     1     1
     1     1     1
```

Pythonでも同じような関数の名前なので覚えやすい。

```python:python
np.zeros([3,4,2])
np.ones([4,3,2])
```

0と1以外の値の場合は[repmat](https://jp.mathworks.com/help/matlab/ref/repmat.html)関数を使います。
```matlab:matlab
repmat(3,2,4)
```
```:結果
     3     3     3     3
     3     3     3     3
```

Pythonの`full`という関数と似ています。
```python:python
np.full([2,4],3)
```
```:結果
array([[3, 3, 3, 3],
       [3, 3, 3, 3]])
```

### 同じ配列の値を繰り返して並ぶ

`repmat`関数は同じよう配列をコピーして連結するのにも使えます。
```matlab:matlab
ar = [4 5 6];
repmat(ar,3,2)
```
```:結果
     4     5     6     4     5     6
     4     5     6     4     5     6
     4     5     6     4     5     6
```

Pythonの`tile`関数と似ています。
```python:python
ar = np.array([4,5,6])
np.tile(ar,[3,2])
```
```:結果
array([[4, 5, 6, 4, 5, 6],
       [4, 5, 6, 4, 5, 6],
       [4, 5, 6, 4, 5, 6]])
```

`repmat`と似ている関数として[`repelem`](https://jp.mathworks.com/help/matlab/ref/repelem.html)がありますが、繰り返し方は違います。
```matlab:matlab
ar = [1 2;3 4]
ar_repmat = repmat(ar,3,2)
ar_repelem = repelem(ar,3,2)
```
```:結果
ar =

     1     2
     3     4


ar_repmat =

     1     2     1     2
     3     4     3     4
     1     2     1     2
     3     4     3     4
     1     2     1     2
     3     4     3     4


ar_repelem =

     1     1     2     2
     1     1     2     2
     1     1     2     2
     3     3     4     4
     3     3     4     4
     3     3     4     4
```


## 乱数で配列を生成する

MATLABで乱数配列を作る関数を持っています。

`rand`関数は0から1を一様分布でランダムする乱数を作ります。サイズの配列の指定`zeros`と`ones`と同じ
```matlab:matlab
rand(3,4)
```
```:結果
    0.9058    0.6324    0.5469    0.1576
    0.1270    0.0975    0.9575    0.9706
    0.9134    0.2785    0.9649    0.9572
```

Pythonの`np.random.random`関数と同じですね。
```python:python
np.random.random([3,4])
```

`randn`は正規分布でランダムする乱数を作ります。
```matlab:matlab
randn(3,4)
```
```:結果
   -0.0631   -0.1241    1.4172    0.7172
    0.7147    1.4897    0.6715    1.6302
   -0.2050    1.4090   -1.2075    0.4889
```

Pythonではの`np.random.randn`関数と同じです。
```python:python
np.random.randn(3,4)
```

`randi`は指定した範囲の整数でランダムする乱数の配列を作成します。
```matlab:matlab
randi([7 9],3,4)
```
```:結果
     7     8     9     8
     9     8     7     8
     7     9     8     9
```

Pythonでは同じようなことをこう書きます。
```python:python
np.random.randint(7,9+1,[3,4])
```

Pythonの`np.random.randint`と違ってMATLABの`randi`は上限の値を含むので`+1`が必要ないというところは注意です。

上限だけ指定することもできます（その場合`[ ]`は要らない）。その場合は1からその上限の値までとなります。
```matlab:matlab
randi(3,2,5)
```
```:結果
     3     3     1     2     2
     1     2     1     3     2
```

Pythonの`np.random.randint`ではこういう省略はないので普通の1を入れます。
```python:python
np.random.randint(1,3+1,[2,5])
```


## 等間隔の連続値を持つ配列を作成する

### 範囲と間隔を指定する

MATLABで連続の数字の配列が欲しいならこのように`:`で簡単に作れます。
```matlab:matlab
5:9
```
```:結果
     5     6     7     8     9
```

これはPythonの`np.arange`関数と同じですが、Pythonでは最後が含まれないので`+1`が必要です。
```python:python
np.arange(5,9+1)
```
```:結果
array([5, 6, 7, 8, 9])
```

書き方がシンプルで、しかも関数を使わなくても文法で簡単に作れるMATLABは楽ですね。

間隔が1ではない場合は間隔を中間に入れます。
```matlab:matlab
4:3:13
```
```:結果
     4     7    10    13
```

Pythonの`arange`では間隔の値を最後に置くので、書く場所が逆なのは注意です。
```python:python
np.arange(4,13+1,3)
```
```:結果
array([ 4,  7, 10, 13])
```

### 範囲と数を指定する（linspace）

下限と上限を指定して作りたい場合は`linspace`を使うことができます。書き方は`linspace(下限,上限,数)`です。
```matlab:matlab
linspace(4,6,5)
```
```:結果
    4.0000    4.5000    5.0000    5.5000    6.0000
```

Pythonでも同じ関数の名前で同じような書き方です。
```python:python
np.linspace(4,6,5)
```
```:結果
array([4. , 4.5, 5. , 5.5, 6. ])
```

ただしPythonでは上限が要らないという場合は最後に`False`を入れてることでできます。
```python:python
np.linspace(4,6,5,False)
```
```:結果
array([4. , 4.4, 4.8, 5.2, 5.6])
```

MATLABではこんなことができないので残念です。


## 要素の参照

### 1次元配列の要素

1次元の配列の中の値を取るには`( )`で囲んで取りたい順番を入れるのです。
```matlab:matlab
ar = [7 8 9];
ar(2)
```
```:結果
     8
```

:::note warn
MATLABではFortranと同じように配列のインデックスは「1」から始めます。これは「0」から数えるC、Python、Ruby、JavaScript、PHP、[IDL](https://qiita.com/phyblas/items/c62e8e9b4cb51a4b9447)など大半の言語と違います。

CやPythonみたいに`[ ]`ではなく、`( )`で囲むというところもFortranと同じです。
:::

Pythonの場合。
```python:python
ar = np.array([7,8,9])
ar[1]
```
```:結果
8
```

また、`( )`は直接配列の変数の後ろに置かなければならない。例えばPythonではこう書けます。
```python:python
np.linspace(1,3,5)[3]
```
```:結果
2.5
```

しかしMATLABこれはエラーとなります。
```matlab:matlab
linspace(1,3,5)(4)
```
```:結果
エラー: 配列のインデックス付けが無効です。
```

だから一旦変数に収める必要なので、ちょっと面倒かもしれません。
```matlab:matlab
ar = linspace(1,3,5);
ar(4)
```
```:結果
    2.5000
```

### 2次元配列の要素

2次元配列へのアクセスは`,`で挟んで各軸での順番を指定するのです。

```matlab:matlab
ar = [9 8;7 5;4 3];
ar(3,1)
```
```:結果
     4
```

Pythonでも似ています。
```python:python
ar = np.array([[9,8],[7,5],[4,3]])
ar[2,0]
```
```:結果
4
```

ただし、一つしか数字を入れない場合、それは全体から見る順番で入ることになります。
```matlab:matlab
ar = [9 8 7; 5 4 3];
ar(3)
```
```:結果
     8
```

順番は各列の全部の要素から数えるので、ここでは9, 5, 8, ...ということで３番目は8となります。

Pythonで同じような書き方したら、「i-1行目を取る」ということになりますね。

その場合MATLABでは`,:`を書く必要があります。
```matlab:matlab
ar = [1 2 3; 4 5 6; 7 8 9]
ar(2,:)
```
```:結果
     4     5     6
```

これはPythonでこう書くのと同じ。
```python:python
ar = np.array([[1,2,3],[4,5,6],[7,8,9]])
ar[1]
```
```:結果
array([4, 5, 6])
```

逆に「i列の全ての行を取る」場合はこのように書きます。
```matlab:matlab
ar = [1 2 3; 4 5 6; 7 8 9]
ar(:,2)
```
```:結果
     2
     5
     8
```

これはPythonでこう書くのと同じ。
```python:python
ar = np.array([[1,2,3],[4,5,6],[7,8,9]])
ar[:,1]
```
```:結果
array([2, 5, 8])
```

ただしPythonでは横に並ぶ配列に変わるのに対し、MATLABではこの場合縦に並ぶ形のままです。

MATLABで1次元配列は縦と横2種類ありますが、Pythonでは全部横だから。

### 最後からの順番を指定して

最後から数える順番の指定で取りたい場合は`end`を使います
```matlab:matlab
ar = [1 2 3 4];
ar(end)
```
```:結果
     4
```
```matlab:matlab
ar(end-1)
```
```:結果
     3
```

Pythonでは負の数字を使うのでその方が書きやすいです。
```python:python
ar = np.array([1,2,3,4])
ar[-1]
```
```:結果
4
```
```python:python
ar[-2]
```
```:結果
3
```

### 範囲を指定して取る

`a:b`と書くと配列の指定したaからbの範囲内の要素を全部取ることになります。

```matlab:matlab
ar = [7 3 5 8 6 2]
ar(2:4)
```
```:結果
     3     5     8
```

これはPythonと同じです。
```python:python
ar = np.array([7,3,5,8,6,2])
ar[1:4]
```
```:結果
array([3, 5, 8])
```

最後まで取りたい場合Pythonでは`:`の後の数字を省略できますが、MATLABではそんな省略はできず、`end`を書く必要があります。
```matlab:matlab
ar(2:end)
```
```:結果
     3     5     8     6     2
```
```python:python
ar[1:]
```
```:結果
array([3, 5, 8, 6, 2])
```


## 配列のサイズを調べる

`size`関数を使えば配列の各軸のサイズがわかります。
```matlab:matlab
ar = rand(5,6,7,9);
size(ar)
```
```:結果
     5     6     7     9
```

Pythonの`.shape`と同じです。
```python:python
ar = np.random.random([5,6,7,9])
ar.shape
```
```:結果
(5, 6, 7, 9)
```

ただしこれは1次元の配列に使っても最低限2の数字ができます。
```matlab:matlab
size([9 9 9])
```
```:結果
     1     3
```

ある軸だけのサイズを取る場合はその軸の番号を指定します。
```matlab:matlab
ar = zeros(5,4,3,2)
size(ar,2)
```
```:結果
     4
```

一次元配列のサイズは普段`length`関数を使います。ただし`length`関数は最後の軸でのサイズを返します。
```matlab:matlab
ar = randn(3,6,2,11)
length(ar)
```
```:結果
    11
```

Pythonのリストなどの長さを図る`len`関数と似ていますが、配列に使う場合は最初の軸のサイズを返します。この動作の違いも注意です。
```python:python
ar = np.random.randn(3,6,2,11)
len(ar)
```
```:結果
3
```

またPythonでは`size`が配列全体の要素数を返します。MATLABでは[`numel`](https://jp.mathworks.com/help/matlab/ref/double.numel.html)という関数を使います。
```matlab:matlab
ar = randn(3,3,3);
numel(ar)
```
```:結果
    27
```
```python:python
ar = np.random.randn(3,3,3)
ar.size
```
```:結果
27
```


## 配列を逆に並べ替える

### 最初と最後を逆転させる

配列を逆にさせるために[`flip`](https://jp.mathworks.com/help/matlab/ref/flip.html)という関数があります。
```matlab:matlab
ar = [2 3 4];
flip(ar)
```
```:結果
     4     3     2
```

実は関数を使わなくても`end:-1:1`と書けばいいが、関数を使う方が書きやすいかも。
```matlab:matlab
ar(end:-1:1)
```

同じようなことはPythonなら簡単な方法があって書きやすいです。
```python:python
ar = np.array([2,3,4])
ar[::-1]
```
```:結果
array([4, 3, 2])
```

2次元の配列の場合`flip`は上と下を逆にさせますが、横の方向にしたいなら軸の番号を指定します。
```matlab:matlab
ar0 = [1 1 3;1 1 3;3 3 3]
ar1 = flip(ar0) % 又は flip(ar0,1)
ar2 = flip(ar0,2)
ar3 = ar0(end:-1:1,end:-1:1)
```
```:結果
ar0 =

     1     1     3
     1     1     3
     3     3     3


ar1 =

     3     3     3
     1     1     3
     1     1     3


ar2 =

     3     1     1
     3     1     1
     3     3     3


ar3 =

     3     3     3
     3     1     1
     3     1     1
```

### 2次元配列における転置行列（transpose）

2次元配列の転置行列（行と列の軸を逆転させること）は[`transpose`](https://jp.mathworks.com/help/matlab/ref/transpose.html)関数でできます。
```matlab:matlab
ar0 = [1 2 3;4 4 4;5 6 6]
ar1 = transpose(ar0)
```
```:結果
ar0 =

     1     2     3
     4     4     4
     5     6     6


ar1 =

     1     4     5
     2     4     6
     3     4     6
```

ただし実はもっと簡単な方法があります。それはただ`'`をつけるということです。
```matlab:matlab
[1 1 1;6 6 6]'
```
```:結果
     1     6
     1     6
     1     6
```

Pythonで`.T`を付けるのと同じです。
```python:python
np.array([[1,1,1],[6,6,6]]).T
```
```:結果
array([[1, 6],
       [1, 6],
       [1, 6]])
```


### 3次元配列における軸の入れ替え

`transpose`関数も`'`も2次元の配列にしか使えないのです。3次元以上の場合は[`permute`](https://jp.mathworks.com/help/matlab/ref/permute.html)という関数を使います。

```matlab:matlab
ar = ones(2,3,4);
ar = permute(ar,[3 1 2]);
size(ar)
```
```:結果
     4     2     3
```

Pythonでは同じようなことを`transpose`関数でできます。2次元専用のMATLABの`transpose`と違って、Pythonの`transpose`何次元にでも使えます。
```python:python
ar = np.ones([2,3,4])
ar = np.transpose(ar,[2,0,1])
ar.shape
```
```:結果
(4, 2, 3)
```


## データ型

MATLABの数字のデータ型が色々ありますが、指定しない限り基本的に全てはdouble（倍精度配列）となります。

`class`関数でデータ型を調べることができます。
```matlab:matlab
ar = [1 3 5];
class(ar)
```
```:結果
    'double'
```

データ型を変更するにはそのデータ型の名前と同じ関数を使えばいい。
```matlab:matlab
ar = uint8([7 6 3]);
class(ar)
```
```:結果
    'uint8'
```

画像処理では[uint8](https://jp.mathworks.com/help/matlab/ref/uint8.html)がよく使われています。

MATLABで真偽を示す値は[logical](https://jp.mathworks.com/help/matlab/ref/logical.html)というデータ型です。普段はtrueとfalseではなく0と1と表示します。数字から変換する場合は0がfalseで、それ以外の数字はtrueとなります。
```matlab:matlab
class(5>3)
```
```:結果
    'logical'
```

## 演算子による配列の計算

### 足し算と引き算

MATLABの配列は同じサイズの配列と`+`か`-`を使ったら要素ごとの足し算と引き算となります。
```matlab:matlab
ar1 = 3:6
ar2 = ones(1,4)
ar3 = ar1+ar2
ar4 = ar1-ar2
```
```:結果
ar1 =

     3     4     5     6


ar2 =

     1     1     1     1


ar3 =

     4     5     6     7


ar4 =

     2     3     4     5
```

配列と一つの数字の計算もできます。
```matlab:matlab
[4 4 5 5]+10
```
```:結果
    14    14    15    15
```

これはPythonと同じです。
```python:python
np.array([4,4,5,5])+10
```
```:結果
array([14, 14, 15, 15])
```

### 掛け算と割り算と冪乗

掛け算の場合は足し算と割り算のように簡単ではなく、MATLABでは配列の`*`は「行列の積」と見做されます。単に要素ごとの掛け算が欲しい場合は`.*`と書きます。
```matlab:matlab
ar1 = [1 1;2 2]
ar2 = [3 3;4 4]
ar3 = ar1*ar2
ar4 = ar1.*ar2
```
```:結果
ar1 =

     1     1
     2     2


ar2 =

     3     3
     4     4


ar3 =

     7     7
    14    14


ar4 =

     3     3
     8     8
```

Pythonなら`*`は普通の要素ごとの掛け算で、行列の席は`dot`関数を使うのです。
```python:python
ar1 = np.array([[1,1],[2,2]])
ar2 = np.array([[3,3],[4,4]])
np.dot(ar1,ar2)
```
```:結果
array([[ 7,  7],
       [14, 14]])
```
```python:python
ar1*ar2
```
```:結果
array([[3, 3],
       [8, 8]])
```

同じく、割り算と冪乗も`.`を付ける必要があります。

割り算は`./`。
```matlab:matlab
[3 3 6]./[1.5 3 1.5]
```
```:結果
     2     1     4
```

冪乗は`.^`。
```matlab:matlab
[2 3 5].^2
```
```:結果
     4     9    25
```

間違って`.`を忘れたらたとえエラー゛が出なくても望むのと違う結果になるので特に要注意です。

### 論理演算子

論理演算子は単体の数字でも配列でも同じように使えます。
- andは`&`
- orは`|`
- notは`~`
```matlab:matlab
ar1 = logical([1 1 0 0])
ar2 = logical([1 0 1 0])
ar_and = ar1&ar2
ar_or = ar1|ar2
ar_not = ~ar1
```
```:結果
ar1 =

  1×4 の logical 配列

   1   1   0   0


ar2 =

  1×4 の logical 配列

   1   0   1   0


ar_and =

  1×4 の logical 配列

   1   0   0   0


ar_or =

  1×4 の logical 配列

   1   1   1   0


ar_not =

  1×4 の logical 配列

   0   0   1   1
```

### 複素数ができる計算

MATLABでは冪乗などでデータ型doubleの配列が複素数になってしまう場合はそのまま複素数の配列になります。
```matlab:matlab
[-1 0 1].^0.5
```
```:結果
   0.0000 + 1.0000i   0.0000 + 0.0000i   1.0000 + 0.0000i
```

ただし複素数になってもデータ型としてはdoubleのままで、別のデータ型となるわけではないです。

それはPythonだったら普通のfloat配列は複素数にはならず、nanになってしまいます。
```python:python
np.array([-1,0,1])**0.5
```
```:結果
array([nan,  0.,  1.])
```

こうやって自動的に複素数になるMATLABは便利ですね。

ただしデータ型が整数タイプにされていたら駄目です。
```matlab:matlab
int8([-1 0 1]).^0.5
```
```:結果
次を使用中のエラー:  .^ 
整数は、正の整数乗のみが許容されます。
```


## 条件を満たす要素だけ抽出する方法

配列の中で条件を指定してある要素だけ取得することができます。
```matlab:matlab
ar = [9 5 8 7 4 6];
ar(ar<6)
```
```:結果
     5     4
```

それはPythonと同じです。
```python:python
ar = np.array([9,5,8,7,4,6])
ar[ar<6]
```
```:結果
array([5, 4])
```

その一部の値にアクセスして値を変更することもできます。
```matlab:matlab
ar = [8 7 6 5 4];
ar(ar>5) = 9
```
```:結果
     9     9     9     5     4
```
```python:python
ar = np.array([8,7,6,5,4])
ar[ar>5] = 9
ar
```
```:結果
array([9, 9, 9, 5, 4])
```


## 配列を変形する

### 各軸のサイズを指定して変形

`reshape`関数で配列を好きな形に再編成することができます。
```matlab:matlab
ar = 1:12;
reshape(ar,4,3)
```
```:結果
     1     5     9
     2     6    10
     3     7    11
     4     8    12
```

ただしMATLABでは縦から数えるから、同じようなことをPythonでやったら違う結果になります。
```python.python
ar = np.arange(1,13)
ar.reshape(4,3)
```
```:結果
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])
```

横から並べたい場合は後で`'`などで転置するのです。
```matlab:matlab
ar = 1:12;
reshape(ar,3,4)'
```
```:結果
     1     2     3
     4     5     6
     7     8     9
    10    11    12
```

### 一つの軸のサイズを省いて変形する

もし沢山軸があって、例えばn軸がある場合n-1軸だけサイズを指定したら残りの一つは書かなくてもわかるので、省略できます。その場合はその軸の位置に`[]`で入れ替えます。
```matlab:matlab
ar = 1:36;
ar = reshape(ar,3,[],2);
size(ar)
```
```:結果
     3     6     2
```

Pythonで`-1`を使うのと同じです。
```python:python
ar = np.arange(1,37)
ar = ar.reshape(3,-1,2)
ar.shape
```
```:結果
(3, 6, 2)
```

### 1次元の配列にする

一次元にしたい時`(:)`を付けます。
```matlab:matlab
ar = rand(2,4);
ar(:)
```
```:結果
    0.1496
    0.3508
    0.3360
    0.7840
    0.4867
    0.4648
    0.1313
    0.8864
```

ただしこの方法では縦で並ぶ配列になるので、横に並べたい場合`'`を付けます。
```matlab:matlab
ar = ones(2,4);
ar(:)'
```
```:結果
     1     1     1     1     1     1     1     1
```

又は`reshape`関数を使います。
```matlab:matlab
reshape(ar,1,[])
```

Pythonでは`ravel`メソッドを使います。
```python:python
ar = np.ones([2,4])
ar.ravel()
```
```:結果
array([1., 1., 1., 1., 1., 1., 1., 1.])
```


## 配列内の最小値と最大値を求める

### 1次元の配列の最小値と最大値

配列の中の最小値と最大値を求めるために[`min`](https://jp.mathworks.com/help/matlab/ref/min.html)と[`max`](https://jp.mathworks.com/help/matlab/ref/max.html)という関数があります。

1次元の配列の場合は全ての要素の最小値と最大値となります。
```matlab:matlab
ar = [7 5 3 6];
min(ar)
```
```:結果
     3
```

### 2次元の配列の最小値と最大値

2次元の配列に使う場合は各列の最小値と最大値を取った1次元の配列にします。
```matlab:matlab
ar = [3 1 2;1 4 3];
max(ar)
```
```:結果
     3     4     3
```

Pythonでこう書くのと同じ。
```python:python
ar = np.array([[3,1,2],[1,4,3]])
ar.max(0)
```
```:結果
array([3, 4, 3])
```

逆に各行の最小値と最大値を取りたい場合はこう書きます。
```matlab:matlab
ar = [3 4;4 2;5 3];
max(ar,[],2)
```
```:結果
     4
     4
     5
```

Pythonでこう書くのと似ていますが、MATLABの方は縦のままで、Pythonは横に並ぶことになるのでわかりにくいかもしれません。
```python:python
ar = np.array([[3,4],[4,2],[5,3]])
ar.max(1)
```
```:結果
array([4, 4, 5])
```

もし全体の最小値と最大値である一つだけ取りたい場合は`(:)`を付けます

```matlab:matlab
ar = [1 9 7;0 2 2; 5 5 5];
max(ar(:))
```
```:結果
     9
```

Pythonでこれがデフォルトの`min`と`max`の動作ですね。
```python:python
ar = np.array([[1,9,7],[0,2,2],[5,5,5]])
ar.max()
```
```:結果
9
```

:::note info
その他に`sum`、`mean`、`std`、`var`、`median`という、総和、平均値、標準偏差、分散、中央値を求める関数があります。使い方は`min`と`max`と大体似ています。
:::

### 最小値と最大値の要素の位置を取る

実は`min`と`max`は最小値と最大値を返すだけでなく、同時に最小値と最大値の要素が置かれている位置を返すこともできます。

返り血を受ける変数を2つにすることで２つ目の変数に最小値と最大値の位置が入ります。
```matlab:matlab
ar = [1 9 2 8 3 7 4];
[ar_max,ar_argmax] = max(ar)
```
```:結果
ar_max =

     9


ar_argmax =

     2
```

Pythonでは`argmin`と`argmax`という別のメソッドがあるからそれを使っていいです。
```python:python
ar = np.array([1,9,2,8,3,7,4])
ar.argmax()
```
```:結果
1
```

:::note info
MATLABでは2つ以上の返り値を返す関数がありますが、もし返り値受ける変数が一つしかない場合2つ目の返り値が無視されます。
それを受けるために`[ ]`で囲んで受ける変数を並べます。

ただし1つ目の関数が要らない場合は`~`を書きます。
:::

最小値か最大値の位置だけ欲しい場合はこう書いたらいいです。
```matlab:matlab
ar = [5 5 1 5 5];
[~,a] = min(ar)
```
```:結果
a =

     3
```


## 要素の値のよって配列を並べ替える

### 1次元配列の並べ替え
[`sort`](https://jp.mathworks.com/help/matlab/ref/sort.html)関数は並べ替えた配列を返します。
```matlab:matlab
ar = [3 7 8 1 3 4 4 1];
sort(ar)
```
```:結果
     1     1     3     3     4     4     7     8
```

これはPythonの`sort`関数と同じです。
```python:python
ar = np.array([3,7,8,1,3,4,4,1])
np.sort(ar)
```
```:結果
array([1, 1, 3, 3, 4, 4, 7, 8])
```

普段は小さいから大きいですが、その逆の場合は`"descend"`を書きます。
```matlab:matlab
sort(ar,"descend")
```
```:結果
     8     7     4     4     3     3     1     1
```

Pythonの`sort`はそんなことができませんが、`[::-1]`を付ければ簡単に逆にできますね。
```python:python
np.sort(ar)[::-1]
```
```:結果
array([8, 7, 4, 4, 3, 3, 1, 1])
```

受け取る変数が2つあれば、元の配列におけるその要素の位置は2つ目の変数に入ります。
```matlab:matlab
ar = [9 4 3 1 2 9 1 2];
[ar_sort,ar_argsort] = sort(ar)
```
```:結果
ar_sort =

     1     1     2     2     3     4     9     9


ar_argsort =

     4     7     5     8     3     2     1     6
```

Pythonでは`argsort`という関数で同じようなことができます。
```python:python
ar = np.array([9,4,3,1,2,9,1,2])
np.argsort(ar)
```
```:結果
array([3, 6, 4, 7, 2, 1, 0, 5])
```

### 2次元配列の並べ替え

2次元の配列に使う場合、各列の縦方向の並び替えになります。
```matlab:matlab
sort(rand(5,4))
```
```:結果
    0.1111    0.2581    0.1174    0.0855
    0.1848    0.2622    0.2217    0.2625
    0.4389    0.4087    0.2967    0.4242
    0.9049    0.5949    0.3188    0.5079
    0.9797    0.6028    0.7112    0.8010
```

Pythonの`sort`ならデフォルトでは各行の横方向の並び替えになりますが、各列の縦方向に並び替えたい場合は`0`を書いて軸を指定します。
```python:python
np.sort(np.random.random([5,4]),0)
```
```:結果
array([[0.07246839, 0.12292841, 0.01737945, 0.07570672],
       [0.21563644, 0.22558492, 0.05396218, 0.57438107],
       [0.51257565, 0.32309553, 0.05432823, 0.74583307],
       [0.79599123, 0.50041688, 0.09723998, 0.92513542],
       [0.9333539 , 0.84303799, 0.4322749 , 0.93461428]])
```

MATLABで各行の横方向の並び替えにしたい場合は`2`を書いて並ぶ軸を指定します。
```matlab:matlab
sort(rand(3,5),2)
```
```:結果
    0.2785    0.8147    0.9134    0.9572    0.9649
    0.1576    0.4854    0.5469    0.6324    0.9058
    0.0975    0.1270    0.8003    0.9575    0.9706
```

逆にPythonではデフォルトなので特に軸の指定は必要ないです。
```python:python
np.sort(np.random.random([3,5]))
```
```:結果
array([[0.29972417, 0.42224089, 0.58319216, 0.67747214, 0.73102413],
       [0.06321068, 0.20421848, 0.38762647, 0.47854416, 0.58272604],
       [0.04423574, 0.22271907, 0.60158118, 0.68406467, 0.78256067]])
```

## NaNの扱い

NaNという値は特別な存在で、`NaN==NaN`はfalseとなります。だからNaNを持つ配列を条件で要素を抽出する時に注意する必要があります。

NaNかどうかを調べるためには`isnan`という関数を使います。
```matlab:matlab
ar = [NaN 1 NaN 2 NaN 4];
ar(isnan(ar)) = 0
```
```:結果
ar =

     0     1     0     2     0     4
```

これはPythonも同じです。
```python:python
ar = np.array([np.NaN,1,np.NaN,2,np.NaN,4])
ar[np.isnan(ar)] = 0
ar
```
```:結果
array([0., 1., 0., 2., 0., 4.])
```

MATLABでは配列の中にNaNがあっても`min`や`max`などの関数は普通に動きます。
```matlab:matlab
ar = [1 NaN 2 3];
min(ar)
```
```:結果
     1
```

Pythonならこういう時は`nanmin`
難民!?
や`nanmax`などの別の関数を使う必要があるから面倒になりますね。
```python:python
ar = np.array([1,np.NaN,2,3])
np.nanmin(ar)
```
```:結果
1.0
```

ただし`sum`などの関数はMATLABでも普段はNaNが無視されません。NaNを無視するには`"omitnan"`を書く必要があります。
```matlab:matlab
ar = [2 NaN 1 1 NaN 2];
sum(ar,"omitnan")
```
```:結果
     6
```
Pythonでは`nansum`を使います。
```python:python
ar = np.array([2,np.NaN,1,1,np.NaN,2])
np.nansum(ar)
```
```:結果
6.0
```


## forループで使う時

MATLABの`for`ループはPythonと同じように、配列の要素を取って繰り返します。

1次元の配列に使う場合はPythonとほぼ同じです。
```matlab:matlab
for i = [7 5 3]
    i
end
```
```:結果
i =

     7


i =

     5


i =

     3
```
```python:python
for i in np.array([7,5,3]):
    print(i)
```
```:結果
7
5
3
```

しかし2次元以上の配列の場合はMATLABでは最後の軸で繰り返しを行います。
```matlab:matlab
for ari = [1 2;3 4;5 6]
    ari
end
```
```:結果
ari =

     1
     3
     5


ari =

     2
     4
     6
```

Pythonでは最初の軸で繰り返しを行うので違います。
```python:python
for ari in np.array([[1,2],[3,4],[5,6]]):
    print(ari)
```
```:結果
[1 2]
[3 4]
[5 6]
```

要するにPythonでは前の軸（各**行**）から分解するが、MATLABでは後ろの軸（各**列**）から分解する……。この根本的な違いは色んな動作に影響を与えるのでしっかり意識するのも大事です。

## cell配列

MATLABでは以上説明した普通の配列の他に「cell配列」という特別な配列があります。

これについて詳しくは次の記事に纏めてあります。

https://qiita.com/phyblas/items/83e10ee040981d08e3aa


# 重要なポイント纏め
最後にPython経験者がMATLABで間違えやすそうなことを纏めておきたいです。
- 配列は0ではなく、1から始まる
- 配列全体で数える時は横（各行）ではなく、縦（各列）は先
- 配列の掛け算、割り算、冪乗は`*`,`/`,`**`ではなく、`.*`,`./`,`.^`
- 範囲を指定して参照する時に最後の値は常に含まれる
- `min`や`max`などの関数はデフォルトでは全体ではなく、各列での最小値を最大値を取る


# もっと読む

qiitaで他にも沢山MATLABの基本や役に立つ記事があるので一部のおすすめのリンクをここに載せておきます。
- [[#matlab] Matlabのベスト・プラクティス](https://qiita.com/sshojiro/items/bd2ce703e605ffc9451e)
- [【初心者向け】一部自己流なMATLABノウハウ](https://qiita.com/ushibuta/items/1dc32b178c7c1aad8e44)
- [大学の卒業研究で使っているMATLABの基礎知識](https://qiita.com/yuya_yuzen/items/e9bffd47872a64f5568b)
- [MATLABで使いそうな機能まとめ 【MATLAB入門】](https://qiita.com/hamukun8686/items/70c6cafa63a347fc5448)
- [matlab ベクトル化入門](https://qiita.com/atorii/items/85a5510f2abaf8e7437f)
- [MATLABとPythonのコード対応（行列編）](https://qiita.com/kaeruair/items/44838b90d8f5160f1b85)
- [言語処理100本ノックで MATLAB 入門！第1章: 準備運動 00-09](https://qiita.com/eigs/items/5d96212d265bf1437254)
- [[MATLAB]初心者が初見で必ずthinking顔になるもの特集](https://qiita.com/motorcontrolman/items/b8d89a0cc09c73e058cb)
- [【MATLAB】N-D array（N次元配列）の計算速度比較](https://qiita.com/eigs/items/298398ca2c750beb392c)
- [MATLABの行列演算を使いこなそう。](https://qiita.com/arcadia13/items/94d3538156ff6dd8207b)
- [MATLABの隠れたデータ型？　コンマ区切りリスト](https://qiita.com/h583/items/95a1a7e91212b190e49e)
- [MATLAB入門コースの楽しみ方 (我流)](https://qiita.com/hibs_MATLAB_Amb/items/bb5d33284bd1df01a3a7)
- [MATLABによる画像処理・コンピュータービジョン入門](https://qiita.com/tohruk/items/e5f7939b622bcf2e3c4c)
- [MATLABの小ネタ：行列に対する"all"とインデックスの指定方法について](https://qiita.com/Lgarwn/items/ccd80a055b452db5b53d)
- [MATLAB 無償利用できる機能のまとめ](https://qiita.com/MatrixVectorScalar/items/718cd7e7c0764088917b)
- [MATLABからPythonライブラリを利用できた話](https://qiita.com/larking95/items/405316460dc51cbd7071)


# 終わりに
以上、MATLABの配列の基本的な扱い方及びPython（numpy）との比較を纏めました。

MATLABとPythonはそれぞれ書きやすい所と面倒な所が違って、どれがいいかなかなか言えないですね。

機能は大分重なっているし、書き方の違いはそれほど大きくないから乗り換えたいと思ったらすぐできると思います。

人気度で言うとPythonの方は圧倒的に上ですが、それはMATLABが有料であることが大きな原因でしょう。
（ちなみに人気度については[この前の記事](https://qiita.com/phyblas/items/356f12004674620587fe)で纏めています）

それでも仕事によってはMATLABを使うことになる可能性もあるので、そんな状況になった人のためにこの記事が役に立てば嬉しいです。

また、画像処理に関してはこの記事、

https://qiita.com/phyblas/items/74f3788dd69c75c68e0b

機械学習の実装はこの記事を書いてあります。

https://qiita.com/phyblas/items/4fa8fc71b83eb348fd71