はじめに
私は今まで科学計算や機械学習などはPythonを使ってきましたが、今仕事の関係でMATLABを使う必要になったのです。
私がPythonを使い始める前からMATLABのことは知っていたが、実際に使ったことないのでほとんどゼロから勉強です。
汎用性が高いPythonと違ってMATLABは数値解析に特化する言語なので、配列操作はほとんど全てで、どんな場面でも使うので配列の動作を理解することはとても重要です。
配列の扱いに関しては意外と色々Pythonのnumpyと似ていてPythonに慣れている人にとって勉強しやすくてすぐ飲み込みできますが、それでもある程度の違いや注意点も多くて、それを意識しながら使うのも重要です。
この記事は主にPythonを使っていた人に向いているMATLABの入門となります。
Pythonを使ったことない人でも読めると思いますが、ここでは主に「Pythonで普通にやっていることはMATLABならどうやる?」という見方で、基本などは省くので、Python経験を持ったらわかりやすいつもりです。
また、MATLABコードを載せるのと同時に、相当するPythonコードも一緒に載せるので、比較しながら理解していけます。
配列の他にMATLABはまだ色々面白いところがありますが、これを書いたら長くなるのでね今回は配列に関することだけ書きます。
本題 〜配列操作〜
配列の作成
1次元の配列の作成
MATLABの1次元の配列は[ ]
で囲んだだけで簡単に作れます。各要素の間に空白
かコンマ,
どちら使っても同じです。
ar = [7 6 5];
又は
ar = [7,6,5];
空白
で書いてもコンマ,
で書いてもほとんど同じように使えますが、これからの例では全部空白
で統一します。
MATLABでは後ろのセミコロン;
は「表示しないで動かす」ようにするための役割です。
;
がなくてもコードの動きは変わりませんが、;
がないと関数や代入の返り値が表示されます。それはPythonなどでprint
を使うのと似ています。
表示したいかどうかで使い分けしましょう。
Pythonで配列を作る時にまずnumpyをimport
しておかないと使えない上に、配列を作る時も冗長です。
import numpy as np
ar = np.array([7,6,5])
MATLABでは配列は基本的な機能なのですぐ使えるし、書き方も簡潔です。これを見るとMATLABの方が楽ですね。
2次元の配列の作成
MATLABでは;
で挟むことで行を区分することになります。こうやって簡単に数行を持つ2次元の配列が作れます。
[8 7 6 5; 3 4 5 6]
8 7 6 5
3 4 5 6
または改行して書くことも同じような2次元配列ができます。こう書いた方がわかりやすいですね。
[8 7 6 5
3 4 5 6]
Pythonでは2重の[ ]
で囲むことでできます。
np.array([[8,7,6,5],[3,4,5,6]])
array([[8, 7, 6, 5],
[3, 4, 5, 6]])
ちなみにMATLABでは1次元の配列を特に「ベクトル」と呼び、2次元の配列を「行列」と呼びます。
更に横に並ぶベクトルは「行ベクトル」と呼び、縦に並ぶベクトルは「列ベクトル」と呼びます。
公式サイトでもこの呼び方がよく使われているから資料を読むには覚えておく必要がありますね。
3次元以上の配列の作成
1、2次元配列なら簡単に作れるMATLABですが、3次元以上は直接作る方法がないので、意外と面倒な気もします。
一行のコードで書きたい場合cat
関数によって作るという方法があります。
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
は配列の連結に使う関数です。3
の指定は3つ目の次元で結合するという意味です。
Pythonでは3重の[ ]
で作れます。これの方が直感的かもしれません。
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
を使います。
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次元での連結の場合は関数を使わなくても連結できます。
配列を[]
で囲んだら横方向に並んで連結することになります。
ar1 = [1 1;3 3];
ar2 = [2 2;4 4];
[ar1 ar2]
1 1 2 2
3 3 4 4
cat
関数ではこう書きます。
cat(2,ar1,ar2)
その他にもhorzcat
という関数が使えます。
horzcat(ar1,ar2)
これはPythonのhstack
と同じです。
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]])
もし;
で挟んだら縦方向での連結となります。
[ar1;ar2]
1 1
3 3
2 2
4 4
cat
関数ではこう書きます。
cat(1,ar1,ar2)
又はvertcat
という関数も使えます。
vertcat(ar1,ar2)
Pythonではvstack
。
np.vstack([ar1,ar2])
array([[1, 1],
[3, 3],
[2, 2],
[4, 4]])
同じ値が並ぶ配列を作る
「0」しかない指定サイズの配列を作りたければzeros
という関数が使えます。
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
又は各次元のサイズを収める配列を入力として使うこともできます。こう書いても上記と同じ結果
zeros([3 4 2])
ただし、数字n一つしか入れない場合は勝手にn×nの行列になってしまいます。
zeros(3)
0 0 0
0 0 0
0 0 0
1次元の配列が欲しい場合(1,n)
と書きます。
zeros(1,3)
0 0 0
同じように、「1」いっぱいの配列の場合はones
ones(4,3)
1 1 1
1 1 1
1 1 1
1 1 1
Pythonでも同じような関数の名前なので覚えやすい。
np.zeros([3,4,2])
np.ones([4,3,2])
0と1以外の値の場合はrepmat関数を使います。
repmat(3,2,4)
3 3 3 3
3 3 3 3
Pythonのfull
という関数と似ています。
np.full([2,4],3)
array([[3, 3, 3, 3],
[3, 3, 3, 3]])
同じ配列の値を繰り返して並ぶ
repmat
関数は同じよう配列をコピーして連結するのにも使えます。
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
関数と似ています。
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
がありますが、繰り返し方は違います。
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
と同じ
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
関数と同じですね。
np.random.random([3,4])
randn
は正規分布でランダムする乱数を作ります。
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
関数と同じです。
np.random.randn(3,4)
randi
は指定した範囲の整数でランダムする乱数の配列を作成します。
randi([7 9],3,4)
7 8 9 8
9 8 7 8
7 9 8 9
Pythonでは同じようなことをこう書きます。
np.random.randint(7,9+1,[3,4])
Pythonのnp.random.randint
と違ってMATLABのrandi
は上限の値を含むので+1
が必要ないというところは注意です。
上限だけ指定することもできます(その場合[ ]
は要らない)。その場合は1からその上限の値までとなります。
randi(3,2,5)
3 3 1 2 2
1 2 1 3 2
Pythonのnp.random.randint
ではこういう省略はないので普通の1を入れます。
np.random.randint(1,3+1,[2,5])
等間隔の連続値を持つ配列を作成する
範囲と間隔を指定する
MATLABで連続の数字の配列が欲しいならこのように:
で簡単に作れます。
5:9
5 6 7 8 9
これはPythonのnp.arange
関数と同じですが、Pythonでは最後が含まれないので+1
が必要です。
np.arange(5,9+1)
array([5, 6, 7, 8, 9])
書き方がシンプルで、しかも関数を使わなくても文法で簡単に作れるMATLABは楽ですね。
間隔が1ではない場合は間隔を中間に入れます。
4:3:13
4 7 10 13
Pythonのarange
では間隔の値を最後に置くので、書く場所が逆なのは注意です。
np.arange(4,13+1,3)
array([ 4, 7, 10, 13])
範囲と数を指定する(linspace)
下限と上限を指定して作りたい場合はlinspace
を使うことができます。書き方はlinspace(下限,上限,数)
です。
linspace(4,6,5)
4.0000 4.5000 5.0000 5.5000 6.0000
Pythonでも同じ関数の名前で同じような書き方です。
np.linspace(4,6,5)
array([4. , 4.5, 5. , 5.5, 6. ])
ただしPythonでは上限が要らないという場合は最後にFalse
を入れてることでできます。
np.linspace(4,6,5,False)
array([4. , 4.4, 4.8, 5.2, 5.6])
MATLABではこんなことができないので残念です。
要素の参照
1次元配列の要素
1次元の配列の中の値を取るには( )
で囲んで取りたい順番を入れるのです。
ar = [7 8 9];
ar(2)
8
MATLABではFortranと同じように配列のインデックスは「1」から始めます。これは「0」から数えるC、Python、Ruby、JavaScript、PHP、IDLなど大半の言語と違います。
CやPythonみたいに[ ]
ではなく、( )
で囲むというところもFortranと同じです。
Pythonの場合。
ar = np.array([7,8,9])
ar[1]
8
また、( )
は直接配列の変数の後ろに置かなければならない。例えばPythonではこう書けます。
np.linspace(1,3,5)[3]
2.5
しかしMATLABこれはエラーとなります。
linspace(1,3,5)(4)
エラー: 配列のインデックス付けが無効です。
だから一旦変数に収める必要なので、ちょっと面倒かもしれません。
ar = linspace(1,3,5);
ar(4)
2.5000
2次元配列の要素
2次元配列へのアクセスは,
で挟んで各軸での順番を指定するのです。
ar = [9 8;7 5;4 3];
ar(3,1)
4
Pythonでも似ています。
ar = np.array([[9,8],[7,5],[4,3]])
ar[2,0]
4
ただし、一つしか数字を入れない場合、それは全体から見る順番で入ることになります。
ar = [9 8 7; 5 4 3];
ar(3)
8
順番は各列の全部の要素から数えるので、ここでは9, 5, 8, ...ということで3番目は8となります。
Pythonで同じような書き方したら、「i-1行目を取る」ということになりますね。
その場合MATLABでは,:
を書く必要があります。
ar = [1 2 3; 4 5 6; 7 8 9]
ar(2,:)
4 5 6
これはPythonでこう書くのと同じ。
ar = np.array([[1,2,3],[4,5,6],[7,8,9]])
ar[1]
array([4, 5, 6])
逆に「i列の全ての行を取る」場合はこのように書きます。
ar = [1 2 3; 4 5 6; 7 8 9]
ar(:,2)
2
5
8
これは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
を使います
ar = [1 2 3 4];
ar(end)
4
ar(end-1)
3
Pythonでは負の数字を使うのでその方が書きやすいです。
ar = np.array([1,2,3,4])
ar[-1]
4
ar[-2]
3
範囲を指定して取る
a:b
と書くと配列の指定したaからbの範囲内の要素を全部取ることになります。
ar = [7 3 5 8 6 2]
ar(2:4)
3 5 8
これはPythonと同じです。
ar = np.array([7,3,5,8,6,2])
ar[1:4]
array([3, 5, 8])
最後まで取りたい場合Pythonでは:
の後の数字を省略できますが、MATLABではそんな省略はできず、end
を書く必要があります。
ar(2:end)
3 5 8 6 2
ar[1:]
array([3, 5, 8, 6, 2])
配列のサイズを調べる
size
関数を使えば配列の各軸のサイズがわかります。
ar = rand(5,6,7,9);
size(ar)
5 6 7 9
Pythonの.shape
と同じです。
ar = np.random.random([5,6,7,9])
ar.shape
(5, 6, 7, 9)
ただしこれは1次元の配列に使っても最低限2の数字ができます。
size([9 9 9])
1 3
ある軸だけのサイズを取る場合はその軸の番号を指定します。
ar = zeros(5,4,3,2)
size(ar,2)
4
一次元配列のサイズは普段length
関数を使います。ただしlength
関数は最後の軸でのサイズを返します。
ar = randn(3,6,2,11)
length(ar)
11
Pythonのリストなどの長さを図るlen
関数と似ていますが、配列に使う場合は最初の軸のサイズを返します。この動作の違いも注意です。
ar = np.random.randn(3,6,2,11)
len(ar)
3
またPythonではsize
が配列全体の要素数を返します。MATLABではnumel
という関数を使います。
ar = randn(3,3,3);
numel(ar)
27
ar = np.random.randn(3,3,3)
ar.size
27
配列を逆に並べ替える
最初と最後を逆転させる
配列を逆にさせるためにflip
という関数があります。
ar = [2 3 4];
flip(ar)
4 3 2
実は関数を使わなくてもend:-1:1
と書けばいいが、関数を使う方が書きやすいかも。
ar(end:-1:1)
同じようなことはPythonなら簡単な方法があって書きやすいです。
ar = np.array([2,3,4])
ar[::-1]
array([4, 3, 2])
2次元の配列の場合flip
は上と下を逆にさせますが、横の方向にしたいなら軸の番号を指定します。
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
関数でできます。
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
ただし実はもっと簡単な方法があります。それはただ'
をつけるということです。
[1 1 1;6 6 6]'
1 6
1 6
1 6
Pythonで.T
を付けるのと同じです。
np.array([[1,1,1],[6,6,6]]).T
array([[1, 6],
[1, 6],
[1, 6]])
3次元配列における軸の入れ替え
transpose
関数も'
も2次元の配列にしか使えないのです。3次元以上の場合はpermute
という関数を使います。
ar = ones(2,3,4);
ar = permute(ar,[3 1 2]);
size(ar)
4 2 3
Pythonでは同じようなことをtranspose
関数でできます。2次元専用のMATLABのtranspose
と違って、Pythonのtranspose
何次元にでも使えます。
ar = np.ones([2,3,4])
ar = np.transpose(ar,[2,0,1])
ar.shape
(4, 2, 3)
データ型
MATLABの数字のデータ型が色々ありますが、指定しない限り基本的に全てはdouble(倍精度配列)となります。
class
関数でデータ型を調べることができます。
ar = [1 3 5];
class(ar)
'double'
データ型を変更するにはそのデータ型の名前と同じ関数を使えばいい。
ar = uint8([7 6 3]);
class(ar)
'uint8'
画像処理ではuint8がよく使われています。
MATLABで真偽を示す値はlogicalというデータ型です。普段はtrueとfalseではなく0と1と表示します。数字から変換する場合は0がfalseで、それ以外の数字はtrueとなります。
class(5>3)
'logical'
演算子による配列の計算
足し算と引き算
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
配列と一つの数字の計算もできます。
[4 4 5 5]+10
14 14 15 15
これはPythonと同じです。
np.array([4,4,5,5])+10
array([14, 14, 15, 15])
掛け算と割り算と冪乗
掛け算の場合は足し算と割り算のように簡単ではなく、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
関数を使うのです。
ar1 = np.array([[1,1],[2,2]])
ar2 = np.array([[3,3],[4,4]])
np.dot(ar1,ar2)
array([[ 7, 7],
[14, 14]])
ar1*ar2
array([[3, 3],
[8, 8]])
同じく、割り算と冪乗も.
を付ける必要があります。
割り算は./
。
[3 3 6]./[1.5 3 1.5]
2 1 4
冪乗は.^
。
[2 3 5].^2
4 9 25
間違って.
を忘れたらたとえエラー゛が出なくても望むのと違う結果になるので特に要注意です。
論理演算子
論理演算子は単体の数字でも配列でも同じように使えます。
- andは
&
- orは
|
- notは
~
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の配列が複素数になってしまう場合はそのまま複素数の配列になります。
[-1 0 1].^0.5
0.0000 + 1.0000i 0.0000 + 0.0000i 1.0000 + 0.0000i
ただし複素数になってもデータ型としてはdoubleのままで、別のデータ型となるわけではないです。
それはPythonだったら普通のfloat配列は複素数にはならず、nanになってしまいます。
np.array([-1,0,1])**0.5
array([nan, 0., 1.])
こうやって自動的に複素数になるMATLABは便利ですね。
ただしデータ型が整数タイプにされていたら駄目です。
int8([-1 0 1]).^0.5
次を使用中のエラー: .^
整数は、正の整数乗のみが許容されます。
条件を満たす要素だけ抽出する方法
配列の中で条件を指定してある要素だけ取得することができます。
ar = [9 5 8 7 4 6];
ar(ar<6)
5 4
それはPythonと同じです。
ar = np.array([9,5,8,7,4,6])
ar[ar<6]
array([5, 4])
その一部の値にアクセスして値を変更することもできます。
ar = [8 7 6 5 4];
ar(ar>5) = 9
9 9 9 5 4
ar = np.array([8,7,6,5,4])
ar[ar>5] = 9
ar
array([9, 9, 9, 5, 4])
配列を変形する
各軸のサイズを指定して変形
reshape
関数で配列を好きな形に再編成することができます。
ar = 1:12;
reshape(ar,4,3)
1 5 9
2 6 10
3 7 11
4 8 12
ただしMATLABでは縦から数えるから、同じようなことをPythonでやったら違う結果になります。
ar = np.arange(1,13)
ar.reshape(4,3)
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
横から並べたい場合は後で'
などで転置するのです。
ar = 1:12;
reshape(ar,3,4)'
1 2 3
4 5 6
7 8 9
10 11 12
一つの軸のサイズを省いて変形する
もし沢山軸があって、例えばn軸がある場合n-1軸だけサイズを指定したら残りの一つは書かなくてもわかるので、省略できます。その場合はその軸の位置に[]
で入れ替えます。
ar = 1:36;
ar = reshape(ar,3,[],2);
size(ar)
3 6 2
Pythonで-1
を使うのと同じです。
ar = np.arange(1,37)
ar = ar.reshape(3,-1,2)
ar.shape
(3, 6, 2)
1次元の配列にする
一次元にしたい時(:)
を付けます。
ar = rand(2,4);
ar(:)
0.1496
0.3508
0.3360
0.7840
0.4867
0.4648
0.1313
0.8864
ただしこの方法では縦で並ぶ配列になるので、横に並べたい場合'
を付けます。
ar = ones(2,4);
ar(:)'
1 1 1 1 1 1 1 1
又はreshape
関数を使います。
reshape(ar,1,[])
Pythonではravel
メソッドを使います。
ar = np.ones([2,4])
ar.ravel()
array([1., 1., 1., 1., 1., 1., 1., 1.])
配列内の最小値と最大値を求める
1次元の配列の最小値と最大値
配列の中の最小値と最大値を求めるためにmin
とmax
という関数があります。
1次元の配列の場合は全ての要素の最小値と最大値となります。
ar = [7 5 3 6];
min(ar)
3
2次元の配列の最小値と最大値
2次元の配列に使う場合は各列の最小値と最大値を取った1次元の配列にします。
ar = [3 1 2;1 4 3];
max(ar)
3 4 3
Pythonでこう書くのと同じ。
ar = np.array([[3,1,2],[1,4,3]])
ar.max(0)
array([3, 4, 3])
逆に各行の最小値と最大値を取りたい場合はこう書きます。
ar = [3 4;4 2;5 3];
max(ar,[],2)
4
4
5
Pythonでこう書くのと似ていますが、MATLABの方は縦のままで、Pythonは横に並ぶことになるのでわかりにくいかもしれません。
ar = np.array([[3,4],[4,2],[5,3]])
ar.max(1)
array([4, 4, 5])
もし全体の最小値と最大値である一つだけ取りたい場合は(:)
を付けます
ar = [1 9 7;0 2 2; 5 5 5];
max(ar(:))
9
Pythonでこれがデフォルトのmin
とmax
の動作ですね。
ar = np.array([[1,9,7],[0,2,2],[5,5,5]])
ar.max()
9
その他にsum
、mean
、std
、var
、median
という、総和、平均値、標準偏差、分散、中央値を求める関数があります。使い方はmin
とmax
と大体似ています。
最小値と最大値の要素の位置を取る
実はmin
とmax
は最小値と最大値を返すだけでなく、同時に最小値と最大値の要素が置かれている位置を返すこともできます。
返り血を受ける変数を2つにすることで2つ目の変数に最小値と最大値の位置が入ります。
ar = [1 9 2 8 3 7 4];
[ar_max,ar_argmax] = max(ar)
ar_max =
9
ar_argmax =
2
Pythonではargmin
とargmax
という別のメソッドがあるからそれを使っていいです。
ar = np.array([1,9,2,8,3,7,4])
ar.argmax()
1
MATLABでは2つ以上の返り値を返す関数がありますが、もし返り値受ける変数が一つしかない場合2つ目の返り値が無視されます。
それを受けるために[ ]
で囲んで受ける変数を並べます。
ただし1つ目の関数が要らない場合は~
を書きます。
最小値か最大値の位置だけ欲しい場合はこう書いたらいいです。
ar = [5 5 1 5 5];
[~,a] = min(ar)
a =
3
要素の値のよって配列を並べ替える
1次元配列の並べ替え
sort
関数は並べ替えた配列を返します。
ar = [3 7 8 1 3 4 4 1];
sort(ar)
1 1 3 3 4 4 7 8
これはPythonのsort
関数と同じです。
ar = np.array([3,7,8,1,3,4,4,1])
np.sort(ar)
array([1, 1, 3, 3, 4, 4, 7, 8])
普段は小さいから大きいですが、その逆の場合は"descend"
を書きます。
sort(ar,"descend")
8 7 4 4 3 3 1 1
Pythonのsort
はそんなことができませんが、[::-1]
を付ければ簡単に逆にできますね。
np.sort(ar)[::-1]
array([8, 7, 4, 4, 3, 3, 1, 1])
受け取る変数が2つあれば、元の配列におけるその要素の位置は2つ目の変数に入ります。
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
という関数で同じようなことができます。
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次元の配列に使う場合、各列の縦方向の並び替えになります。
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
を書いて軸を指定します。
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
を書いて並ぶ軸を指定します。
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ではデフォルトなので特に軸の指定は必要ないです。
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
という関数を使います。
ar = [NaN 1 NaN 2 NaN 4];
ar(isnan(ar)) = 0
ar =
0 1 0 2 0 4
これは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
などの関数は普通に動きます。
ar = [1 NaN 2 3];
min(ar)
1
Pythonならこういう時はnanmin
難民!?やnanmax
などの別の関数を使う必要があるから面倒になりますね。
ar = np.array([1,np.NaN,2,3])
np.nanmin(ar)
1.0
ただしsum
などの関数はMATLABでも普段はNaNが無視されません。NaNを無視するには"omitnan"
を書く必要があります。
ar = [2 NaN 1 1 NaN 2];
sum(ar,"omitnan")
6
Pythonではnansum
を使います。
ar = np.array([2,np.NaN,1,1,np.NaN,2])
np.nansum(ar)
6.0
forループで使う時
MATLABのfor
ループはPythonと同じように、配列の要素を取って繰り返します。
1次元の配列に使う場合はPythonとほぼ同じです。
for i = [7 5 3]
i
end
i =
7
i =
5
i =
3
for i in np.array([7,5,3]):
print(i)
7
5
3
しかし2次元以上の配列の場合はMATLABでは最後の軸で繰り返しを行います。
for ari = [1 2;3 4;5 6]
ari
end
ari =
1
3
5
ari =
2
4
6
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配列」という特別な配列があります。
これについて詳しくは次の記事に纏めてあります。
重要なポイント纏め
最後にPython経験者がMATLABで間違えやすそうなことを纏めておきたいです。
- 配列は0ではなく、1から始まる
- 配列全体で数える時は横(各行)ではなく、縦(各列)は先
- 配列の掛け算、割り算、冪乗は
*
,/
,**
ではなく、.*
,./
,.^
- 範囲を指定して参照する時に最後の値は常に含まれる
-
min
やmax
などの関数はデフォルトでは全体ではなく、各列での最小値を最大値を取る
もっと読む
qiitaで他にも沢山MATLABの基本や役に立つ記事があるので一部のおすすめのリンクをここに載せておきます。
- [#matlab] Matlabのベスト・プラクティス
- 【初心者向け】一部自己流なMATLABノウハウ
- 大学の卒業研究で使っているMATLABの基礎知識
- MATLABで使いそうな機能まとめ 【MATLAB入門】
- matlab ベクトル化入門
- MATLABとPythonのコード対応(行列編)
- 言語処理100本ノックで MATLAB 入門!第1章: 準備運動 00-09
- [MATLAB]初心者が初見で必ずthinking顔になるもの特集
- 【MATLAB】N-D array(N次元配列)の計算速度比較
- MATLABの行列演算を使いこなそう。
- MATLABの隠れたデータ型? コンマ区切りリスト
- MATLAB入門コースの楽しみ方 (我流)
- MATLABによる画像処理・コンピュータービジョン入門
- MATLABの小ネタ:行列に対する"all"とインデックスの指定方法について
- MATLAB 無償利用できる機能のまとめ
- MATLABからPythonライブラリを利用できた話
終わりに
以上、MATLABの配列の基本的な扱い方及びPython(numpy)との比較を纏めました。
MATLABとPythonはそれぞれ書きやすい所と面倒な所が違って、どれがいいかなかなか言えないですね。
機能は大分重なっているし、書き方の違いはそれほど大きくないから乗り換えたいと思ったらすぐできると思います。
人気度で言うとPythonの方は圧倒的に上ですが、それはMATLABが有料であることが大きな原因でしょう。
(ちなみに人気度についてはこの前の記事で纏めています)
それでも仕事によってはMATLABを使うことになる可能性もあるので、そんな状況になった人のためにこの記事が役に立てば嬉しいです。
また、画像処理に関してはこの記事、
機械学習の実装はこの記事を書いてあります。