Matlabの基礎

# はじめに
新しい会社に入ったらMatlabをやることになったので、自分用のまとめです。
行列、セル行列、containers.Map、tableなどの編集・参照方法をまとめます。
なお、現状会社で使用するのは2021年バージョンなので、それ以降の機能(dictionaryなど)は含みません。


# 行列
行列は縦と横に数や記号を並べたものです。
行列内のデータはすべて同じ型でなければなりません。

### 行ベクトル(１行n列)
```matlab
A=[1 2 0 4 5]    % 初期化
B = 1:1:5  % 初期化
A(3) = 3         %代入(編集)
C = A(2:4)       %抽出
D = A + B        %加算
E = A - B        %減算
F = A .* B       %アダマール積
G = A ./ B       %アダマール除算
H = [A B C]           %連結
I = horzcat(A, B, C)  %連結(上と同じ)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/6b89c1af-39d1-4775-adb5-ea6549c9ceeb.png)


### 列ベクトル(n行1列)
```
A=[1; 2; 0; 4; 5;]    % 初期化
B = (1:1:5)'     % 初期化(行ベクトルを転地)
A(3) = 3         %代入(編集)
C = A(2:4)       %抽出
D = A + B        %加算
E = A - B        %減算
F = A .* B       %アダマール積
G = A ./ B       %アダマール除算
H = [A; B; C]         %連結
I = vertcat(A, B, D)  %連結(上と同じ)
J = horzcat(A, B, D)  %行方向に連結

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/14c068c4-849f-4914-95b6-77354ffb7825.png)

### 行列(n行m列)
```
A = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12] % 初期化(4行3列)
B = rand(4, 3)  % ランダム初期化(4行3列)
C = rand(3, 4)  % ランダム初期化(3行4列)
D = A + B         % 加算(A+Cはエラー)
E = A - B         % 減算(A-Cはエラー)
F = A .* B        % アムダール積(A.*Cはエラー)
G = A ./ B        % アムダール除算(A./Cはエラー)
H = A / B         % 除算(A/Cはエラー)
I = H * B         % Aと一致
J = A * C         % 積(A*Bはエラー)
K = A + 3         % すべての要素に3を加算(その他四則演算も同様)

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/4cf4db72-1c46-4262-9e02-256d3078f838.png)

### 行列上での文字列
```
A=['a', 'b', 'c';'c', 'd', 'e'; 'f', 'g', 'h']
B=["a", "b", "c";"c", "d", "e"; "f", "g", "h"]
```
''だとchar配列。
""だとstring(文字列)。
行列にいれると違いが明確にわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/20191ddb-060c-4080-bfd9-b75a8caf9e8b.png)
char配列だと行ベクトルとして合算されるが、文字列だと単一の値として扱われる
```
A=['a', 'bc', 'c';'c', 'd', 'e'; 'f', 'g', 'h']   %こちらはエラー
B=["a", "bc", "c";"c", "d", "e"; "f", "g", "h"]   %こちらは問題なし
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/2c9067e4-aac8-40c3-b7e6-4085f80e123d.png)


### 行列から抽出
```
A = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12] % 初期化(4行3列)
A(2)          % ans => 4(行方向に最初に進むらしい）
A(11)         % ans => 9(行方向に最初に進むらしい）
A(3,2)        % ans => 8(3行2列目)
A(2:3, 2)     % 2行目から３行目の2列目を抽出
A(:, 2:3)     % すべての行に対して、2列目から3列目を抽出
A(1:2:4, 3)   % 1行目から４行目まで２行おきに、3列目を抽出
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/3eb45909-1b1c-445d-96c9-39abe96c3c97.png)


### 特定の数値に一致した行/列から値を抽出する
```
A = [1 2 3 ;...
     4 5 6 ;...
     7 8 9]

%『3』がある行から２列目を抽出する     
resultA = A(any(A == 3,2) , 2)
% 同じ場所に222を代入する
A(any(A == 3,2) , 2) = 222

%『3』がある列から２行目を抽出する    
resultB = A(2 , any(A == 3,1))
% 同じ場所に666を代入する
A(2 , any(A == 3,1)) = 666

%　上記の補足
% 2を指定すると行方向に探索する。つまり１行目だけが1の列ベクトルがとれる
any(A == 3,2)

% 1を指定すると列方向を探索する。つまり3列目だけが1の行ベクトルがとれる
any(A == 3,1)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/b3f55827-81c1-4231-b83f-380d526c9558.png)

# セル配列
普通の行列だと同じ型しかいれることができなかったが、セル配列を利用すると様々な型を同時に扱うことができる。印象としては、普通の行列は配列に値を直接入れたもの。セル行列は配列に、C言語でいうところのポインタを入れたもの。

```
% セル配列の定義
A = {1, 'abc', 1.234; ...
     "ABC", pi, -100;...
     0, "" , 5.1}
    
% セル配列の抽出(Bもセル配列になる)
B=A(2:3, 1:2)
% 次の方法だと先頭要素だけがCに入る(多分使わないほうがいい)
C=A{2:3, 1:2}

% 次の代入方法ではエラーになる
%A(1, 3) = '3' 
% 以下の方法なら成功する（1行3列目に代入)
A{1, 3} = 4.321
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/32aa14b7-219d-43cb-82a1-725107729d3f.png)

### セル配列内の特定の要素だけを抽出
```
A = {1, 'abc', 1.234; ...
     "ABC", pi, -999;...
     0, "" , 5.1}

% 文字列だけを取得(char配列は対象外)
idx = find(cellfun(@(x) isstring(x) , A)) 
B = A(idx)

% ABCという文字がある行の３列目を取得
idx = find(cellfun(@(x) isstring(x) && strcmpi(x, "ABC") , A)) 
C = A(idx, 3)


```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/cdd435b5-c272-4e3d-8428-7e240cee514f.png)

### セル配列の連結
行列と同じく、vertcatおよびhorzcatで問題ない
```
D = vertcat(A , {"abc", "aaa", "zzz"}) % 縦(行方向)に追加
E = horzcat(A , {"abc"; "aaa"; "zzz"}) % 横(列方向)に追加

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/33bdcadf-2094-473b-9a44-03acb66b66d1.png)


### セル配列から行列へ変換
すべてが数値やchar配列なら以下のように変換できる
```
A = {1 2 3 ;...
     4 5 6 ;...
     7 8 9};
B = cell2mat(A)

C = {'a' 'b' 'c' ;...
     'd' 'e' 'f' ;...
     'g' 'h' 'i'}
D = cell2mat(C)

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/325f3cbf-8cd4-49e5-af77-b41885b7de87.png)

stringの場合はなぜかできない
```

A = {"a" "b" "c" ;...
     "d" "e" "f" ;...
     "g" "h" "i"}
     
B= ["a" "b" "c" ;...
     "d" "e" "f" ;...
     "g" "h" "i"]
     
% AをBのように変換したいのにエラーとなる
C = cell2mat(A{:})
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/5091f276-f4ff-4923-b64e-2a57646db236.png)

string型のセル配列を行列に変換したい場合は次のようにする
```
A = {"a" "b" "c" ;...
     "d" "e" "f" ;...
     "g" "h" "i"}
     
C = string(A)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/68f15d1f-5db9-4a16-bffc-451ee2407cd3.png)

# containers.Map
C++で言うところのstd::mapと同じものだと思う。
なお、R2022年度から[dicrionary](https://jp.mathworks.com/help/matlab/dictionary.html)が使えるそうだが、違いはkeyに利用できる型がMapは**文字列かスカラー値**だけだが、dictionaryは**イミュータブルなオブジェクト**でも使えること、メソッドが増えていること、パフォーマンスもいいことが挙げられるが使ったことがないので詳細は知らない。

```
A = {'a' 'b' 'c' ;...
     'd' 'e' 'f' ;...
     'g' 'h' 'i'}
B = [1 2 3; 4 5 6; 7 8 9]
C = containers.Map(A, B)   % Mapの初期化(key:A, value:B)
D = containers.Map(B, A)   % Mapの初期化(key:B, value:A)

% 注意点として、Mapのkey, valuesはともにcell配列になっている
E = D.keys
E = D.values


% cell配列なので{}でくくらないと動かない
% F = C(E(1))　% これはエラーになる 
F = C(E{1})    %　こちらは成功する

C(E{1})  = 111 % 代入はこれでOK
C(E{1}) 

% keyがあるかどうかの確認
isKey(C, 'a')
isKey(C, 'z')

% 要素追加(型を一致させる必要あり)
C('z') = 3; % 型が一致しているので問題なし
D(10) = 3; % 型が不一致のためエラーとなる
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/ae158220-5ba0-485e-9f9f-ad8e7498c1b0.png)


# table

```
names = {'Alice'; 'Bob'; 'Charlie'};
ages = {25; 30; 28};
heights = [1.65; 1.80; 1.75];
columns = {'Name', 'Age', 'Height'}

% table初期化
T = table(names, ages, heights, 'VariableNames', columns)

% 参照はカラム名からでも列数からでも可能
A = T{1:2, 'Name'}
B = T{1:2, 1}

% 次の方法ですべてのHeight要素に1を加算
T.Height = T.Height+1

% ひとつだけ変更したい場合は以下のようにする
T.Height(2) = T.Height(2) + 1

% ただし、セル配列はエラーとなる
T.Age = T.Age + 1
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/d8757aa6-0c93-4c27-93d3-93481306b43a.png)

### talbe内のセル配列の変更
```
% セル配列なのでcellfunを適用し、それを直接代入する
% num2cell()がないとセル配列でなくなるので、セル配列を維持したいならこれをつける
T.Age = num2cell(cellfun(@(x) x+1 , T.Age ))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/25bdafda-b499-4467-bd39-93fae78c035e.png)

### Table内の特定の要素を抽出する
```
% Heightが2.7以上のNameを抽出する(行列なら以下で問題ない)
H = T(T.Height > 2.7, :).Name
% セル配列だと同じやり方でエラーとなる
A = T(T.Age > 25, :).Name
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/e39a005b-1f21-473b-9864-19539c86b592.png)

### Table内の特定の要素を抽出する(セル配列内を検索)
```
% セル配列なのでcellfunを使用する
% Ageが25以上のNameを抽出したいとき
T.Name{find(cellfun(@(x) x > 25 , T.Age ))}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/6e46ee5e-7315-48ee-afc0-3fcadc3a5253.png)

### Table内を変更したい時
```
% Heightが2.7以上の名前を変更する
% ただし、この場合は見つかった要素が2つであることが予めわかっていたからできた書き方
T(T.Height > 2.7, :).Name = {'abc';'def'}

% 見つかった最初の要素だけを変更する
T(T.Height > 2.7, :).Name{1} = 'ABC'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338221/216c67e8-4fdc-4304-beaa-9739b6e31f1b.png)

### Table内のある文字列に一致した要素の行の一部を編集したいとき
```
% Nameが"ABC"のAgeを99に変更する(抽出は=99を削除すればOK)
T.Age{find(cellfun(@(x) strcmpi(x, "ABC") , T.Name ))} =99
```

# 終わりに
Matlabの行列式やセル行列を実際に編集しようとした時、あまりにもできなかったので勉強のつもりで記事を書きました。あくまでも自身の勉強のためなので、わかりやすく書いてはいませんが、だれかの参考に少しでもなれば幸いです。