[Pythonのはじめ方] Part28: NumPyによる数値処理

Python
このページは、Pythonの学習ステップ Step 7: ライブラリ活用と応用 の中の NumPyによる数値処理 について解説します。 データ分析や機械学習の世界へようこそ!ここではその第一歩として、Pythonで数値計算を高速に行うための必須ライブラリ、NumPyの基本を学びます。

1. NumPyとは? 🤔

NumPy(ナンパイまたはナムパイと読みます)は、「Numerical Python」の略で、Pythonでベクトルや行列といった多次元配列を効率的に扱うためのライブラリです。 Python標準のリストでも似たようなことはできますが、NumPyを使うと、特に大量の数値データを扱う計算が非常に高速になります。これは、NumPyの内部がC言語などで最適化されているためです。

データサイエンス、機械学習、科学技術計算など、数値計算が重要な分野では、NumPyはデファクトスタンダード(事実上の標準)として広く利用されています。PandasやMatplotlib、Scikit-learnといった他の有名なライブラリも、NumPyをベースに作られています。

2. NumPyのインストールとインポート

インストール

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

pip install numpy

Jupyter NotebookやGoogle Colaboratoryなど、一部の環境では最初からインストールされている場合もあります。

インポート

インストールしたNumPyをPythonスクリプトで使うには、import文を使います。慣例として、npという別名(エイリアス)をつけてインポートするのが一般的です。

import numpy as np

これで、以降はnp.に続けてNumPyの機能(関数やクラスなど)を呼び出すことができます。

3. NumPy配列 (ndarray) の基本

NumPyの中心的な機能は、ndarray (N-dimensional array) と呼ばれる多次元配列オブジェクトです。これは、同じデータ型の要素を持つ多次元のデータの集まりです。

ndarrayの作成方法

ndarrayを作成するにはいくつかの方法があります。

  1. Pythonのリストやタプルから作成: np.array()関数を使います。これが最も基本的な方法です。
    # 1次元配列 (ベクトル)
    list1 = [1, 2, 3, 4, 5]
    arr1 = np.array(list1)
    print(arr1)  # 出力: [1 2 3 4 5]
    print(type(arr1)) # 出力: <class 'numpy.ndarray'>
    
    # 2次元配列 (行列)
    list2 = [[1, 2, 3], [4, 5, 6]]
    arr2 = np.array(list2)
    print(arr2)
    # 出力:
    # [[1 2 3]
    #  [4 5 6]]
  2. 特定の値を要素とする配列を作成:
    • np.zeros(shape): 指定した形状 (shape) で、要素がすべて0の配列を作成します。
    • np.ones(shape): 指定した形状で、要素がすべて1の配列を作成します。
    • np.full(shape, fill_value): 指定した形状で、要素がすべて指定した値 (fill_value) の配列を作成します。
    # 3x4のゼロ配列
    zeros_arr = np.zeros((3, 4))
    print(zeros_arr)
    # 出力:
    # [[0. 0. 0. 0.]
    #  [0. 0. 0. 0.]
    #  [0. 0. 0. 0.]]
    
    # 2x3の1配列
    ones_arr = np.ones((2, 3))
    print(ones_arr)
    # 出力:
    # [[1. 1. 1.]
    #  [1. 1. 1.]]
    
    # 2x2で要素がすべて7の配列
    full_arr = np.full((2, 2), 7)
    print(full_arr)
    # 出力:
    # [[7 7]
    #  [7 7]]

    ※ 要素のデータ型は、指定しなければ浮動小数点数 (float) になることが多いです。

  3. 連番や等間隔の配列を作成:
    • np.arange(start, stop, step): Pythonのrangeに似ていますが、ndarrayを生成します。整数だけでなく浮動小数点数も扱えます。
    • np.linspace(start, stop, num): 指定した範囲 (startからstopまで) を等間隔に指定個数 (num) で区切った値を要素とする配列を作成します。
    # 0から9までの整数配列 (10は含まない)
    range_arr = np.arange(0, 10, 1) # step=1 は省略可: np.arange(10)
    print(range_arr)
    # 出力: [0 1 2 3 4 5 6 7 8 9]
    
    # 0から1までを5個の要素で等間隔に区切る配列
    linspace_arr = np.linspace(0, 1, 5)
    print(linspace_arr)
    # 出力: [0.   0.25 0.5  0.75 1.  ]
  4. 乱数配列の作成: np.randomモジュールを使います。
    # 0.0以上1.0未満の一様乱数で3x3配列を作成
    rand_arr = np.random.rand(3, 3)
    print(rand_arr)
    # 出力例:
    # [[0.123 0.456 0.789]
    #  [0.987 0.654 0.321]
    #  [0.111 0.222 0.333]]
    
    # 平均0、標準偏差1の正規分布(ガウス分布)に従う乱数で2x4配列を作成
    randn_arr = np.random.randn(2, 4)
    print(randn_arr)
    # 出力例:
    # [[-0.5  1.2 -0.8  0.1]
    #  [ 0.9 -1.5  0.3 -0.2]]
    
    # 0から9までの整数乱数を5個生成
    randint_arr = np.random.randint(0, 10, 5)
    print(randint_arr)
    # 出力例: [3 7 0 9 2]

ndarrayの属性

作成したndarrayは、自身の情報を持ついくつかの属性(プロパティ)を持っています。

属性 説明 例 (arr = np.array([[1, 2], [3, 4]]) の場合)
ndim 配列の次元数 (Number of dimensions) arr.ndim2
shape 各次元の要素数をタプルで表したもの (配列の形状) arr.shape(2, 2)
size 配列の全要素数 arr.size4
dtype 配列の要素のデータ型 arr.dtypedtype('int64') (環境により異なる場合があります)
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(f"次元数 (ndim): {arr.ndim}")
print(f"形状 (shape): {arr.shape}")
print(f"全要素数 (size): {arr.size}")
print(f"データ型 (dtype): {arr.dtype}")
# 出力:
# 次元数 (ndim): 2
# 形状 (shape): (2, 3)
# 全要素数 (size): 6
# データ型 (dtype): int64

4. NumPy配列の操作

NumPy配列は、Pythonのリストに似た操作(インデックス参照、スライス)に加え、より高度で高速な操作が可能です。

インデックス参照とスライス

Pythonのリストと同様に、[]を使って要素にアクセスしたり、範囲を指定して部分配列を取り出したり(スライス)できます。多次元配列の場合は、次元ごとにカンマ,で区切って指定します。

arr = np.arange(10)  # [0 1 2 3 4 5 6 7 8 9]

# インデックス参照 (0から始まる)
print(arr[0])    # 出力: 0
print(arr[5])    # 出力: 5
print(arr[-1])   # 出力: 9 (末尾の要素)

# スライス [start:stop:step] (stopは含まない)
print(arr[2:5])  # 出力: [2 3 4] (インデックス2から5の手前まで)
print(arr[:3])   # 出力: [0 1 2] (最初からインデックス3の手前まで)
print(arr[5:])   # 出力: [5 6 7 8 9] (インデックス5から最後まで)
print(arr[::2])  # 出力: [0 2 4 6 8] (最初から最後まで2つ飛ばし)

# 多次元配列の場合
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 1行目 (インデックス0), 2列目 (インデックス1) の要素
print(arr2d[0, 1]) # 出力: 2

# 1行目全体
print(arr2d[0, :]) # 出力: [1 2 3] (arr2d[0] と同じ)

# 2列目全体
print(arr2d[:, 1]) # 出力: [2 5 8]

# 部分行列 (0行目と1行目、1列目と2列目)
print(arr2d[0:2, 1:3])
# 出力:
# [[2 3]
#  [5 6]]

要素ごとの演算 (Element-wise operations)

NumPy配列同士の算術演算(+, -, *, /, **など)は、基本的に同じ位置にある要素ごとに行われます。これはベクトル化 (Vectorization) と呼ばれ、Pythonのforループで要素ごとに計算するよりも格段に高速です。

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

# 要素ごとの足し算
print(a + b)  # 出力: [5 7 9]

# 要素ごとの掛け算
print(a * b)  # 出力: [ 4 10 18]

# 配列とスカラー(単一の数値)の演算
print(a * 10) # 出力: [10 20 30]
print(a + 5)  # 出力: [6 7 8]

# 比較演算も要素ごとに行われる (結果はブール値の配列)
print(a > 1)  # 出力: [False  True  True]
注意点⚠️: 要素ごとの演算を行うには、基本的に配列の形状 (shape) が一致している必要があります。形状が異なる場合の演算ルールについては、後述の「ブロードキャスティング」で説明します。

5. 数学関数と統計関数 📊

NumPyには、配列全体や特定の軸に沿って計算を行うための便利な数学関数や統計関数が多数用意されています。

基本的な数学関数

三角関数、指数関数、対数関数などが用意されており、これらも要素ごとに適用されます。

arr = np.array([1, 4, 9])

# 平方根
print(np.sqrt(arr))  # 出力: [1. 2. 3.]

# 指数関数 (eのべき乗)
print(np.exp(arr))   # 出力: [  2.71828183  54.59815003 8103.08392758]

# 自然対数 (log_e)
print(np.log(arr))   # 出力: [0.         1.38629436 2.19722458]

# 三角関数 (角度はラジアンで指定)
angles = np.array([0, np.pi/2, np.pi]) # np.pi は円周率
print(np.sin(angles)) # 出力: [0.0000000e+00 1.0000000e+00 1.2246468e-16] (ほぼ [0. 1. 0.])

統計関数

合計、平均、最大値、最小値などを簡単に計算できます。多次元配列の場合、axis引数を使って計算する軸(方向)を指定できます。

  • axis=0: 各列に対して計算(縦方向)
  • axis=1: 各行に対して計算(横方向)
  • axisを指定しない場合: 配列全体の要素に対して計算
arr2d = np.array([[1, 2, 3], [4, 5, 6]])

# 全要素の合計
print(np.sum(arr2d))       # 出力: 21 (1+2+3+4+5+6)

# 各列の合計 (axis=0)
print(np.sum(arr2d, axis=0)) # 出力: [5 7 9] ([1+4, 2+5, 3+6])

# 各行の合計 (axis=1)
print(np.sum(arr2d, axis=1)) # 出力: [ 6 15] ([1+2+3, 4+5+6])

# 全要素の平均値
print(np.mean(arr2d))      # 出力: 3.5

# 各列の最大値 (axis=0)
print(np.max(arr2d, axis=0)) # 出力: [4 5 6]

# 各行の最小値 (axis=1)
print(np.min(arr2d, axis=1)) # 出力: [1 4]

他にも、標準偏差 (np.std)、分散 (np.var)、中央値 (np.median) など、多くの統計関数が利用可能です。

6. ブロードキャスティング 📡

ブロードキャスティングは、形状 (shape) が異なる配列同士で演算を行う際に、NumPyが自動的に配列の形状を「拡張」して合わせてくれる機能です。これにより、明示的に形状を揃えるコードを書かなくても、柔軟な計算が可能になります。

例えば、配列の各要素に同じ値を足したり掛けたりする操作(スカラー演算)も、ブロードキャスティングの一種です。スカラー値が配列と同じ形状に「拡張」されてから演算が行われていると考えることができます。

ブロードキャスティングのルール:

  1. 2つの配列の次元数が異なる場合、次元数が少ない方の配列の形状の先頭に1を追加して次元数を揃えます。
  2. 次に、各次元のサイズを比較します。以下のいずれかの条件を満たす場合、その次元は互換性があるとみなされます。
    • 次元のサイズが等しい。
    • どちらかの次元のサイズが1である。
  3. すべての次元で互換性があれば、ブロードキャスティングが可能です。サイズが1の次元は、もう一方の配列のサイズに合わせて「引き伸ばされ」て計算が行われます。
  4. 互換性のない次元がある場合(サイズが異なり、かつどちらも1ではない場合)、エラーが発生します。

例:

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # shape (3, 3)
b = np.array([10, 20, 30])                      # shape (3,)

# a (3, 3) と b (3,) の足し算
# 1. 次元数を揃える: b の形状を (1, 3) とみなす
# 2. 各次元のサイズ比較:
#    - 次元0: aは3, bは1 -> 互換性あり (bが拡張される)
#    - 次元1: aは3, bは3 -> 互換性あり (サイズが等しい)
# 3. ブロードキャスト実行: bが [[10, 20, 30], [10, 20, 30], [10, 20, 30]] のように拡張されて計算される

result = a + b
print(result)
# 出力:
# [[11 22 33]
#  [14 25 36]
#  [17 28 39]]

# 例2: 列ベクトルとの演算
c = np.array([[10], [20], [30]]) # shape (3, 1)

# a (3, 3) と c (3, 1) の足し算
# 1. 次元数は同じ (2次元)
# 2. 各次元のサイズ比較:
#    - 次元0: aは3, cは3 -> 互換性あり
#    - 次元1: aは3, cは1 -> 互換性あり (cが拡張される)
# 3. ブロードキャスト実行: cが [[10, 10, 10], [20, 20, 20], [30, 30, 30]] のように拡張されて計算される

result2 = a + c
print(result2)
# 出力:
# [[11 12 13]
#  [24 25 26]
#  [37 38 39]]

ブロードキャスティングを理解すると、より簡潔で効率的なNumPyコードを書くことができます。

7. まとめと次のステップ 📚

今回は、Pythonの数値計算ライブラリNumPyの基本的な使い方について学びました。

  • NumPyは多次元配列ndarrayを使って高速な数値計算を実現します。
  • np.array(), np.zeros(), np.arange() などでndarrayを作成できます。
  • インデックス参照、スライス、要素ごとの演算が効率的に行えます。
  • np.sum(), np.mean() などの数学・統計関数が豊富に用意されています。
  • ブロードキャスティングにより、形状の異なる配列間の演算も柔軟に行えます。

NumPyは非常に強力で多機能なライブラリであり、ここで紹介したのはほんの一部です。しかし、これらの基本をマスターすれば、データ分析や機械学習でよく使われる他のライブラリ(Pandas, Matplotlib, Scikit-learnなど)へスムーズに進むことができます。

次は、データ分析に特化したライブラリである Pandas について学んでいきましょう! PandasはNumPyをベースにしており、表形式のデータを効率的に扱うための機能を提供します。

🎉 NumPyの基礎を学びました!この知識を活かして、さらにデータサイエンスの世界を探求していきましょう!

参考情報

コメント

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