「データ処理や数値計算をもっと効率的にやりたい」
「NumPyってよく聞くけど、普通のリストと何が違うの?」
そんな疑問を解決するために、今回はNumPy配列について、初心者の方でも理解できるように詳しく説明していきます。
NumPyとは?なぜ必要なのか

NumPyの基本概念
NumPyとは、「Numerical Python(ナメリカル・パイソン)」の略で、数値計算に特化したpythonライブラリです。
NumPy配列(ndarray)の利点
# 普通のリストでの計算
normal_list = [1, 2, 3, 4, 5]
doubled_list = []
for num in normal_list:
doubled_list.append(num * 2)
print(doubled_list) # [2, 4, 6, 8, 10]
# NumPy配列での計算
import numpy as np
numpy_array = np.array([1, 2, 3, 4, 5])
doubled_array = numpy_array * 2
print(doubled_array) # [2 4 6 8 10]
このように、NumPy配列を使うと計算がとても簡潔に書けます。
リストとNumPy配列の比較
特徴 | リスト(list) | NumPy配列(ndarray) |
---|---|---|
データ型 | 混在可能 | 統一必須(全要素同じ型) |
多次元対応 | 工夫が必要 | 標準対応 |
計算速度 | 遅い | 高速(C言語ベース) |
メモリ効率 | 普通 | 高い |
数学演算 | 手動でループ | 一括処理可能 |
パフォーマンスの違いを実感してみる
import numpy as np
import time
# 大きなデータで速度比較
size = 1000000
# リストでの計算
start = time.time()
python_list = list(range(size))
result_list = [x * 2 for x in python_list]
list_time = time.time() - start
# NumPy配列での計算
start = time.time()
numpy_array = np.arange(size)
result_array = numpy_array * 2
numpy_time = time.time() - start
print(f"リストの計算時間: {list_time:.4f}秒")
print(f"NumPyの計算時間: {numpy_time:.4f}秒")
print(f"NumPyは約{list_time/numpy_time:.1f}倍高速")
NumPyのインストールと基本設定
インストール方法
# pip を使ってインストール
pip install numpy
# condaを使ってインストール(Anaconda環境の場合)
conda install numpy
基本的なインポート
import numpy as np # 慣例的に np という別名を使う
# バージョン確認
print(np.__version__) # 1.21.0 など
NumPy配列の作成方法

リストからNumPy配列を作成
# 1次元配列
list_1d = [1, 2, 3, 4, 5]
array_1d = np.array(list_1d)
print(array_1d) # [1 2 3 4 5]
print(type(array_1d)) # <class 'numpy.ndarray'>
# 2次元配列
list_2d = [[1, 2, 3], [4, 5, 6]]
array_2d = np.array(list_2d)
print(array_2d)
# [[1 2 3]
# [4 5 6]]
# 3次元配列
list_3d = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
array_3d = np.array(list_3d)
print(array_3d.shape) # (2, 2, 2)
特定の値で初期化する方法
# すべて0の配列
zeros_array = np.zeros((3, 4)) # 3行4列
print(zeros_array)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]
# すべて1の配列
ones_array = np.ones((2, 3)) # 2行3列
print(ones_array)
# [[1. 1. 1.]
# [1. 1. 1.]]
# 任意の値で埋める
full_array = np.full((2, 2), 7) # 2x2の配列を7で埋める
print(full_array)
# [[7 7]
# [7 7]]
# 単位行列(対角線が1、それ以外が0)
identity_matrix = np.eye(3) # 3x3の単位行列
print(identity_matrix)
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
数列を生成する方法
# arange:範囲を指定した数列
range_array = np.arange(0, 10, 2) # 0から10未満、2刻み
print(range_array) # [0 2 4 6 8]
# linspace:等間隔の数列
linear_array = np.linspace(0, 1, 5) # 0から1まで5等分
print(linear_array) # [0. 0.25 0.5 0.75 1. ]
# logspace:対数スケールの数列
log_array = np.logspace(0, 2, 3) # 10^0から10^2まで3点
print(log_array) # [ 1. 10. 100.]
ランダムな配列の生成
# 0から1の一様乱数
random_array = np.random.random((2, 3))
print(random_array)
# [[0.123 0.456 0.789]
# [0.234 0.567 0.890]]
# 正規分布(平均0、標準偏差1)
normal_array = np.random.normal(0, 1, (2, 3))
print(normal_array)
# 整数の乱数
randint_array = np.random.randint(1, 10, (2, 3)) # 1から9の整数
print(randint_array)
NumPy配列の基本操作
配列の情報を確認する
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
# 形状(shape)
print(arr.shape) # (2, 4) ← 2行4列
# 次元数
print(arr.ndim) # 2 ← 2次元
# 要素数
print(arr.size) # 8 ← 合計8個の要素
# データ型
print(arr.dtype) # int64(環境により異なる)
要素へのアクセス
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 単一要素
print(arr[0, 1]) # 2 (0行目1列目)
print(arr[1, 2]) # 6 (1行目2列目)
# 負のインデックス
print(arr[-1, -1]) # 9 (最後の行の最後の列)
# 行全体
print(arr[1, :]) # [4 5 6] (1行目すべて)
print(arr[1]) # [4 5 6] (省略記法)
# 列全体
print(arr[:, 2]) # [3 6 9] (2列目すべて)
スライス(部分取り出し)
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# 部分配列の取得
print(arr[0:2, 1:3]) # 0-1行目、1-2列目
# [[2 3]
# [6 7]]
# ステップ指定
print(arr[::2, ::2]) # 2行おき、2列おき
# [[ 1 3]
# [ 9 11]]
# 条件による抽出
print(arr[arr > 5]) # 5より大きい要素のみ
# [ 6 7 8 9 10 11 12]
要素の変更
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 単一要素の変更
arr[0, 1] = 99
print(arr)
# [[ 1 99 3]
# [ 4 5 6]]
# 複数要素の変更
arr[1, :] = [10, 11, 12] # 1行目をすべて変更
print(arr)
# [[ 1 99 3]
# [10 11 12]]
# 条件による一括変更
arr[arr > 10] = 0 # 10より大きい要素を0にする
print(arr)
# [[ 1 0 3]
# [ 0 0 0]]
配列の形状操作

reshape:形状の変更
arr = np.arange(12) # [0 1 2 3 4 5 6 7 8 9 10 11]
# 1次元を2次元に変更
reshaped = arr.reshape(3, 4)
print(reshaped)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 自動サイズ計算(-1を使用)
auto_shaped = arr.reshape(4, -1) # 4行、列数は自動計算
print(auto_shaped)
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
次元の追加・削除
arr = np.array([1, 2, 3])
# 次元を追加
expanded = np.expand_dims(arr, axis=0) # 行として追加
print(expanded.shape) # (1, 3)
expanded = np.expand_dims(arr, axis=1) # 列として追加
print(expanded.shape) # (3, 1)
# 次元を削除(サイズが1の次元のみ)
squeezed = np.squeeze(expanded)
print(squeezed.shape) # (3,)
配列の結合
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
# 縦方向に結合
v_concat = np.vstack([arr1, arr2])
print(v_concat)
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# 横方向に結合
h_concat = np.hstack([arr1, arr2])
print(h_concat)
# [[1 2 5 6]
# [3 4 7 8]]
# 軸を指定して結合
concat_axis0 = np.concatenate([arr1, arr2], axis=0) # 縦
concat_axis1 = np.concatenate([arr1, arr2], axis=1) # 横
NumPy配列での計算

要素ごとの演算
arr = np.array([1, 2, 3, 4, 5])
# 四則演算
print(arr + 10) # [11 12 13 14 15]
print(arr - 2) # [-1 0 1 2 3]
print(arr * 3) # [ 3 6 9 12 15]
print(arr / 2) # [0.5 1. 1.5 2. 2.5]
print(arr ** 2) # [ 1 4 9 16 25] (べき乗)
# 数学関数
print(np.sqrt(arr)) # [1. 1.41 1.73 2. 2.23] (平方根)
print(np.exp(arr)) # 指数関数
print(np.log(arr)) # 自然対数
print(np.sin(arr)) # 三角関数
配列同士の演算
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
# 要素ごとの演算
print(arr1 + arr2) # [5 7 9]
print(arr1 * arr2) # [4 10 18]
# 行列の積(ドット積)
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
dot_product = np.dot(matrix1, matrix2)
print(dot_product)
# [[19 22]
# [43 50]]
# @ 演算子でも行列積が可能(Python 3.5以降)
result = matrix1 @ matrix2
print(result) # 同じ結果
ブロードキャスティング
# 異なる形状の配列同士の演算
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
arr_1d = np.array([10, 20, 30])
# 1次元配列が各行に適用される
result = arr_2d + arr_1d
print(result)
# [[11 22 33]
# [14 25 36]]
# スカラーとの演算
matrix = np.array([[1, 2], [3, 4]])
scaled = matrix * 5
print(scaled)
# [[ 5 10]
# [15 20]]
統計・集計関数
基本的な統計量
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 基本統計
print(arr.sum()) # 21 (総和)
print(arr.mean()) # 3.5 (平均)
print(arr.std()) # 1.71 (標準偏差)
print(arr.var()) # 2.92 (分散)
print(arr.max()) # 6 (最大値)
print(arr.min()) # 1 (最小値)
# 軸を指定した統計
print(arr.sum(axis=0)) # [5 7 9] (列ごとの合計)
print(arr.sum(axis=1)) # [6 15] (行ごとの合計)
print(arr.mean(axis=0)) # [2.5 3.5 4.5] (列ごとの平均)
順序統計
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
# ソート
sorted_arr = np.sort(arr)
print(sorted_arr) # [1 1 2 3 4 5 6 9]
# インデックスのソート
sorted_indices = np.argsort(arr)
print(sorted_indices) # [1 3 6 0 2 4 7 5]
# パーセンタイル
print(np.percentile(arr, 50)) # 3.5 (中央値)
print(np.percentile(arr, 25)) # 2.25 (第1四分位)
print(np.percentile(arr, 75)) # 5.5 (第3四分位)
# 最大・最小のインデックス
print(np.argmax(arr)) # 5 (最大値のインデックス)
print(np.argmin(arr)) # 1 (最小値のインデックス)
条件による処理
arr = np.array([1, 5, 3, 8, 2, 7])
# 条件を満たす要素の抽出
filtered = arr[arr > 4]
print(filtered) # [5 8 7]
# 条件を満たす要素の個数
count = np.sum(arr > 4)
print(count) # 3
# 条件による置き換え
result = np.where(arr > 4, arr, 0) # 4より大きいものはそのまま、そうでなければ0
print(result) # [0 5 0 8 0 7]
# 複数条件
result = np.where((arr > 2) & (arr < 7), arr, -1)
print(result) # [-1 5 3 -1 -1 -1]
実践的な使用例

画像データの処理
# 画像を模擬した3次元配列(高さ×幅×RGB)
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
print(f"画像サイズ: {image.shape}") # (100, 100, 3)
# グレースケール変換(RGB→グレー)
gray = np.mean(image, axis=2).astype(np.uint8)
print(f"グレースケール画像サイズ: {gray.shape}") # (100, 100)
# 画像の明度調整
brightened = np.clip(image + 50, 0, 255) # 明度+50、0-255の範囲でクリップ
# 画像の一部を切り出し
cropped = image[25:75, 25:75, :] # 中央部分を切り出し
print(f"切り出し画像サイズ: {cropped.shape}") # (50, 50, 3)
時系列データの分析
# 模擬的な時系列データ
days = np.arange(365) # 1年分の日数
temperature = 20 + 10 * np.sin(2 * np.pi * days / 365) + np.random.normal(0, 2, 365)
# 移動平均の計算
def moving_average(data, window_size):
return np.convolve(data, np.ones(window_size)/window_size, mode='valid')
# 7日移動平均
temp_ma = moving_average(temperature, 7)
# 統計情報
print(f"年間平均気温: {np.mean(temperature):.2f}°C")
print(f"最高気温: {np.max(temperature):.2f}°C")
print(f"最低気温: {np.min(temperature):.2f}°C")
print(f"気温の標準偏差: {np.std(temperature):.2f}°C")
行列計算(線形代数)
# 連立方程式の解法
# 2x + 3y = 7
# x - y = 1
# 係数行列
A = np.array([[2, 3], [1, -1]])
# 定数ベクトル
b = np.array([7, 1])
# 解を求める
solution = np.linalg.solve(A, b)
print(f"解: x = {solution[0]:.2f}, y = {solution[1]:.2f}")
# 検証
print(f"検証: {A @ solution}") # [7. 1.] になるはず
# 固有値・固有ベクトル
eigenvalues, eigenvectors = np.linalg.eig(A)
print(f"固有値: {eigenvalues}")
print(f"固有ベクトル:\n{eigenvectors}")
データの正規化
# サンプルデータ
data = np.random.normal(100, 15, 1000) # 平均100、標準偏差15の正規分布
# Min-Max正規化(0-1の範囲に変換)
normalized_minmax = (data - np.min(data)) / (np.max(data) - np.min(data))
# Z-score正規化(平均0、標準偏差1に変換)
normalized_zscore = (data - np.mean(data)) / np.std(data)
print(f"元データ: 平均={np.mean(data):.2f}, 標準偏差={np.std(data):.2f}")
print(f"Min-Max正規化: 最小={np.min(normalized_minmax):.2f}, 最大={np.max(normalized_minmax):.2f}")
print(f"Z-score正規化: 平均={np.mean(normalized_zscore):.2f}, 標準偏差={np.std(normalized_zscore):.2f}")
よくあるエラーと対処法
形状不一致エラー
# よくあるエラー
arr1 = np.array([[1, 2, 3]]) # (1, 3)
arr2 = np.array([[1], [2]]) # (2, 1)
try:
result = arr1 + arr2
except ValueError as e:
print(f"エラー: {e}")
# 解決方法:形状を確認して調整
print(f"arr1の形状: {arr1.shape}")
print(f"arr2の形状: {arr2.shape}")
# 形状を合わせる
arr2_reshaped = arr2.reshape(1, 2) # または適切な形状に変更
データ型の問題
# 意図しないデータ型
arr_int = np.array([1, 2, 3]) # int型
arr_float = arr_int / 2
print(arr_float.dtype) # float64になる
# データ型を明示的に指定
arr_specified = np.array([1, 2, 3], dtype=np.float32)
print(arr_specified.dtype) # float32
# データ型の変換
arr_converted = arr_int.astype(np.float64)
print(arr_converted.dtype) # float64
コピーと参照の問題
# 参照による予期しない変更
original = np.array([1, 2, 3, 4, 5])
reference = original # 参照(コピーではない)
reference[0] = 99
print(original) # [99 2 3 4 5] ← 元の配列も変更される
# 明示的なコピー
original = np.array([1, 2, 3, 4, 5])
copy_array = original.copy() # 明示的なコピー
copy_array[0] = 99
print(original) # [1 2 3 4 5] ← 元の配列は変更されない
# ビューとコピーの違い
view = original[1:3] # ビュー(元データを参照)
copy = original[1:3].copy() # コピー(独立したデータ)
よくある質問

- QNumPy配列とPythonリスト、どちらを使えば良い?
- A
数値計算やデータ処理が主目的ならNumPy配列、汎用的なデータ管理ならリストがおすすめです。
- Q多次元配列のインデックスがわからなくなる
- A
array.shape
で形状を確認し、array[行, 列]
の順序を意識しましょう。
- Qメモリ不足エラーが出る
- A
大きな配列を作成する場合は、データ型を
float32
やint32
にしてメモリ使用量を削減できます。# メモリ効率の良いデータ型 large_array = np.zeros((10000, 10000), dtype=np.float32) # float64より半分のメモリ
- QNoneや欠損値はどう扱う?
- A
NumPyでは
np.nan
(Not a Number)を使います。arr_with_nan = np.array([1.0, 2.0, np.nan, 4.0]) print(np.isnan(arr_with_nan)) # [False False True False] print(np.nanmean(arr_with_nan)) # NaNを除いた平均
- QNumPy配列をファイルに保存したい
- A
np.save()
やnp.savez()
を使って効率的に保存できます。# 保存 arr = np.array([1, 2, 3, 4, 5]) np.save('my_array.npy', arr) # 読み込み loaded_arr = np.load('my_array.npy') print(loaded_arr) # [1 2 3 4 5]
まとめ
NumPy配列は、pythonで高速・効率的に数値データを扱うための必須ツールです。
おさらい:
- 基本概念:NumPyはリストより高速でメモリ効率が良い
- 作成方法:
np.array()
、np.zeros()
、np.arange()
など多様な方法 - 操作方法:インデックス、スライス、reshape、結合など柔軟な操作
- 計算機能:要素ごとの演算、統計処理、線形代数が簡潔に記述可能
- 注意点:形状の一致、データ型、コピーと参照の違い
コメント