Pythonのリストと配列とnumpy.ndarrayの違いと使い分け

Modified: | Tags: Python, リスト, NumPy, pandas

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

リストの要素の追加や削除、その他の関連記事については以下を参照。

リストは先頭に要素を追加したり先頭の要素を削除するのが遅いという欠点があり、例えばキュー(queue, FIFO)として使うには効率的でない。先頭・末尾の要素の出し入れを効率的に行う型として標準ライブラリcollectionsモジュールにdeque型が用意されている。

なお、実際にリストがどのようなものかはPythonの実装によって異なる。リファレンス実装であるCPythonではポインタを要素とする動的配列(dynamic array)。連結リスト(linked list)ではない。

CPythonのリストは実際に変数分の長さの配列で、Lispスタイルの連結リストではありません。この実装は他のオブジェクトへの参照の連続した配列を使用していて、この配列へのポインタおよび配列長はリストの先頭の構造体に保存されています。
デザインと歴史 FAQ - CPythonでリストはどのように実装されているのですか? — Python 3.12.0 ドキュメント

Pythonにおける「リスト」は実装方法を表す名前ではなく、抽象データ型としての「リスト」を意味していると考えておけばよいだろう。

配列 - array

配列arrayの主な特徴は以下の通り。

コンストラクタ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の主な特徴は以下の通り。

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を生成する関数。ndN-dimensional(= N次元)の意味。

NumPy関連記事は以下から。

独断と偏見によるそれぞれの使い分け

いわゆる配列ライクな処理をするのであればリストlistで十分な場合が多い。

arrayは格納する要素の型が制限されているので厳密なメモリ管理が可能だが、特に気にする必要がなければlist、より効率的な数値計算を行いたければnumpy.ndarrayのほうが適当。メモリサイズ、メモリアドレスを必要とするような処理以外にあえてarrayを使う意味はない。

多次元配列を扱う場合や、配列に対する数値計算(科学技術演算)や行列演算を行う場合はNumPy配列numpy.ndarrayを使う。

コンピュータビジョンライブラリOpenCVや機械学習ライブラリscikit-learnなど多くのライブラリでNumPy配列numpy.ndarrayが使われているので、それらのライブラリを使うと自動的にnumpy.ndarrayを使うことになる。

なお、listnumpy.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だと非常に簡単。

詳しい使い方などは以下の記事を参照。

関連カテゴリー

関連記事