こんにちは、小澤です。
前回は、NumPyの有力な機能であるブロードキャストについてと、配列の掛け算について説明しました。今回は、NumPyにおける真偽値と比較、また、NumPy配列の関数とPythonリストのメソッドの違いについて説明していきましょう。教科書『Pythonによる新しいデータ分析の教科書(第2版)』の4.1.3章「NumPyの各機能」では130ページ〜134ページの部分です。
真偽値
NumPyには、配列の要素を一括でチェックして、その結果を真偽値(ブール値;True / False)として返す関数や演算子が提供されています。これによって、データのフィルタリングや分析を効率的に行うことができます。
NumPyの比較演算子を使うことで、要素ごとの判定結果を真偽値の配列として得ることができます。実際にサンプルコードを使って説明しましょう。
import numpy as np # 数値の配列を生成 a = np.array([0, 4, -5, 2]) # 各要素が3より大きいかどうかのブール配列を生成 bool_array = a > 3 print(bool_array) # => [False True False False] |
上記のコードは、array 関数を使って配列を作成し、その各要素に対して、> 演算子を使って、3より大きいかどうかの判定を行っているものです。この判定の結果は真偽値の配列として返されます。
また、以下のような2次元配列でも、各要素に対して判定を行います。
# 数値の配列を生成 b = np.array([[1, 2, 8], [4, 5, 3]]) # 各要素が3より大きいかどうかのブール配列を生成 bool_array = b > 3 print(bool_array) # => [[False False True] # [ True True False]] |
ここで、count_nonzero 関数を使うと、配列内の特定の条件を満たす要素の数を数えることができます。
np.count_nonzero(a > 3) # ⇒ 1 np.count_nonzero(b > 3) # ⇒ 3 |
count_nonzero 関数の代わりに、sum 関数を使っても、同じ結果を得ることができます。
np.sum(a > 3) # ⇒ 1 np.sum(b > 3) # ⇒ 3 |
any 関数と、all 関数は、配列の中にTrueが含まれているか、つまり、条件に一致する要素が存在するかを判定するものです。any 関数は、Trueとなる要素が1つでも含まれている場合にTrueを返し、all 関数は、すべての要素がTrueとなる場合にTrueを返します。逆に、any 関数は、すべての要素がFalseとなる場合にFalseを返し、all 関数は、Falseとなる要素が1つでも含まれている場合にFalseを返します。
np.any(a > 3) # ⇒ True np.all(a > 3) # ⇒ False |
配列から条件に一致するものだけを取得したい場合は、ブールインデクシングと呼ばれる操作が便利です。ブールインデクシングは、真偽値がTrueの位置にある要素だけを取り出します。
b[b > 3] # ⇒ array([8, 4, 5]) |
NumPyはブール演算子も提供しており、2つの真偽値の配列に対して論理演算(AND, OR, NOT)を行うことができます。
b = np.array([[1, 2, 8], [4, 5, 3]]) condition = np.logical_and(b > 2, b < 5) b[condition] # => array([4, 3]) condition = np.logical_or(b == 2, b == 5) b[condition] # => array([2, 5]) |
比較
NumPyでは、配列の要素同士の比較を行い、その結果を真偽値の配列として返すこともできます。
a = np.array([1, 2, 3, 4]) b = np.array([1, 3, 2, 4]) a == b # => [ True False False True] a != b # => [False True True False] a > b # => [False False True False] (a == b) | (a > b) # => [ True False True True] |
allclose 関数は、2つの配列の全要素が指定した許容誤差内で等しいかどうかをチェックするものです。これは、浮動小数点演算のように誤差が発生しやすい数値計算の結果の比較や、近似値を持つ配列同士の比較に非常に便利です。
a = np.array([1.0, 2.001, 3.0, 4.0]) b = np.array([1.0, 2.0, 3.0, 4.0]) np.allclose(a, b) # => False |
誤差の指定には相対誤差と絶対誤差があり、相対誤差はrtol、絶対誤差はatolで指定します。相対誤差は、誤差を基準値に対する割合で示すため、基準値が変動する状況や、誤差の相対的な大きさを比較する際に有効です。例えば、株価の変動や、異なる測定における誤差を比較する場合に使われます。一方、絶対誤差は、単純な誤差の大きさを知りたい場合に有効です。例えば、特定の距離や時間の誤差を測定する際に適しています。
allclose 関数では、相対誤差(rtol)のデフォルトは1e-05で、絶対誤差(atol)のデフォルトは1e-08です。上記の allclose 関数に絶対誤差として「10.0」という大きな数字を与えてみましょう。この場合は、2つの配列の各要素間の差が10以下である場合にTrueになります。
np.allclose(a, b, atol=10.0) # => True |
PythonのリストとNumPy配列の違い
NumPy配列の関数とPythonリストのメソッドにはいくつかの違いがあります。その違いについて説明します。
データ構造の違い
- Pythonリスト Pythonの組み込みデータ型で、任意の型の要素を持つことができます。例えば、整数、文字列、他のリストなど、異なる型の要素を混在させることができます。可変長で、要素の追加や削除が簡単にできます。
- NumPy配列 NumPyライブラリで提供されるデータ構造で、数値計算に特化しています。通常は同じ型の要素だけを持ちます。特に効率的な数値計算を行うため、要素の型を統一することが推奨されます。
戻り値の違い
- Pythonリストのメソッド Pythonリストには append(), extend(), remove(), sort(), reverse() などのメソッドがあります。これらはリストを直接変更します。
- NumPy配列の関数 NumPyには、配列に対する多くの操作関数が提供されています。例えば、np.sum(), np.mean(), np.dot() などがあります。これらの関数は配列の内容を変更せず、新しい結果を返します。
パフォーマンス
- Pythonリスト リストの操作は単純で使いやすいですが、大量のデータや複雑な数値計算を行う際のパフォーマンスは最適とは言えません。
- NumPy配列 NumPy配列は高速な数値計算に最適化されているので、大量のデータや行列演算などの計算を効率的に行えます。
数学的な操作
- Pythonリスト リストの要素同士で直接数学的な演算(加算、乗算など)を行うことはできません。リストの要素に対して繰り返しの処理をしながら逐一操作する必要があります。
- NumPy配列 数学的な演算を直接行うことができます。例えば、配列同士の加算や乗算を行うと、それぞれの要素に対して一括して演算が適用されます。
まとめ
今回は、NumPyにおける真偽値の扱いと比較、さらにはPythonのリストとNumPy配列の違いについて説明しました。
これまで5回にわたりNumPyの説明を行ってきましたが、範囲が広かったため、次回はこれまで説明した内容をふまえたNumPyの復習を予定しています。次回もぜひご期待ください。