【完全入門】Python NumPy配列の使い方|基礎から応用まで分かりやすく解説!

python

「データ処理や数値計算をもっと効率的にやりたい」
「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()  # コピー(独立したデータ)

よくある質問

Q
NumPy配列とPythonリスト、どちらを使えば良い?
A

数値計算やデータ処理が主目的ならNumPy配列、汎用的なデータ管理ならリストがおすすめです。

Q
多次元配列のインデックスがわからなくなる
A

array.shapeで形状を確認し、array[行, 列]の順序を意識しましょう。

Q
メモリ不足エラーが出る
A

大きな配列を作成する場合は、データ型をfloat32int32にしてメモリ使用量を削減できます。

# メモリ効率の良いデータ型
large_array = np.zeros((10000, 10000), dtype=np.float32)  # float64より半分のメモリ
Q
Noneや欠損値はどう扱う?
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を除いた平均
Q
NumPy配列をファイルに保存したい
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、結合など柔軟な操作
  • 計算機能:要素ごとの演算、統計処理、線形代数が簡潔に記述可能
  • 注意点:形状の一致、データ型、コピーと参照の違い

コメント

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