[機械学習のはじめ方] Part6: NumPyによる配列操作の基礎

機械学習

データサイエンスと機械学習の必須ツール、NumPyの基本をマスターしよう!

機械学習やデータ分析の世界へようこそ!これからたくさんのデータを扱うことになりますが、その際に非常に強力な味方となるのがNumPy (Numerical Python)です。NumPyは、Pythonで数値計算、特に配列や行列の計算を高速に行うための基本的なパッケージです。

なぜNumPyが重要なのでしょうか?🤔 それは、多くの機械学習ライブラリ(例: scikit-learn, TensorFlow, PyTorch)が、内部でデータをNumPyの配列形式で扱っているからです。NumPyを理解することは、これらのライブラリを効率的に使いこなすための第一歩となります。

このステップでは、NumPyの最も基本的な機能である配列(ndarray)の作成と操作について学んでいきましょう!

1. NumPyのインストール

まず、NumPyを使うためにはインストールが必要です。Pythonのパッケージ管理ツールであるpipを使って、コマンドライン(ターミナルやコマンドプロンプト)で以下のコマンドを実行します。

pip install numpy

多くの場合、Anacondaなどのデータサイエンス向けPythonディストリビューションを使っている場合は、すでにNumPyがインストールされています。インストール済みか確認するには、PythonインタプリタやJupyter Notebookなどで `import numpy` を実行してみましょう。エラーが出なければOKです!👍

慣例として、NumPyは `np` という別名でインポートされます。今後のコード例でもこの慣例に従います。

import numpy as np

2. NumPy配列 (ndarray) の作成

NumPyの中心的なオブジェクトは、ndarray (N-dimensional array) と呼ばれる多次元配列です。さまざまな方法でndarrayを作成できます。

2.1. Pythonのリストから作成

最も一般的な方法は、Pythonのリストやタプルから np.array() 関数を使って作成する方法です。

# 1次元配列 (ベクトル)
list1 = [1, 2, 3, 4, 5]
arr1 = np.array(list1)
print(arr1)
# 出力: [1 2 3 4 5]

# 2次元配列 (行列)
list2 = [[1, 2, 3], [4, 5, 6]]
arr2 = np.array(list2)
print(arr2)
# 出力:
# [[1 2 3]
#  [4 5 6]]

2.2. 特定の配列を生成する関数

NumPyには、特定のパターンを持つ配列を簡単に作成するための便利な関数が用意されています。

関数説明出力
np.zeros(shape)指定した形状 (shape) の、全ての要素が0の配列を作成np.zeros((2, 3))
[[0. 0. 0.]
 [0. 0. 0.]]
np.ones(shape)指定した形状の、全ての要素が1の配列を作成np.ones((3,))
[1. 1. 1.]
np.arange(start, stop, step)指定した範囲 (startからstop未満) で、指定したステップ (step) ごとの数値を持つ配列を作成 (Pythonの range に似ています)np.arange(0, 10, 2)
[0 2 4 6 8]
np.linspace(start, stop, num)指定した範囲 (startからstopまでを含む) を、指定した数 (num) で等間隔に分割した数値を持つ配列を作成np.linspace(0, 1, 5)
[0.   0.25 0.5  0.75 1.  ]
np.random.rand(d0, d1, ..., dn)0.0以上1.0未満の一様分布の乱数で、指定された形状の配列を作成np.random.rand(2, 2)
[[0.123 0.456]
 [0.789 0.012]] # 例
np.random.randn(d0, d1, ..., dn)平均0、分散1の正規分布(標準正規分布)に従う乱数で、指定された形状の配列を作成np.random.randn(3)
[-0.5 1.2 0.3] # 例

ポイント: np.zerosnp.ones は、後で計算結果を格納するための配列を初期化する際によく使われます。

3. 配列の属性

NumPy配列は、自身に関する情報(属性)を持っています。これらを確認することで、配列の構造を理解できます。

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(f"配列:\n{arr}")

# 配列の形状 (行数, 列数)
print(f"形状 (shape): {arr.shape}") # 出力: (2, 3)

# 配列の次元数
print(f"次元数 (ndim): {arr.ndim}") # 出力: 2

# 配列要素のデータ型
print(f"データ型 (dtype): {arr.dtype}") # 出力: int64 (環境によりint32の場合も)

# 配列の要素数 (全要素の数)
print(f"要素数 (size): {arr.size}") # 出力: 6

特に shape は配列の構造を理解する上で非常に重要です。機械学習モデルに入力するデータの形状を確認・整形する際によく使います。データ型 (dtype) も、メモリ使用量や計算精度に関わるため意識することが大切です。

4. 基本的な配列操作

配列の要素にアクセスしたり、部分的に取り出したり、形を変えたりする操作は基本中の基本です。

4.1. インデックス参照

Pythonのリストと同様に、[] を使って要素にアクセスします。インデックスは0から始まります。多次元配列の場合は、[行インデックス, 列インデックス] のように指定します。

arr1 = np.array([10, 20, 30, 40, 50])
print(f"arr1[0]: {arr1[0]}")   # 出力: 10 (最初の要素)
print(f"arr1[2]: {arr1[2]}")   # 出力: 30 (3番目の要素)
print(f"arr1[-1]: {arr1[-1]}") # 出力: 50 (最後の要素)

arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(f"arr2[0, 1]: {arr2[0, 1]}") # 出力: 2 (1行目、2列目の要素)
print(f"arr2[1, -1]: {arr2[1, -1]}") # 出力: 6 (2行目、最後の列の要素)

4.2. スライシング

配列の一部を範囲指定して取り出す操作をスライシングと呼びます。start:stop:step の形式で指定します。これもPythonのリストのスライシングと似ています。

arr1 = np.array([10, 20, 30, 40, 50])
print(f"arr1[1:4]: {arr1[1:4]}") # 出力: [20 30 40] (インデックス1から4未満)

arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f"arr2[0:2, 1:]: \n{arr2[0:2, 1:]}")
# 出力:
# [[2 3]
#  [5 6]] (0行目から2行目未満、1列目から最後まで)

# 特定の行や列全体を選択
print(f"1行目全体: {arr2[0, :]}") # 出力: [1 2 3]
print(f"2列目全体: {arr2[:, 1]}") # 出力: [2 5 8]

⚠️ 注意: NumPyのスライスは、元の配列の「ビュー(参照)」を返します。つまり、スライスした配列の要素を変更すると、元の配列の要素も変更されてしまいます。コピーが必要な場合は .copy() メソッドを使います。

arr_slice = arr2[0:2, 1:]
arr_slice[0, 0] = 99 # スライスした配列の要素を変更
print(f"変更後のarr2:\n{arr2}")
# 出力:
# [[ 1 99  3]
#  [ 4  5  6]
#  [ 7  8  9]] ← 元の配列も変更されている!

# コピーを作成する場合
arr_copy = arr2[0:2, 1:].copy()
arr_copy[0, 0] = 100 # コピーを変更
print(f"コピー変更後のarr2:\n{arr2}") # 元の配列は変更されない

4.3. 形状変更 (reshape)

reshape() メソッドを使うと、配列の要素数を変えずに形状を変更できます。これは、機械学習モデルが要求する入力データの形式に合わせる際などに頻繁に使われます。

arr = np.arange(1, 10) # [1 2 3 4 5 6 7 8 9]
print(f"元の配列 (shape={arr.shape}): {arr}")

arr_reshaped = arr.reshape((3, 3))
print(f"reshape後の配列 (shape={arr_reshaped.shape}):\n{arr_reshaped}")
# 出力:
# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]

# 要素数が合わない形状には変更できない
# arr.reshape((3, 4)) # これはエラーになる

reshape の引数に -1 を指定すると、他の次元のサイズに基づいて自動的にサイズを計算してくれます。

arr = np.arange(12)
reshaped1 = arr.reshape((3, -1)) # 3行 x 自動計算列
print(f"reshape(3, -1) -> shape={reshaped1.shape}") # 出力: (3, 4)

reshaped2 = arr.reshape((-1, 6)) # 自動計算行 x 6列
print(f"reshape(-1, 6) -> shape={reshaped2.shape}") # 出力: (2, 6)

5. 配列の演算

NumPy配列の強力な機能の一つが、配列同士の高速な演算です。ループを使わずに、配列全体に対して一度に計算(ベクトル化演算)できます。

5.1. 要素ごとの算術演算

同じ形状の配列同士では、四則演算(+, -, *, /)などが要素ごとに行われます。

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(f"a + b = {a + b}")   # 出力: [5 7 9]
print(f"a - b = {a - b}")   # 出力: [-3 -3 -3]
print(f"a * b = {a * b}")   # 出力: [ 4 10 18]
print(f"a / b = {a / b}")   # 出力: [0.25 0.4  0.5 ]
print(f"a ** 2 = {a ** 2}") # 出力: [1 4 9] (べき乗)

スカラー値(単一の数値)との演算も可能です。この場合、スカラー値が配列の全ての要素に対して演算されます。

arr = np.array([1, 2, 3])
print(f"arr + 5 = {arr + 5}") # 出力: [6 7 8]
print(f"arr * 2 = {arr * 2}") # 出力: [2 4 6]

5.2. ブロードキャスト

形状が異なる配列同士でも、特定のルールに従って形状が自動的に拡張され、演算が可能になる場合があります。これをブロードキャストと呼びます。これは非常に強力で便利な機能です。

例えば、2次元配列(行列)の各行に1次元配列(ベクトル)を加算する場合などに使われます。

matrix = np.array([[1, 2, 3], [4, 5, 6]]) # shape=(2, 3)
vector = np.array([10, 20, 30])          # shape=(3,)

# matrixの各行にvectorが加算される
result = matrix + vector
print(f"ブロードキャストによる加算:\n{result}")
# 出力:
# [[11 22 33]
#  [14 25 36]]

ブロードキャストにはルールがありますが、直感的には「足りない次元やサイズが1の次元を、もう一方の配列のサイズに合わせて仮想的に引き伸ばして計算する」イメージです。最初は少し戸惑うかもしれませんが、慣れると非常に効率的なコードが書けるようになります。

5.3. 集計関数

配列全体の合計、平均、最大値、最小値などを計算するための関数も豊富に用意されています。

arr = np.array([[1, 2, 3], [4, 5, 6]])

print(f"全体の合計 (sum): {np.sum(arr)}")     # 出力: 21
print(f"全体の平均 (mean): {np.mean(arr)}")    # 出力: 3.5
print(f"全体の最大値 (max): {np.max(arr)}")     # 出力: 6
print(f"全体の最小値 (min): {np.min(arr)}")     # 出力: 1
print(f"全体の標準偏差 (std): {np.std(arr)}")    # 出力: 1.7078...

axis 引数を指定することで、特定の軸(次元)に沿って集計することも可能です。

  • axis=0: 列方向(縦方向)に集計
  • axis=1: 行方向(横方向)に集計
arr = np.array([[1, 2, 3], [4, 5, 6]])

print(f"列ごとの合計 (axis=0): {np.sum(arr, axis=0)}") # 出力: [5 7 9]
print(f"行ごとの合計 (axis=1): {np.sum(arr, axis=1)}") # 出力: [ 6 15]
print(f"列ごとの最大値 (axis=0): {np.max(arr, axis=0)}") # 出力: [4 5 6]

6. まとめ 🎉

今回は、機械学習の基礎となるNumPyについて、以下の点を学びました。

  • NumPyの重要性とインストール方法
  • ndarray の作成方法(リストから、専用関数から)
  • 配列の属性(shape, ndim, dtype, size)の確認
  • 基本的な操作(インデックス参照、スライシング、reshape
  • 配列の演算(要素ごと、ブロードキャスト、集計関数)

NumPyは非常に多機能ですが、ここで紹介した内容はデータ操作の基本中の基本です。これらの操作に慣れておくことで、今後のデータ前処理やモデル構築がスムーズに進むはずです。

次のステップでは、NumPyをベースにした、より高機能なデータ操作ライブラリである Pandas について学んでいきましょう!📊

コメント

タイトルとURLをコピーしました