Pythonリスト・配列・numpy.ndarrayの違い完全解説:特徴と使い分けガイド

 

はじめに

Pythonでデータを扱う際、「リスト」「配列」「numpy.ndarray」という3つの概念があり、初心者にとって混乱しやすいポイントです。それぞれ異なる特徴と用途があるため、適切に使い分けることで効率的なプログラミングが可能になります。この記事では、これらの違いを詳しく解説し、実践的な使い分け方法を紹介します。

1. Pythonリスト(list)

基本的な特徴

Pythonの組み込みデータ型で、最も基本的なコンテナです。

# リストの作成
my_list = [1, 2, 3, 4, 5]
mixed_list = [1, "hello", 3.14, True]
print(type(my_list))  # <class 'list'>

主な特徴

  • 異なる型の要素を格納可能
  • 動的サイズ変更
  • 豊富な組み込みメソッド
  • メモリ使用量が多い
# 要素の追加・削除
numbers = [1, 2, 3]
numbers.append(4)
numbers.insert(0, 0)
numbers.remove(2)
print(numbers)  # [0, 1, 3, 4]

リストの操作例

# スライシング
data = [1, 2, 3, 4, 5]
print(data[1:4])  # [2, 3, 4]

# リスト内包表記
squares = [x**2 for x in range(5)]
print(squares)  # [0, 1, 4, 9, 16]

# 結合
list1 = [1, 2]
list2 = [3, 4]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4]

2. array.array(配列)

基本的な特徴

Pythonのarrayモジュールで提供される、同じ型の要素のみを格納するデータ構造です。

import array

# 整数配列の作成
int_array = array.array('i', [1, 2, 3, 4, 5])
float_array = array.array('f', [1.0, 2.0, 3.0])
print(type(int_array))  # <class 'array.array'>

型コードの例

# よく使用される型コード
byte_array = array.array('b', [1, 2, 3])     # 符号付き1バイト整数
int_array = array.array('i', [1, 2, 3])      # 符号付き整数
long_array = array.array('l', [1, 2, 3])     # 符号付き長整数
float_array = array.array('f', [1.0, 2.0])   # 単精度浮動小数点
double_array = array.array('d', [1.0, 2.0])  # 倍精度浮動小数点

配列の操作例

import array

# 配列の作成と操作
arr = array.array('i', [1, 2, 3])
arr.append(4)
arr.extend([5, 6])
print(arr.tolist())  # [1, 2, 3, 4, 5, 6]

# ファイルへの書き込み・読み込み
with open('data.bin', 'wb') as f:
    arr.tofile(f)

3. numpy.ndarray

基本的な特徴

NumPyライブラリで提供される、科学計算に特化した多次元配列です。

import numpy as np

# ndarrayの作成
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([[1, 2], [3, 4]])
print(type(arr1))  # <class 'numpy.ndarray'>

多次元配列の作成

import numpy as np

# 1次元配列
arr_1d = np.array([1, 2, 3])

# 2次元配列
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])

# 3次元配列
arr_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

print(f"1D shape: {arr_1d.shape}")  # (3,)
print(f"2D shape: {arr_2d.shape}")  # (2, 3)
print(f"3D shape: {arr_3d.shape}")  # (2, 2, 2)

便利な生成関数

import numpy as np

# ゼロ配列
zeros = np.zeros((3, 4))

# 1で埋められた配列
ones = np.ones((2, 3))

# 等差数列
range_arr = np.arange(0, 10, 2)  # [0, 2, 4, 6, 8]

# 等間隔の値
linspace_arr = np.linspace(0, 1, 5)  # [0. 0.25 0.5 0.75 1.]

# 単位行列
identity = np.eye(3)

詳細比較表

特徴 list array.array numpy.ndarray
データ型 混在可能 同一型のみ 同一型のみ
メモリ効率 低い 中程度 高い
計算速度 遅い 中程度 高速
多次元
数学演算 限定的 限定的 豊富
外部ライブラリ 不要 不要 NumPy必要

パフォーマンス比較

メモリ使用量の比較

import sys
import array
import numpy as np

# 同じデータでのメモリ使用量比較
data = list(range(1000))

python_list = data
array_obj = array.array('i', data)
numpy_array = np.array(data)

print(f"List size: {sys.getsizeof(python_list)} bytes")
print(f"Array size: {sys.getsizeof(array_obj)} bytes")  
print(f"NumPy size: {numpy_array.nbytes} bytes")

計算速度の比較

import time
import numpy as np

# 大きなデータセットでの計算比較
size = 1000000

# Python リスト
start = time.time()
list_data = list(range(size))
list_squared = [x**2 for x in list_data]
list_time = time.time() - start

# NumPy配列
start = time.time()
numpy_data = np.arange(size)
numpy_squared = numpy_data**2
numpy_time = time.time() - start

print(f"List time: {list_time:.4f}s")
print(f"NumPy time: {numpy_time:.4f}s")
print(f"Speed up: {list_time/numpy_time:.1f}x")

実践的な使い分け

1. データ収集・前処理段階

# 異なる型のデータを扱う場合はリスト
mixed_data = []
mixed_data.append("user_001")
mixed_data.append(25)
mixed_data.append(True)

2. 数値計算・科学計算

import numpy as np

# 行列計算
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
result = np.dot(matrix_a, matrix_b)
print(result)

3. ファイル入出力

import array

# バイナリデータの効率的な処理
sensor_data = array.array('f', [23.5, 24.1, 23.8, 24.3])
with open('sensor.dat', 'wb') as f:
    sensor_data.tofile(f)

変換方法

リスト ↔ array.array

import array

# リスト → array
my_list = [1, 2, 3, 4, 5]
my_array = array.array('i', my_list)

# array → リスト
back_to_list = my_array.tolist()

リスト ↔ numpy.ndarray

import numpy as np

# リスト → numpy
my_list = [1, 2, 3, 4, 5]
numpy_arr = np.array(my_list)

# numpy → リスト
back_to_list = numpy_arr.tolist()

array.array ↔ numpy.ndarray

import array
import numpy as np

# array → numpy
my_array = array.array('i', [1, 2, 3])
numpy_arr = np.frombuffer(my_array, dtype=np.int32)

# numpy → array
numpy_arr = np.array([1, 2, 3], dtype=np.int32)
my_array = array.array('i', numpy_arr)

具体的な使用例

1. データ分析での使い分け

import numpy as np
import array

# 生データ(リスト)
raw_data = ["temperature", 23.5, 24.1, 23.8, 24.3]

# 数値部分のみ抽出(array)
numeric_data = array.array('f', raw_data[1:])

# 統計計算(numpy)
temp_array = np.array(numeric_data)
average = np.mean(temp_array)
std_dev = np.std(temp_array)

2. 画像処理での例

import numpy as np

# 画像データ(numpy配列として扱う)
image = np.zeros((100, 100, 3), dtype=np.uint8)  # RGB画像

# ピクセル操作
image[25:75, 25:75, 0] = 255  # 赤い四角形

# 画像の平均輝度
brightness = np.mean(image)

3. センサーデータの処理

import array
import numpy as np

# センサーから取得した生データ(効率的な格納)
sensor_readings = array.array('f')
for i in range(1000):
    sensor_readings.append(20.0 + i * 0.01)

# 統計分析のためにnumpy配列に変換
data_analysis = np.array(sensor_readings)
trend = np.polyfit(range(len(data_analysis)), data_analysis, 1)

よくある間違いと対策

1. 型の混在エラー

import numpy as np

# 間違い:異なる型を混在
# arr = np.array([1, "hello", 3.14])  # 文字列に統一される

# 正解:同じ型で統一
arr = np.array([1, 2, 3])  # 整数
str_arr = np.array(["hello", "world"])  # 文字列

2. メモリ効率を考慮しない選択

# 大量の数値データの場合
# 非効率:リスト
large_list = [i for i in range(1000000)]

# 効率的:numpy配列
large_array = np.arange(1000000)

3. 不適切な計算方法

import numpy as np

# 非効率:ループでの計算
result = []
for x in [1, 2, 3, 4, 5]:
    result.append(x ** 2)

# 効率的:ベクトル化された計算
arr = np.array([1, 2, 3, 4, 5])
result = arr ** 2

選択基準のフローチャート

データの性質は?
├─ 異なる型が混在
│  └─ Python list
├─ 同じ型の数値のみ
│  ├─ 単純な格納・読み書き → array.array
│  ├─ 数学的計算が必要 → numpy.ndarray
│  └─ 多次元データ → numpy.ndarray
└─ 計算速度が重要 → numpy.ndarray

まとめ

Python list:

  • 異なる型のデータを格納
  • 動的なサイズ変更
  • 一般的なデータ処理に最適

array.array:

  • 同じ型の数値データ
  • メモリ効率が良い
  • ファイル入出力に便利

numpy.ndarray:

  • 科学計算・数値計算
  • 高速な演算処理
  • 多次元データ処理

使い分けの原則:

  1. データ収集段階 → list
  2. 効率的な格納 → array.array
  3. 数値計算・分析 → numpy.ndarray

適切な選択により、メモリ効率と実行速度の両方を最適化できます。プロジェクトの要件に応じて、最適なデータ構造を選択することが重要です。

関連記事

  • NumPy配列操作の基本ガイド
  • Pythonリスト内包表記の活用法
  • データ分析のためのPandas入門

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座