Pythonのリストと配列とnumpy.ndarrayの違いと使い分け
Pythonには、組み込み型としてリストlist
、標準ライブラリに配列array
が用意されている。さらに数値計算ライブラリNumPyをインストールすると、多次元配列numpy.ndarray
を使うこともできる。
それぞれの違いと使い分けについて説明する。表(テーブル)で表現されるような二次元データを扱うのに便利なデータ分析ライブラリpandasについても最後に少し触れる。
リストと配列とnumpy.ndarrayの違い
リスト - list
リストlist
の主な特徴は以下の通り。
- 組み込み型であり、何も
import
せずに使える - 異なる型を格納できる
- リストのリストによって多次元配列を表現することも可能
- 狭義の配列とは異なるが、配列ライクな簡単な処理を行うのであればリスト
list
で十分な場合が多い
l = ['apple', 100, 0.123]
print(l)
# ['apple', 100, 0.123]
l_2d = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
print(l_2d)
# [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
要素を取り出すときは位置(インデックス)を[]
で指定する。0始まり。
print(l[1])
# 100
print(l_2d[1])
# [3, 4, 5]
print(l_2d[1][1])
# 4
スライス[:]
で複数指定(範囲指定)も可能。
print(l[:2])
# ['apple', 100]
組み込み関数のmax()
, min()
, sum()
, len()
を使って、最大値や最小値、合計、平均などを算出できる。len()
は要素数を返す関数。
l_num = [0, 10, 20, 30]
print(min(l_num))
# 0
print(max(l_num))
# 30
print(sum(l_num))
# 60
print(sum(l_num) / len(l_num))
# 15.0
for文によるループ処理の例。
l_str = ['apple', 'orange', 'banana']
for s in l_str:
print(s)
# apple
# orange
# banana
リストの要素の追加や削除、その他の関連記事については以下を参照。
- 関連記事: Pythonでリスト(配列)に要素を追加するappend, extend, insert
- 関連記事: Pythonでリスト(配列)の要素を削除するclear, pop, remove, del
- 関連記事: リスト関連記事
リストは先頭に要素を追加したり先頭の要素を削除するのが遅いという欠点があり、例えばキュー(queue, FIFO)として使うには効率的でない。先頭・末尾の要素の出し入れを効率的に行う型として標準ライブラリcollectionsモジュールにdeque
型が用意されている。
なお、実際にリストがどのようなものかはPythonの実装によって異なる。リファレンス実装であるCPythonではポインタを要素とする動的配列(dynamic array)。連結リスト(linked list)ではない。
CPythonのリストは実際に変数分の長さの配列で、Lispスタイルの連結リストではありません。この実装は他のオブジェクトへの参照の連続した配列を使用していて、この配列へのポインタおよび配列長はリストの先頭の構造体に保存されています。
デザインと歴史 FAQ - CPythonでリストはどのように実装されているのですか? — Python 3.12.0 ドキュメント
Pythonにおける「リスト」は実装方法を表す名前ではなく、抽象データ型としての「リスト」を意味していると考えておけばよいだろう。
- リスト (抽象データ型) - Wikipedia
- Why are Python Lists called 'lists' when they are implemented as dynamic arrays - Stack Overflow
配列 - array
配列array
の主な特徴は以下の通り。
- 標準ライブラリの
array
モジュールをimport
して使う- array --- 効率のよい数値アレイ — Python 3.12.0 ドキュメント
- 標準ライブラリなのでインストールは不要
- 同じ型しか格納できない
- 一次元配列のみ
- 型に制限がある以外はリストと同様の処理が可能
コンストラクタarray.array()
で型コードを指定して生成する。型コードの一覧は公式ドキュメント参照。
型コードと一致しない型の要素は格納できずエラーになる。
import array
arr_int = array.array('i', [0, 1, 2])
print(arr_int)
# array('i', [0, 1, 2])
arr_float = array.array('f', [0.0, 0.25, 0.5])
print(arr_float)
# array('f', [0.0, 0.25, 0.5])
# arr_int = array.array('i', [0, 0.5, 1])
# TypeError: 'float' object cannot be interpreted as an integer
リストと同様の処理が可能。
print(arr_int[1])
# 1
print(sum(arr_int))
# 3
多次元配列 - numpy.ndarray
NumPyの多次元配列numpy.ndarray
の主な特徴は以下の通り。
- NumPyをインストール、
import
して使う - 同じ型しか格納できない
object
型で異なる型へのポインタを格納することはできる
- 多次元配列を表現できる
- 数値計算のためのメソッド・関数が豊富で、高速な演算が可能
- 行列演算や画像処理など様々な場面で使える
import numpy as np
arr = np.array([0, 1, 2])
print(arr)
# [0 1 2]
arr_2d = np.array([[0, 1, 2], [3, 4, 5]])
print(arr_2d)
# [[0 1 2]
# [3 4 5]]
多次元配列の場合はカンマ区切りで位置(インデックス)を指定する。スライスも使用可能。
print(arr[1])
# 1
print(arr_2d[1, 1])
# 4
print(arr_2d[0, 1:])
# [1 2]
要素ごとに演算をしたり(例は平方根)、行列積を求めたりできる。
print(np.sqrt(arr_2d))
# [[0. 1. 1.41421356]
# [1.73205081 2. 2.23606798]]
arr_1 = np.array([[1, 2], [3, 4]])
arr_2 = np.array([[1, 2, 3], [4, 5, 6]])
print(np.dot(arr_1, arr_2))
# [[ 9 12 15]
# [19 26 33]]
なぜか混同されることが多いが、array
型ではなくndarray
型。numpy.array()
はndarray
を生成する関数。nd
はN-dimensional
(= N次元)の意味。
NumPy関連記事は以下から。
- 関連記事: NumPy関連記事まとめ
独断と偏見によるそれぞれの使い分け
いわゆる配列ライクな処理をするのであればリストlist
で十分な場合が多い。
array
は格納する要素の型が制限されているので厳密なメモリ管理が可能だが、特に気にする必要がなければlist
、より効率的な数値計算を行いたければnumpy.ndarray
のほうが適当。メモリサイズ、メモリアドレスを必要とするような処理以外にあえてarray
を使う意味はない。
多次元配列を扱う場合や、配列に対する数値計算(科学技術演算)や行列演算を行う場合はNumPy配列numpy.ndarray
を使う。
コンピュータビジョンライブラリOpenCVや機械学習ライブラリscikit-learnなど多くのライブラリでNumPy配列numpy.ndarray
が使われているので、それらのライブラリを使うと自動的にnumpy.ndarray
を使うことになる。
なお、list
とnumpy.ndarray
は相互に変換する事が可能。以下の記事を参照。
データ分析ライブラリpandas
表(テーブル)で表現されるような二次元データに対して統計的な処理を行う場合は、データ分析ライブラリpandasが便利。
pandasでは二次元データをpandas.DataFrame
として扱う。pandas.Series
として一次元データを扱うことも可能。
pandas.DataFrame
では、行・列ごとの操作や表計算ソフトにおけるピボットテーブルのような操作など、データ処理に便利な関数やメソッドが豊富に用意されている。
列ごとの平均値を算出したり、属性を指定して集計したりする例を示す。
import pandas as pd
df = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=0)
df['sex'] = ['Female', 'Male', 'Male', 'Male', 'Female', 'Male']
print(df)
# age state point sex
# name
# Alice 24 NY 64 Female
# Bob 42 CA 92 Male
# Charlie 18 CA 70 Male
# Dave 68 TX 70 Male
# Ellen 24 CA 88 Female
# Frank 30 NY 57 Male
print(df.mean(numeric_only=True))
# age 34.333333
# point 73.500000
# dtype: float64
print(df.pivot_table(index='state', columns='sex', aggfunc='mean'))
# age point
# sex Female Male Female Male
# state
# CA 24.0 30.0 88.0 81.0
# NY 24.0 30.0 64.0 57.0
# TX NaN 68.0 NaN 70.0
この例のような数値と文字列を含んだデータはNumPyだと扱いが面倒だが、pandasだと非常に簡単。
詳しい使い方などは以下の記事を参照。