【初心者必見】機械学習のためのNumPyの基礎知識①「配列の基本」

目次

はじめに

 Pythonを用いて機械学習を行う際,NumPyというライブラリがよく使われます.このライブラリを用いるとベクトルや行列,テンソルなどの計算が効率よくできるため,機械学習との相性が良いとされています.まずはNumPyについての基礎知識を解説します.

ベクトルと行列

ベクトルをつくる

一次元配列(行ベクトルと列ベクトル)はそれぞれどのように作るの?
# ライブラリをロードします
import numpy as np

# 行ベクトル(1次元配列)
vector_row = np.array([1, 2, 3])        # shape -> (3,)

# 列ベクトル(2次元配列)
vector_column = np.array([[1],
                          [2],
                          [3]])        # shape -> (3,1)

コードの解説

import numpy as np

 NumPy を使用するには上記のコードをプログラムの最初に書く必要があります. np とはNumPyの事を表しています.NumPyに限らず,任意のライブラリを読み込む際はimport関数を用いて読み込むのが通例です.以後の配列操作は np.arrayなどで行います。

vector_row = np.array([1, 2, 3])

 角括弧が一重なので 1 次元配列を表しています。 NumPy の内部的な形状は (3,) となっていて,行ベクトルです.行列演算を行う際は「次元が足りない」という扱いになり得るので注意しましょう!

vector_column = np.array([[1],
                          [2],
                          [3]])

 内側にさらに角括弧を使って各要素を縦に並べることで、2 次元配列 (3,1) を作ります。これが「列ベクトル」として線形代数の演算で期待どおり動きます!

なぜ「行」と「列」を区別するのか

  • 多くの線形代数演算(行列積など)は「次元の形」が重要です。行列積を正しく行うには明示的に (1,n) (n,1) のような 2D 表現が必要な場面が多いです。
  • 1 次元配列 (n,) は便利ですが、転置 .T を使っても見た目が変わらず、意図した行列演算にならないことがあります。

行列を作る

 行列はベクトルの要素が増えるだけで,基本的なルールは変わりません.

行列はどのように作るの?
import numpy as np

# 3x3 の行列(matrix)
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])
print("shape:", matrix.shape)   # -> (3, 3)
print(matrix)

コードの解説

matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])


 二重の角括弧で「行ごとのリスト」を並べることで 2 次元配列(行列)を作っています。この場合は 3 行 3 列の行列で、shape(3, 3) です。各内側リストが行を表します(上から1行目が [1,2,3]、2行目が [4,5,6]、3行目が [7,8,9])。

print("shape:", matrix.shape)


 行列の形状を表示します。出力は (3, 3) で、行数・列数が確認できます。デバッグ時はまず shape を確認する習慣をつけると良いです。

print(matrix)


 print関数を用いて行列の中身を表示します。


 機械学習という観点では多次元の行列を扱うため,要素がゼロであることが多いです.このように,多くの要素がゼロであるような行列を「疎行列」といいます.

 疎行列はゼロでない要素が限られるので,非ゼロの値のみ格納したほうが効率がいいです!

疎行列の効率的な格納方法は?
import numpy as np
from scipy import sparse

# 密行列を作る
matrix = np.array([[0, 0],
                   [1, 0],
                   [0, 2]])

# CSR形式に変換する
sparse_matrix = sparse.csr_matrix(matrix)

print(sparse_matrix)

コード解説

  • np.array で作ったのは「密行列」と呼ばれます.全要素をメモリに格納する通常の配列のことです.
  • sparse.csr_matrix(matrix) の部分で通常の配列(密行列)から疎行列に変換しています.結果は CSR 形式の SparseMatrix オブジェクトになります。CSR は行毎に非ゼロ要素を圧縮して保持します。

疎行列に変換された配列は以下のように出力されます.

  (1, 0)    1
  (2, 1)    2

これは座標 (行, 列) に値があることを示しています。(1, 0)2行1列目に1が格納されている,(2, 1)3行2列目に2が格納されていることを表しています.

  • NumPyでは1行1列を(0, 0)で表します.そのため,指定したい行数/列数から1引いたもので記述します.

CSR と COO の違いと使い分け

  • CSR (Compressed Sparse Row)
    • 行方向の圧縮を行う形式。行単位のスライスや行和などが速い。線形代数演算(行列ベクトル積)でも高速。
  • COO (Coordinate)
    • 非ゼロ要素の座標 (row, col, data) をそのまま並べる形式。要素を順に追加・構築する際に使いやすいが、演算では CSR/CSC に変換した方が速い。

変換例

coo = sparse.coo_matrix(matrix)
csr = coo.tocsr()

疎行列から密行列への戻し方と要注意点

 疎行列から密行列へ戻すには toarray() または todense() を使います。

dense_again = sparse_matrix.toarray()

大きな疎行列を .toarray() で密行列に戻すとメモリ不足になります.戻す操作は慎重に行いましょう!

疎行列の内部データにアクセスする方法

 CSR オブジェクトには内部配列があり高速に情報を得られます。indptr[i] から indptr[i+1]-1 までが行 i の非ゼロ要素の index範囲です.

# data: 非ゼロ値の配列
# indices: 各非ゼロ値の列インデックス
# indptr: 各行の開始位置を指すポインタ
print(sparse_matrix.data)
print(sparse_matrix.indices)
print(sparse_matrix.indptr)

メモリ比較の簡単な確認方法

 小さな例でも差を確認できます。

import sys
dense = matrix
sparse_csr = sparse.csr_matrix(matrix)

print("dense size bytes:", dense.nbytes)
# scipy の内部配列の合計サイズを概算
size_est = sparse_csr.data.nbytes + sparse_csr.indices.nbytes + sparse_csr.indptr.nbytes
print("sparse approx bytes:", size_est)

 非ゼロが少ない場合はsparse の方が小さくなります。非ゼロが行列の多数を占める場合は逆に大きくなることに注意してください。

 要素は決めてないけど,任意サイズの配列を用意したいという場合がしばしばあります.このような場合は,要素が0か1で埋められた配列を事前確保しておきます.そうしておけば,要素の数値を入れ替えることで所望の配列を簡単に作ることができるようになります!


任意サイズの配列を用意する方法は?
#ライブラリをロードします.
import numpy as np

#サイズが3行4列の配列(すべての要素が0)を作成します
matrix_1= np.zeros(shape=(3,4))

#サイズが4行2列の配列(すべての要素が1)を作成します
matrix_2 = np.full(shape=(4,2), fill_value=1) 

コード解説

matrix_1 = np.zeros(shape=(3,4))

 指定した shape=(3,4) の配列を作成し 0 で埋めます。任意サイズにするには shape に固定のタプルではなく変数や計算式を渡します(例: np.zeros((n_rows, n_cols)))。dtypeorder を指定すれば型・メモリレイアウトを制御できます。

matrix_2 = np.full(shape=(4,2), fill_value=1)

 指定形状をfill_value で埋める関数です。任意サイズなら shape=(行数, 列数) を変数化します。1 の代わりに 1.0 や配列を渡すと dtype が決まります。fullは定数テンプレートが必要なときに便利です。


行列から情報を取得する

行列から任意の要素を取り出すには?
#ライブラリをロードします.
import numpy as np

# 3x4の行列を作成します
matrix = np.array([1, 2, 3, 4],
                  [5, 6, 7, 8],
                  [9, 10, 11, 12])

#3行2列の要素を抽出します
#3行目=index 2、2列目=index 1
matrix[2, 1]

#3行目の2列から4列までの要素を抽出します
#2列目 index 1 から 4列目 index 3 まで、スライスは end 非包含なので 1:4
matrix[2, 1:4]

#最初の2行のすべての列を抽出します
#行 index 0,1
matrix[:2, :]

#すべての行の3列目の要素を抽出します
#3列目=index 2
matrix[:, 2]

コード解説

matrix = np.array([1, 2, 3, 4],
                  [5, 6, 7, 8],
                  [9, 10, 11, 12])

 3 行 4 列の ndarray を作成します。matrix.shape(3, 4) です。元の提示では二重角括弧が抜けていて構文エラーになります。

elem = matrix[2, 1]

 行インデックス 2(3行目)、列インデックス 1(2列目)を指定して単一要素を取り出します。結果は 10(NumPy スカラー)になります。

slice_row = matrix[2, 1:4]

 行 2 の列 1 から 3(スライス 1:4 は end 非包含)を取り出します。結果は array([10, 11, 12]) です。

top2 = matrix[:2, :]

 行スライス :2 で行 01 を選び、列 : で全列を選択します。結果は array([[1,2,3,4],[5,6,7,8]])(形 (2,4))です。

col3 = matrix[:, 2]

 全行に対して列インデックス 2(3列目)を選びます。結果は array([ 3, 7, 11])(1 次元配列)です。


行列の形状・サイズ・次元数(何次元配列か)はどのように調べる?
import numpy as np

# 3x4の行列(各行をリストで渡す)
matrix = np.array([
    [1,  2,  3,  4],
    [5,  6,  7,  8],
    [9, 10, 11, 12]
])

# 結果表示
print("matrix =")
print(matrix)
print("shape:", matrix.shape)   # (行数, 列数)
print("size:", matrix.size)     # 要素数(行数×列数)
print("ndim:", matrix.ndim)     # 次元数

出力結果例

matrix =
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
shape: (3, 4)
size: 12
ndim: 2

配列の情報を表示するのは基本的ですが,何らかの操作を配列に行った場合は確認する癖をつけておくとよいと思います!

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次