NumPy配列ndarrayの符号(正負)を取得・判定・置換
NumPy配列numpy.ndarray
の符号(正負、プラス・マイナス)に関する処理について、以下の内容を説明する。
- NumPy配列
ndarray
の符号を取得:np.sign()
- 基本的な使い方
- 負のゼロや無限大
inf
、欠損値nan
の場合 - 複素数の場合
- NumPy配列
ndarray
の符号を判定:np.signbit()
- 基本的な使い方
- 比較演算子で判定
- 符号ごとに要素数をカウント
- 負のゼロや無限大
inf
、欠損値nan
の場合 - 複素数の場合
- NumPy配列
ndarray
の符号を別の配列のものに置換:np.copysign()
- 基本的な使い方
- ブロードキャスト
- 負のゼロや無限大
inf
、欠損値nan
の場合 - 複素数の場合
NumPyを使わずにsign()
やcopysign()
の処理を行いたい場合は以下の記事を参照。
NumPy配列ndarrayの符号を取得: np.sign()
numpy.sign()
関数でnumpy.ndarray
の符号を取得できる。
基本的な使い方
numpy.sign()
の引数にnumpy.ndarray
を指定する。負の値は-1
、正の値は1
、0
は0
となるnumpy.ndarray
が返される。
import numpy as np
a = np.array([-100, -10, 0, 10, 100])
print(a)
# [-100 -10 0 10 100]
print(np.sign(a))
# [-1 -1 0 1 1]
print(type(np.sign(a)))
# <class 'numpy.ndarray'>
print(np.sign(a).dtype)
# int64
データ型dtype
は元のnumpy.ndarray
と同じ。浮動小数点数float
の場合はfloat
。
a_float = np.array([-1.23, 0.0, 1.23])
print(a_float)
# [-1.23 0. 1.23]
print(np.sign(a_float))
# [-1. 0. 1.]
print(np.sign(a_float).dtype)
# float64
スカラー値に対してはスカラー値を返す。この場合も元の型と同じ型となる。
print(np.sign(100))
# 1
print(type(np.sign(100)))
# <class 'numpy.int64'>
print(np.sign(-1.23))
# -1.0
print(type(np.sign(-1.23)))
# <class 'numpy.float64'>
負のゼロや無限大inf、欠損値nanの場合
浮動小数点数float
では負のゼロ(= -0.0
)を表現できる。整数int
のゼロには正負はない。
numpy.sign()
は正負いずれの0.0
に対しても0.0
を返す。
無限大inf
はその符号、欠損値nan
はnan
となる。np.inf
やnp.nan
は浮動小数点数float
なので返り値もfloat
。
a_special = np.array([0.0, -0.0, np.inf, -np.inf, np.nan])
print(a_special)
# [ 0. -0. inf -inf nan]
print(np.sign(a_special))
# [ 0. 0. 1. -1. nan]
print(np.sign(a_special).dtype)
# float64
複素数の場合
複素数の場合、実部が0
でなければ実部の符号、実部が0
の場合は虚部の符号が返される。返り値はすべて虚部が0
の複素数。0
, nan
も実部が0
, nan
で虚部が0
の複素数となる。
a_complex = np.array([[10 + 10j, -10 + 10j], [10 - 10j, -10 - 10j], [10, -10], [10j, -10j], [0, np.nan], [0j, np.nan * 1j]])
print(a_complex)
# [[ 10.+10.j -10.+10.j]
# [ 10.-10.j -10.-10.j]
# [ 10. +0.j -10. +0.j]
# [ 0.+10.j -0.-10.j]
# [ 0. +0.j nan +0.j]
# [ 0. +0.j nan+nanj]]
print(np.sign(a_complex))
# [[ 1.+0.j -1.+0.j]
# [ 1.+0.j -1.+0.j]
# [ 1.+0.j -1.+0.j]
# [ 1.+0.j -1.+0.j]
# [ 0.+0.j nan+0.j]
# [ 0.+0.j nan+0.j]]
実部、虚部それぞれの符号を取得したい場合はreal
, imag
属性を使う。
print(a_complex.real)
# [[ 10. -10.]
# [ 10. -10.]
# [ 10. -10.]
# [ 0. -0.]
# [ 0. nan]
# [ 0. nan]]
print(np.sign(a_complex.real))
# [[ 1. -1.]
# [ 1. -1.]
# [ 1. -1.]
# [ 0. 0.]
# [ 0. nan]
# [ 0. nan]]
print(a_complex.imag)
# [[ 10. 10.]
# [-10. -10.]
# [ 0. 0.]
# [ 10. -10.]
# [ 0. 0.]
# [ 0. nan]]
print(np.sign(a_complex.imag))
# [[ 1. 1.]
# [-1. -1.]
# [ 0. 0.]
# [ 1. -1.]
# [ 0. 0.]
# [ 0. nan]]
NumPy配列ndarrayの符号を判定: np.signbit()
numpy.signbit()
関数でnumpy.ndarray
の符号を判定できる。名前の通り、符号ビット(sign bit)をブール値で返す。負の値がTrue
、0
および正の値がFalse
となる。
後述のように、比較演算子を使っても同様の処理が可能。
基本的な使い方
numpy.signbit()
の引数にnumpy.ndarray
を指定する。負の値がTrue
、0
および正の値がFalse
となるnumpy.ndarray
が返される。
a = np.array([-100, -10, 0, 10, 100])
print(a)
# [-100 -10 0 10 100]
print(np.signbit(a))
# [ True True False False False]
print(type(np.signbit(a)))
# <class 'numpy.ndarray'>
print(np.signbit(a).dtype)
# bool
スカラー値に対してはスカラー値を返す。
print(np.signbit(-100))
# True
比較演算子で判定
同様の処理は比較演算子を使ってもできる。
print(a == 0)
# [False False True False False]
print(a > 0)
# [False False False True True]
print(a >= 0)
# [False False True True True]
print(a < 0)
# [ True True False False False]
print(a <= 0)
# [ True True True False False]
符号ごとに要素数をカウント
numpy.count_nonzero()
関数の引数にbool
を要素とするnumpy.ndarray
を指定するとTrue
の数をカウントできる。sum()
でもよい。
したがって、numpy.signbit()
の結果をnumpy.count_nonzero()
の引数に指定すると、True
、すなわち、負の値の数をカウントできる。
print(np.count_nonzero(np.signbit(a)))
# 2
~
でbool
値の各要素の否定も可能。False
、すなわち、0
および正の値の数をカウントできる。
print(~np.signbit(a))
# [False False True True True]
print(np.count_nonzero(~np.signbit(a)))
# 3
比較演算子を使っても同様の処理が可能。
print(np.count_nonzero(a == 0))
# 1
print(np.count_nonzero(a < 0))
# 2
print(np.count_nonzero(a > 0))
# 2
負のゼロや無限大inf、欠損値nanの場合
numpy.signbit()
では、浮動小数点数float
のゼロおよび無限大inf
はその符号を元に判定され、欠損値nan
はFalse
となる。
a_special = np.array([0.0, -0.0, np.inf, -np.inf, np.nan])
print(a_special)
# [ 0. -0. inf -inf nan]
print(np.signbit(a_special))
# [False True False True False]
0
との比較演算の結果は以下の通り。
print(a_special == 0)
# [ True True False False False]
print(a_special < 0)
# [False False False True False]
#
# /usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in less
# """Entry point for launching an IPython kernel.
print(a_special > 0)
# [False False True False False]
#
# /usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in greater
# """Entry point for launching an IPython kernel.
正負いずれの0
も0
と等価とみなされる。また、欠損値nan
はすべての比較演算に対してFalse
となる。
環境によっては、上の例のように、要素数が2個以上で欠損値nan
を含むnumpy.ndarray
の比較演算に対して警告が出る場合がある。エラーではないので処理は中断されない。
複素数の場合
複素数を要素とするnumpy.ndarray
はnumpy.signbit()
の対象外。エラーとなる。
a_complex = np.array([3 + 4j, -3 - 4j])
print(a_complex)
# [ 3.+4.j -3.-4.j]
# print(np.signbit(a_complex))
# TypeError: ufunc 'signbit' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
np.abs()
で絶対値、real
, imag
属性で実部・虚部を取得できる。それらに対する処理はもちろん可能。
print(np.abs(a_complex))
# [5. 5.]
print(a_complex.real)
# [ 3. -3.]
print(a_complex.imag)
# [ 4. -4.]
print(np.signbit(a_complex.real))
# [False True]
print(a_complex.real < 0)
# [False True]
NumPy配列ndarrayの符号を別の配列のものに置換: np.copysign()
numpy.copysign()
で、あるnumpy.ndarray
の符号を別のnumpy.ndarray
のものに置き換えることができる。
基本的な使い方
第一引数、第二引数にそれぞれnumpy.ndarray
を指定する。
第一引数の符号が第二引数の符号に置き換えられる。引数のデータ型によらず、返り値のデータ型は常に浮動小数点数float
。
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
b = np.arange(-5, 7).reshape(3, 4)
print(b)
# [[-5 -4 -3 -2]
# [-1 0 1 2]
# [ 3 4 5 6]]
a_copysign = np.copysign(a, b)
print(a_copysign)
# [[-0. -1. -2. -3.]
# [-4. 5. 6. 7.]
# [ 8. 9. 10. 11.]]
print(a_copysign.dtype)
# float64
スカラー値でもOK。この場合もfloat
が返される。
print(np.copysign(10, -5))
# -10.0
print(type(np.copysign(10, -5)))
# <class 'numpy.float64'>
ブロードキャスト
形状shape
が異なるnumpy.ndarray
同士の演算では、可能な場合はブロードキャストによって形状が揃えられる。
- 関連記事: NumPyのブロードキャスト(形状の自動変換)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
b_small = np.array([-100, -100, 100, 100])
print(b_small)
# [-100 -100 100 100]
print(a + b_small)
# [[-100 -99 102 103]
# [ -96 -95 106 107]
# [ -92 -91 110 111]]
numpy.copysign()
においてもブロードキャストが行われる。
print(np.copysign(a, b_small))
# [[-0. -1. 2. 3.]
# [-4. -5. 6. 7.]
# [-8. -9. 10. 11.]]
ブロードキャストできない場合はエラーとなる。
b_mismatch = np.array([-100, -100, 100])
print(b_mismatch)
# [-100 -100 100]
# print(np.copysign(a, b_mismatch))
# ValueError: operands could not be broadcast together with shapes (3,4) (3,)
numpy.copysign()
の第二引数にはスカラー値も指定できる。
print(np.copysign(b, -10))
# [[-5. -4. -3. -2.]
# [-1. -0. -1. -2.]
# [-3. -4. -5. -6.]]
第二引数にスカラー値を指定した場合は全てに要素がその符号に揃えられるが、絶対値を返すnp.abs()
を使って同じように要素全体の符号を揃えることもできる。numpy.copysign()
の返り値はfloat
だが、np.abs()
を使うとそれぞれのデータ型に応じた型となる。
print(np.abs(b) * -1)
# [[-5 -4 -3 -2]
# [-1 0 -1 -2]
# [-3 -4 -5 -6]]
print(np.abs(b) * -1.0)
# [[-5. -4. -3. -2.]
# [-1. -0. -1. -2.]
# [-3. -4. -5. -6.]]
負の0や無限大inf、欠損値nanの場合
浮動小数点数float
のゼロや無限大inf
は符号を持つのでそのほかの値と同じように扱われる。
第一引数がnan
である場合は第二引数によらずnan
のまま。
a_special = np.array([0.0, -0.0, np.inf, -np.inf, np.nan])
print(a_special)
# [ 0. -0. inf -inf nan]
print(np.copysign(a_special, 1))
# [ 0. 0. inf inf nan]
print(np.copysign(a_special, -1))
# [ -0. -0. -inf -inf nan]
第二引数がnan
である場合は正となる。
print(np.copysign([10, 10, 10, 10, 10], a_special))
# [ 10. -10. 10. -10. 10.]
print(np.copysign([-10, -10, -10, -10, -10], a_special))
# [ 10. -10. 10. -10. 10.]
第二引数に整数int
の0
を指定した場合は正として扱われる。
print(np.copysign(10, 0))
# 10.0
numpy.copysign()
は常に浮動小数点数float
を返すので、第一引数が整数の0
でも第二引数に応じて正負いずれかのゼロ(0.0
または-0.0
)となる。
print(np.copysign(0, 10))
# 0.0
print(np.copysign(0, -10))
# -0.0
複素数の場合
numpy.copysign()
は複素数には対応していない。第一引数に指定しても第二引数に指定してもエラーとなる。
a_complex = np.array([10 + 10j, -10 + 10j])
print(a_complex)
# [ 10.+10.j -10.+10.j]
# print(np.copysign(a_complex, 1))
# TypeError: ufunc 'copysign' 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.copysign([1, 1], a_complex))
# TypeError: ufunc 'copysign' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''