NumPy: NumPy 入門

NumPyはPython科学計算の基盤です。機械学習、データ分析、工学シミュレーションのいずれを行うにしても、ほぼすべての数値計算ライブラリはNumPyの上に構築されています。この章では、Pythonリストのパフォーマンス上の問題点から始め、NumPyがどのように160倍の高速化を実現するのかを明らかにします。数値計算への第一歩です。

⚠️ 注意: 以下のコードは、ローカルの Python 環境で実行する必要があります。

1. 学習内容



2. 100万件データでの高速化の旅

(1) 問題:アリスのリストループ

アリスはデータアナリストで、100万個の乱数を2乗する必要があります。彼女は最も「自然な」Pythonコード、つまりリストの要素を1つずつ処理するforループを書きました。

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: リストの二乗(難易度 ⭐)

PYTHON
import time
import random

size = 1_000_000  # 1 million numbers
data = [random.random() for _ in range(size)]

start = time.time()
result = [x * x for x in data]
elapsed = time.time() - start

print(f"List comprehension: {elapsed:.4f} seconds")
# Typical output: List comprehension: 0.8000 seconds
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

アリスのコードは約0.8秒で実行されます。それほど悪くはないように思えますが、同じ操作を数億件のデータポイントに対して行う必要が生じると、待ち時間は耐え難いものになります。

(2) 解決策:ボブのNumPyベクトル化

ボブはたった2行を変更しただけです。リストをnp.arrayに置き換え、ループを単一のベクトル化された乗算に置き換えました。

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: NumPyでの二乗(難易度 ⭐⭐)

PYTHON
import time
import numpy as np

size = 1_000_000  # 1 million numbers
data = np.random.random(size)

start = time.time()
result = data * data  # vectorized operation
elapsed = time.time() - start

print(f"NumPy vectorized: {elapsed:.4f} seconds")
# Typical output: NumPy vectorized: 0.0050 seconds
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

同じ100万個の数値でも、NumPyではわずか約5ミリ秒で処理されます — およそ160倍高速です。

(3) その成果:160倍高速化の理由

NumPyの高速さは「Pythonが速くなった」からではありません — 重要なのは計算をCに委譲し、連続メモリを使用することです。

これがNumPyの核となる思想です — Pythonの使いやすさと、C言語の速度



3. Pythonリストが数値計算を苦手とする理由

(1) ループのオーバーヘッド:インタプリタ実行

Pythonは動的型付け言語です。ループの各反復では、型チェック → メソッド検索 → 演算の実行 → 結果のボックス化という処理を通ります。数値計算において、これらの余分な手順は純粋な無駄です。

PYTHON
# Each iteration: type check + method lookup + boxing
result = []
for x in data:          # Python loop overhead per iteration
    result.append(x * x)  # type check, method dispatch, result boxing
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

コンパイル済みのCのマシンコードと比べると、Pythonのループ1回分のコストは、実際の乗算の数十倍になることがあります。

(2) 型のオーバーヘッド:各要素は完全なオブジェクト

Pythonリストは生の数値を格納するのではなく、PyObjectへのポインタを格納します。整数42はPythonでは28バイトを消費しますが、Cではわずか4バイトです。



4. NumPyの主な利点

(1) ndarrayとは

ndarray(N次元配列)はNumPyの中核となるデータ構造です。その特徴は次のとおりです。

(2) ndarray と Pythonリストの比較

特徴 Pythonリスト NumPy ndarray
要素の型 混在可能 均一(単一のdtype)
メモリ配置 ポインタ配列、要素が分散 連続したメモリブロック
単一整数のメモリ 28バイト(PyObject) 8バイト(int64)
一括演算 リスト内包表記 / forループ ベクトル化、単一の式
ブロードキャスト 非対応 自動的な次元拡張
スライス コピーを返す デフォルトでビューを返す(ゼロコピー)
多次元 ネストしたリスト(不規則) ネイティブなN次元、shape属性
内部実装 CPythonインタプリタ C / Fortranのコンパイル済みコード

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: メモリ使用量の比較(難易度 ⭐)

PYTHON
import sys
import numpy as np

size = 1_000_000  # 1 million integers

# Python list
py_list = list(range(size))
list_bytes = sys.getsizeof(py_list) + sum(sys.getsizeof(x) for x in py_list[:1000]) * size // 1000
print(f"Python list: ~{list_bytes / 1024 / 1024:.1f} MB")

# NumPy ndarray
np_array = np.arange(size, dtype=np.int64)
array_bytes = np_array.nbytes
print(f"NumPy ndarray: {array_bytes / 1024 / 1024:.1f} MB")

print(f"Ratio: {list_bytes / array_bytes:.1f}x more memory for list")
# Typical output:
# Python list: ~44.7 MB
# NumPy ndarray: 7.6 MB
# Ratio: 5.9x more memory for list
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

単純なint64のndarrayは、同じサイズのPythonリストと比べて約6倍少ないメモリしか使用しません。ndarrayは完全なPythonオブジェクトではなく生の値を格納するためです。

(3) ブロードキャストの第一歩

「ブロードキャスト」により、異なる形状の配列同士を、手動で次元を拡張することなく直接演算できます。

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: 配列演算とリスト内包表記の比較(難易度 ⭐⭐)

PYTHON
import numpy as np

# Task: add 100 to every element and multiply by 2
data = [1, 2, 3, 4, 5]

# --- Python list ---
result_list = [(x + 100) * 2 for x in data]
print(result_list)
# [202, 204, 206, 208, 210]

# --- NumPy ndarray ---
arr = np.array(data)
result_np = (arr + 100) * 2  # broadcasting + vectorization
print(result_np)
# [202 204 206 208 210]

# With a 2D array and 1D array
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
# [[11 22 33]
#  [14 25 36]]
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

リスト内包表記ではループのロジックを明示的に書く必要がありますが、NumPyは1つの数式だけで済みます — コードがそのまま数式になります。



5. NumPyエコシステムの概要

(1) NumPyエコシステム

NumPyはPython科学計算エコシステム全体の基盤です。ほぼすべての主要ライブラリがこれに依存しています。

100%
mindmap
  root((NumPy Ecosystem))
    Data Science
      Pandas
      Polars
    Machine Learning
      Scikit-learn
      TensorFlow
      PyTorch
    Scientific Computing
      SciPy
      Matplotlib
      SymPy
    Deep Learning Frameworks
      Keras
      JAX
      MXNet
    Specialized Domains
      scikit-image
      NetworkX
      AstroPy
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

(2) エコシステム参照表

ライブラリ 分野 NumPyに依存する理由
Pandas データ分析 DataFrameは内部で列データをndarrayとして格納
Scikit-learn 機械学習 モデルの入力と出力がndarray
SciPy 科学計算 ndarray上で線形代数・最適化・積分を提供
Matplotlib 可視化 プロットのデータソースがndarray
TensorFlow ディープラーニング Tensorの概念はndarrayに由来し、相互変換可能
PyTorch ディープラーニング Tensorとndarrayは相互運用可能
Polars データ分析 列指向ストレージだが、NumPy互換

(3) NumPyと純粋なPythonの使い分け

シナリオ 純粋なPython NumPy 推奨
数十回程度の単純な演算 十分 わずかに速い 純粋なPython
1万件以上の一括演算 遅い 10〜100倍速い NumPy
行列の乗算 ネストループで非常に遅い BLASベースで非常に速い NumPy
線形方程式の求解 手書きは非現実的 np.linalg.solve NumPy
文字列処理 柔軟 得意ではない 純粋なPython
型が混在するデータ リストが自然に処理 構造化配列が必要 状況による


6. インストールと最初のプログラム

(1) インストール方法

方法 コマンド 用途
pip pip install numpy 一般的で最も簡単
conda conda install numpy Anaconda / Miniconda環境
システムパッケージ apt install python3-numpy Linuxへのシステム全体インストール
ソースから python setup.py build カスタムBLASバックエンドが必要な場合

初心者はpip install numpyを使用してください。Anacondaユーザーはconda install numpyを使用できます。

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: インストールの確認(難易度 ⭐)

BASH
# Install
pip install numpy

# Verify
python -c "import numpy as np; print(np.__version__)"
# Output (example): 2.1.0
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

(2) 最初のndarrayを作成する

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: np.arrayでの配列作成(難易度 ⭐)

PYTHON
import numpy as np

# From a Python list
a = np.array([1, 2, 3, 4, 5])
print(type(a))   # <class 'numpy.ndarray'>
print(a.dtype)   # int64
print(a.shape)   # (5,)

# From nested list (2D)
b = np.array([[1, 2, 3],
              [4, 5, 6]])
print(b.shape)   # (2, 3)
print(b.ndim)    # 2

# Specify dtype explicitly
c = np.array([1, 2, 3], dtype=np.float32)
print(c.dtype)   # float32
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

(3) バージョンと設定の確認

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: バージョンと設定の確認(難易度 ⭐)

PYTHON
import numpy as np

print(f"NumPy version: {np.__version__}")

# Show build configuration (BLAS, LAPACK, etc.)
np.show_config()
# Output includes: BLAS, LAPACK backend info,
# which determines computation performance
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

np.show_config()で表示されるBLAS/LAPACKバックエンドが、NumPyの行列演算の速度を左右します。OpenBLAS、MKL、その他のバックエンド間では、パフォーマンスに数倍の差が生じることがあります。



7. 実践:1000万件の数値の平均と標準偏差

1000万個の浮動小数点数の平均と標準偏差を計算します。これはデータ分析で最も一般的なタスクの1つです。純粋なPythonとNumPyの両方で実装し、コード量速度メモリを比較します。

▶ サンプル

TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: 総合比較 — リスト vs NumPy(難易度 ⭐⭐⭐)

PYTHON
import time
import math
import random
import numpy as np
import sys

size = 10_000_000  # 10 million

# ========== Pure Python ==========
py_data = [random.random() for _ in range(size)]

t0 = time.time()
mean_py = sum(py_data) / len(py_data)
var_py = sum((x - mean_py) ** 2 for x in py_data) / len(py_data)
std_py = math.sqrt(var_py)
elapsed_py = time.time() - t0

# Memory estimate for list
mem_py = sys.getsizeof(py_data) + size * 24  # ~24 bytes per float object

# ========== NumPy ==========
np_data = np.random.random(size)

t0 = time.time()
mean_np = np.mean(np_data)
std_np = np.std(np_data)
elapsed_np = time.time() - t0

# Memory for ndarray
mem_np = np_data.nbytes

# ========== Results ==========
print(f"--- Pure Python ---")
print(f"  Mean: {mean_py:.6f}  Std: {std_py:.6f}")
print(f"  Time: {elapsed_py:.3f}s")
print(f"  Memory: ~{mem_py / 1024 / 1024:.0f} MB")

print(f"--- NumPy ---")
print(f"  Mean: {mean_np:.6f}  Std: {std_np:.6f}")
print(f"  Time: {elapsed_np:.3f}s")
print(f"  Memory: {mem_np / 1024 / 1024:.1f} MB")

print(f"--- Comparison ---")
print(f"  Speedup: {elapsed_py / elapsed_np:.1f}x")
print(f"  Memory saving: {mem_py / mem_np:.1f}x")
# Typical output:
# --- Pure Python ---
#   Mean: 0.500032  Std: 0.288675
#   Time: 3.200s
#   Memory: ~305 MB
# --- NumPy ---
#   Mean: 0.500032  Std: 0.288675
#   Time: 0.030s
#   Memory: 76.3 MB
# --- Comparison ---
#   Speedup: 106.7x
#   Memory saving: 4.0x
TEXT 📖 参照専用
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
指標 純粋なPython NumPy 比較
コード行数(コアロジック) 4行 2行 NumPyは50%少ない
実行時間 約3.2秒 約0.03秒 約100倍高速
メモリ使用量 約305MB 約76MB 4分の1

結論:データが大きくなるほど、NumPyの真価が発揮されます。1000万件のデータポイントでは、NumPyは速度とメモリの両面で純粋なPythonを圧倒します。



❓ よくある質問

Q NumPyとPythonの関係は?
A NumPyはサードパーティ製のライブラリであり、Python標準ライブラリには含まれません。中核となる計算エンジンはCで書かれており、Pythonインターフェースを通じて公開されているため、PythonからCに近い速度を得られます。
Q NumPyがリストよりはるかに高速な理由は?
A 理由は3つあります — ① Cレベルの実装がPythonインタプリタのオーバーヘッドを回避する、② 連続メモリ配置がCPUキャッシュ効率を最大化する、③ ベクトル化演算が配列全体を1つの命令で処理し、要素ごとのループが不要になる、という点です。
Q NumPyを使うためにCを学ぶ必要はありますか?
A いいえ。NumPyの設計目標は、PythonユーザーがPythonの構文のままでCレベルの速度を享受できるようにすることです。Cが必要になるのは、低レベルコードに貢献したい場合や、NumPy用のカスタムC拡張を書きたい場合だけです。
Q NumPyはExcelの代わりになりますか?
A 数値計算やバッチ処理において、NumPyはExcelよりはるかに強力で効率的です。ただし、NumPyにはスプレッドシートのUI、ドラッグ&ドロップのグラフ、インタラクティブなフィルタリングはありません。通常はPandas(表形式データ)やMatplotlib(可視化)と組み合わせて使用します。
Q NumPy 2.xと1.xの違いは?
A NumPy 2.0(2024年リリース)では、主にC APIの安定性が向上し、いくつかの文字列操作APIが追加され、dtypeシステムが強化されました。日常的なPythonユーザーにとってAPIの変更はわずかで、ほとんどの1.xコードはそのまま移行できます。新しいプロジェクトでは2.xを使用すべきです。
Q ndarrayとPythonのarrayモジュールの違いは?
A Python組み込みのarrayモジュールは1次元の均一配列のみをサポートし、ブロードキャスト、線形代数、FFT機能はありません。NumPyのndarrayは多次元データ、ブロードキャスト、豊富な数学関数をサポートしており、まったく次元の異なる存在です。

📖 まとめ



📝 練習問題

  1. 初心者(難易度 ⭐):NumPyをインストールし、import numpy as np; print(np.__version__)を実行してください。バージョンが1.24以上であることを確認し、出力を記録してください。

  2. 中級(難易度 ⭐⭐):それぞれ500万個の乱数を含むリストとndarrayを作成してください。リスト内包表記とNumPyのベクトル化を使い、各数値の2乗に10を加えた値を計算してください。time.time()で両方の実行時間を計測して比較し、速度比を記録してください。

  3. 上級(難易度 ⭐⭐⭐)np.show_config()を実行し、使用しているNumPyのBLASバックエンド(OpenBLAS / MKL / その他)を特定してください。このバックエンドが行列演算のパフォーマンスにどのように影響するかを調査し、簡単な説明を書いてください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%