NumPy配列ndarrayの論理・ビット演算(AND, OR, XOR, NOT, シフト)
NumPy配列ndarray
の要素ごとの論理演算(ブール演算)およびビット演算には&
(AND, 論理積)、|
(OR, 論理和)、^
(XOR, 排他的論理和)、~
(NOT, 否定・反転)、<<
, >>
(ビットシフト)の各演算子を用いる。
ここでは以下の内容について説明する。
and
,or
,not
と&
,|
,~
の違い- NumPy配列
ndarray
の要素ごとの論理演算(ブール演算)&
,|
,^
,~
演算子logical_and()
,logical_or()
,logical_xor()
,logical_not()
関数- ブロードキャスト
- 条件式を用いる場合の注意点
- NumPy配列
ndarray
の要素ごとのビット演算&
,|
,^
,~
,<<
,>>
演算子bitwise_and()
,bitwise_or()
,bitwise_xor()
,bitwise_not()
,invert()
関数- 反転(
~
,bitwise_not()
,invert()
)の注意点 - ブロードキャスト
- 浮動小数点数
float
やブールbool
の場合
and, or, notと&, |, ~の違い
Pythonでは、オブジェクトの論理演算(ブール演算)にはand
, or
, not
演算子、整数のビット演算(二進数で表した各ビットに対する論理演算)などには&
, |
, ~
演算子を使う。
NumPy配列ndarray
の要素ごとの処理には、いずれも&
, |
, ~
演算子を使う。
以降のサンプルコードで示すように、データ型dtype
がブールbool
であれば要素ごとの論理演算となり、整数int
であれば要素ごとのビット演算となる。
要素数が1個でないNumPy配列ndarray
に対してand
, or
, not
演算子を使うとエラーになるので注意。以降の説明でも簡単に触れるが、要素数が1個の場合など、より詳細は以下の記事を参照。
NumPy配列ndarrayの要素ごとの論理演算(ブール演算)
以下のnumpy.ndarray
を例とする。データ型dtype
はブールbool
。
import numpy as np
print(np.__version__)
# 1.17.3
a_bool = np.array([True, True, False, False])
b_bool = np.array([True, False, True, False])
print(a_bool.dtype)
# bool
print(b_bool.dtype)
# bool
&, |, ^, ~演算子
&
, |
, ^
, ~
演算子で、要素ごとのAND(論理積)、OR(論理和)、XOR(排他的論理和)、NOT(否定)を算出できる。
print(a_bool & b_bool)
# [ True False False False]
print(a_bool | b_bool)
# [ True True True False]
print(a_bool ^ b_bool)
# [False True True False]
print(~a_bool)
# [False False True True]
結果もデータ型dtype
がブールbool
のnumpy.ndarray
となる。
print(type(a_bool & b_bool))
# <class 'numpy.ndarray'>
print((a_bool & b_bool).dtype)
# bool
要素数が1個でない場合、and
, or
, not
はエラーとなる。
# print(a_bool and b_bool)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
詳細は以下の記事を参照。
logical_and(), logical_or(), logical_xor(), logical_not()関数
要素ごとのAND(論理積)、OR(論理和)、XOR(排他的論理和)、NOT(否定)はlogical_and()
, logical_or()
, logical_xor()
, logical_not()
関数でも算出可能。
- numpy.logical_and — NumPy v1.18 Manual
- numpy.logical_or — NumPy v1.18 Manual
- numpy.logical_xor — NumPy v1.18 Manual
- numpy.logical_not — NumPy v1.18 Manual
print(np.logical_and(a_bool, b_bool))
# [ True False False False]
print(np.logical_or(a_bool, b_bool))
# [ True True True False]
print(np.logical_xor(a_bool, b_bool))
# [False True True False]
print(np.logical_not(a_bool))
# [False False True True]
データ型dtype
がブールbool
以外のnumpy.ndarray
は、まず各要素がブールとして判定されてから処理される。
例えば整数int
や浮動小数点数float
では、0
および0.0
がFalse
でそれ以外はTrue
と判定される。
c_int = np.arange(4)
print(c_int)
# [0 1 2 3]
print(np.logical_not(c_int))
# [ True False False False]
d_int = c_int + 4
print(d_int)
# [4 5 6 7]
print(np.logical_not(d_int))
# [False False False False]
logical_and()
やlogical_or()
などでは各要素がブールとして判定されてから処理されるのに対し、後述のように整数int
のnumpy.ndarray
に対する&
や|
などはビット演算となるため、結果が異なる。要注意。
print(np.logical_and(c_int, d_int))
# [False True True True]
print(c_int & d_int)
# [0 1 2 3]
ブロードキャスト
+
, -
のような演算子と同様に、&
, |
, ^
演算子やlogical_and()
, logical_or()
, logical_xor()
でもブロードキャストが行われ、次元の異なるnumpy.ndarray
が自動的に形状変換される。
- 関連記事: NumPyのブロードキャスト(形状の自動変換)
a_bool_2d = np.array([[True, True, False, False], [False, False, True, True]])
print(a_bool_2d)
# [[ True True False False]
# [False False True True]]
print(a_bool_2d & b_bool)
# [[ True False False False]
# [False False True False]]
print(np.logical_and(a_bool_2d, a_bool))
# [[ True True False False]
# [False False False False]]
各要素とスカラー値を処理することも可能。
print(a_bool & True)
# [ True True False False]
print(np.logical_and(a_bool, True))
# [ True True False False]
条件式を用いる場合の注意点
numpy.ndarray
に対して<
や==
などの比較演算子を用いると、各要素がそれぞれ判定され、データ型dtype
がブールbool
のnumpy.ndarray
が返される。
print(c_int)
# [0 1 2 3]
print(c_int < 2)
# [ True True False False]
print(c_int % 2 == 0)
# [ True False True False]
この結果に対して&
, |
, ^
, ~
演算子を使う場合、各条件式を括弧()
で囲む必要がある。括弧が無いとエラーになるので注意。
print((c_int < 2) & (c_int % 2 == 0))
# [ True False False False]
# print(c_int < 2 & c_int % 2 == 0)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
これは、&
, |
, ^
, ~
演算子は比較演算子(<
など)よりも優先順位が高いため。
括弧がないと以下のように処理されてしまう。
# print(c_int < (2 & (c_int % 2)) == 0)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
logical_and()
などでは引数ごとに扱われるため、当然ながら特に括弧は必要ない。
print(np.logical_and(c_int < 2, c_int % 2 == 0))
# [ True False False False]
NumPy配列ndarrayの要素ごとのビット演算
以下のnumpy.ndarray
を例とする。データ型dtype
は整数int
。
import numpy as np
print(np.__version__)
# 1.17.3
a_int = np.array([0, 1, 3]) # [0b00 0b01 0b11]
b_int = np.array([1, 0, 2]) # [0b01 0b00 0b10]
print(a_int.dtype)
# int64
print(b_int.dtype)
# int64
&, |, ^, ~, <<, >>演算子
&
, |
, ^
, ~
, <<
, >>
演算子で、要素ごとのビット単位のAND(論理積)、OR(論理和)、XOR(排他的論理和)、NOT(反転)、左シフト、右シフトを算出できる。
print(a_int & b_int)
# [0 0 2]
print(a_int | b_int)
# [1 1 3]
print(a_int ^ b_int)
# [1 1 1]
print(~a_int)
# [-1 -2 -4]
print(a_int << b_int)
# [ 0 1 12]
print(a_int >> b_int)
# [0 1 0]
反転の結果については後述。
bitwise_and(), bitwise_or(), bitwise_xor(), bitwise_not(), invert()
要素ごとのビット単位のAND(論理積)、OR(論理和)、XOR(排他的論理和)、NOT(反転)はbitwise_and()
, bitwise_or()
, bitwise_xor()
, bitwise_not()
, invert()
関数でも算出可能。
- numpy.bitwise_and — NumPy v1.18 Manual
- numpy.bitwise_or — NumPy v1.18 Manual
- numpy.bitwise_xor — NumPy v1.18 Manual
- numpy.invert — NumPy v1.18 Manual
bitwise_not()
はinvert()
のエイリアスなのでどちらを使っても同じ。
print(np.bitwise_and(a_int, b_int))
# [0 0 2]
print(np.bitwise_or(a_int, b_int))
# [1 1 3]
print(np.bitwise_xor(a_int, b_int))
# [1 1 1]
print(np.bitwise_not(a_int))
# [-1 -2 -4]
print(np.invert(a_int))
# [-1 -2 -4]
反転(~, bitwise_not(), invert())の注意点
符号あり整数の場合、~x
やbitwise_not(x)
, invert(x)
は-(x + 1)
となる値を返す。Pythonにおける~
の挙動と同じく、負の値を表現するための2の補数形式を考慮した結果となる。
print(~a_int)
# [-1 -2 -4]
print(-(a_int + 1))
# [-1 -2 -4]
符号なし整数uint
の場合、単純にビット反転した結果となる。データ型dtype
のビット数によって結果が異なるので注意。
a_uint8 = np.array([0, 1, 3], dtype=np.uint8)
print(~a_uint8)
# [255 254 252]
a_uint16 = np.array([0, 1, 3], dtype=np.uint16)
print(~a_uint16)
# [65535 65534 65532]
bitwise_not()
, invert()
の例は省略するが、~
と同様。
ブロードキャスト
+
, -
のような演算子と同様に、&
, |
, ^
, <<
, >>
演算子やbitwise_and()
, bitwise_or()
, bitwise_xor()
でもブロードキャストが行われ、次元の異なるnumpy.ndarray
が自動的に形状変換される。
- 関連記事: NumPyのブロードキャスト(形状の自動変換)
c_int_2d = np.arange(6).reshape(2, 3)
print(c_int_2d)
# [[0 1 2]
# [3 4 5]]
print(c_int_2d & a_int)
# [[0 1 2]
# [0 0 1]]
print(np.bitwise_and(c_int_2d, a_int))
# [[0 1 2]
# [0 0 1]]
各要素とスカラー値を処理することも可能。
print(c_int_2d & 2)
# [[0 0 2]
# [2 0 0]]
print(np.bitwise_and(c_int_2d, 2))
# [[0 0 2]
# [2 0 0]]
浮動小数点数floatやブールboolの場合
ビット演算を行う演算子や関数は浮動小数点数float
には対応していないので、エラーとなる。
d_float = np.array([0, 1, 3], dtype=float)
# print(a_int & d_float)
# TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
# print(~d_float)
# TypeError: ufunc 'invert' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
# print(np.bitwise_and(a_int, d_float))
# TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
# print(np.bitwise_not(d_float))
# TypeError: ufunc 'invert' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
上述の通り、データ型dtype
がブールbool
同士の&
や|
は要素ごとの論理演算となり、結果もbool
となる。
ブールbool
と整数int
のnumpy.ndarray
を&
やbitwise_and
で処理すると、True
が1
、False
が0
としてビット演算が行われる。結果はint
となる。
e_bool = np.array([True, False, True])
print(a_int & e_bool)
# [0 0 1]
print((a_int & e_bool).dtype)
# int64
print(np.bitwise_and(a_int, e_bool))
# [0 0 1]
print(np.bitwise_and(a_int, e_bool).dtype)
# int64
なお、bitwise_not()
, invert()
では、bool
を渡すとbool
が返される。
print(~e_bool)
# [False True False]
print(np.logical_not(e_bool))
# [False True False]
print(np.bitwise_not(e_bool))
# [False True False]
print(np.invert(e_bool))
# [False True False]