Python に標準で備わっている仕組みの中で、他の言語でいう「配列」に一番近いものは、「リスト」(list)です。数値計算によく使う NumPy というライブラリには array(配列)が定義されています。いずれも添字(インデックス)は 0 から始まります。
3個の要素からなるリストを作ってみましょう:
a = [3, 5, 7] a[0]
3
a[1]
5
a[2]
7
範囲外の要素、例えば a[3]
にアクセスすると、エラーになります:
a[3]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Input In [ ], in <cell line: 1>() ----> 1 a[3] IndexError: list index out of range
インデックスのループで各要素にアクセスする方法:
for i in range(3): print(a[i])
3 5 7
ただし、Python では次のようにするのが一般的です:
for x in a: print(x)
3 5 7
同じ要素のリストなら次のようにして作るのが簡単です:
a = [5] * 10 # 5が10個 a
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
アペンドを繰り返して作ることもできます:
a = [] for i in range(3, 8, 2): # 3から始まり8未満2ずつ増やす a.append(i) a
[3, 5, 7]
上と同じことは次のようにも書けます(リスト内包表記、list comprehension):
a = [i for i in range(3, 8, 2)] a
[3, 5, 7]
リストの要素は同じ型でなくてもかまいません。数値や文字列が混じったリストも可能です。
a = [3, 5.0, "seven"] for x in a: print(x, type(x))
3 <class 'int'> 5.0 <class 'float'> seven <class 'str'>
行列はリストのリストとして作れます:
a = [[2, 9, 4], [7, 5, 3], [6, 1, 8]] a[1][2]
3
リスト以外に、Python には tuple(タプルまたはテュープルと読む)という1次元の配列のようなものがあります。[ ]
を使えばリスト、( )
を使えばタプルです:
t = (2, 3, 4, 5)
要素1つのリストは [2]
のように書きますが、タプルの場合は (2)
ではなく特例として (2,)
のように書きます。
リストは要素を変えられますが、タプルは変えられません:
x = [2, 3, 4, 5] t = (2, 3, 4, 5) x[2] = 30 t[2] = 30 # TypeError: 'tuple' object does not support item assignment x.append(6) # 末尾に 6 を追加 t.append(6) # AttributeError: 'tuple' object has no attribute 'append'
ベクトル・行列などの数値計算をより高速に行うには NumPy の array を使います。
import numpy as np a = np.array([3, 5, 7]) a
array([3, 5, 7])
type(a)
numpy.ndarray
a.dtype
dtype('int64')
一つでも浮動小数点数にすると、全部が浮動小数点数になります。
a = np.array([3, 5, 7.]) a
array([3., 5., 7.])
a.dtype
dtype('float64')
データ型を指定することもできます:
a = np.array([3, 5, 7], dtype="int8") # 8ビット整数型 a
array([3, 5, 7], dtype=int8)
0 に初期化された長さ n
の配列を作るには np.zeros(n)
とします。同様に、1 に初期化された長さ n
の配列は np.ones(n)
です。初期化の必要がなければ np.empty(n)
とします。行列は、n
のところを例えば (m, n)
のように (行数, 列数)
とします。同様に任意次元の配列が作れます。
a = np.ones((2, 3)) a
array([[1., 1., 1.], [1., 1., 1.]])
a = np.ones((2, 3, 4)) a
array([[[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]], [[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]]])
各要素にアクセスするには a[i, j]
でも a[i][j]
でも(通常は)同じ意味ですが、a[i, j]
のほうが倍ほど速いようです:
a = np.empty((1000, 1000)) %timeit a[123][456] %timeit a[123, 456]
a
、b
が array なら、例えば a + b
は要素ごとの和になります。つまり、ベクトルや行列の要素ごとの演算はループしなくても高速にできます。
a = a + b
は a + b
を計算してそれに a
という名前を付けます(古い a
はアクセスできなくなります)。一方で、a += b
は a
に b
をその場で加えます。大きな array の計算はこの方がメモリを節約でき、速くなります:
a = np.empty((1000, 1000)) b = np.empty((1000, 1000)) %%timeit global a, b a = a + b # または a += b
ベクトル・行列の生成は他に np.arange()
(arange = array range)が便利です:
np.arange(6)
array([0, 1, 2, 3, 4, 5])
np.arange(6).reshape(2, 3) # 2行3列にする
array([[0, 1, 2], [3, 4, 5]])
np.arange(3)
は array([0, 1, 2])
ですが np.arange(3.)
は浮動小数点の array([0., 1., 2.])
になります。
np.empty(n, dtype="int8")
などのようにデータ型を指定することもできます。
乱数のベクトルの生成は乱数を参照してください。
PyTorch や Tensorflow などの機械学習ライブラリでは「テンソル」(tensor)というものをよく使いますが、これも一種の配列です。
PyTorch なら import torch
して、np.array()
の代わりに torch.tensor()
、np.ones()
の代わりに torch.ones()
とします。
Last modified: