NumPyで三角関数(sin, cos, tan, arcsin, arccos, arctan)
NumPyでは、配列numpy.ndarray
の各要素に対して三角関数(sin, cos, tan)および逆三角関数(arcsin, arccos, arctan)を計算する関数が提供されている。
三角関数はPythonの標準ライブラリmathモジュールでも計算可能。
NumPyでは、三角関数のほか、np.sinh()
, np.cosh()
, np.tanh()
, np.arcsinh()
, np.arccosh()
, np.arctanh()
といった双曲線関数も提供されている。
本記事のサンプルコードのNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。
import numpy as np
print(np.__version__)
# 1.26.1
円周率(パイ): np.pi
円周率(パイ、π)はnp.pi
で定義されている。
print(np.pi)
# 3.141592653589793
共通の話題
それぞれの関数に共通する内容として、各関数に引数として指定できる型および値の丸めについて説明する。
対象となる型
以下、度をラジアンに変換するnp.radians()
を例とするが、np.sin()
などほかの関数でも同じ。
引数にスカラー値(数値)を指定すると、スカラー値が返される。
print(np.radians(180))
# 3.141592653589793
print(type(np.radians(180)))
# <class 'numpy.float64'>
引数にnumpy.ndarray
を指定すると、要素ごとに処理されたnumpy.ndarray
が返される。
a = np.array([0, 90, 180])
print(type(a))
# <class 'numpy.ndarray'>
print(np.radians(a))
# [0. 1.57079633 3.14159265]
print(type(np.radians(a)))
# <class 'numpy.ndarray'>
numpy.ndarray
だけでなく、リストなどのいわゆるarray-likeオブジェクトも指定可能。返り値はnumpy.ndarray
なので注意。
l = [0, 90, 180]
print(type(l))
# <class 'list'>
print(np.radians(l))
# [0. 1.57079633 3.14159265]
print(type(np.radians(l)))
# <class 'numpy.ndarray'>
numpy.ndarray
とリストの相互変換については以下の記事を参照。
値の丸め
無理数である円周率を用いるので、三角関数の計算には誤差が生じる場合がある。
値を丸めたい場合はnp.round()
を使う。第二引数に返り値の小数点以下の桁数(デフォルトは0
)を指定する。
a = np.array([0, 90, 180])
print(np.radians(a))
# [0. 1.57079633 3.14159265]
print(np.round(np.radians(a)))
# [0. 2. 3.]
print(np.round(np.radians(a), 2))
# [0. 1.57 3.14]
三角関数の計算で誤差が生じる具体例は以下の通り。
print(np.sin(np.radians(30)))
# 0.49999999999999994
print(np.round(np.sin(np.radians(30)), 1))
# 0.5
numpy.ndarray
として出力すると要素の値が丸められて表示される場合があるが、あくまでも表示上丸められているだけで、値自体はそのまま。
print(np.sin(np.radians([0, 30, 90])))
# [0. 0.5 1. ]
print(np.sin(np.radians([0, 30, 90]))[1])
# 0.49999999999999994
print()
で出力される桁数などの設定はnp.set_printoptions()
で変更できる。
np.set_printoptions(precision=20)
print(np.sin(np.radians([0, 30, 90])))
# [0. 0.49999999999999994 1. ]
np.set_printoptions(precision=8) # reset to default
以降のサンプルコードではデフォルトprecision=8
で実行した結果を示す。
角度変換(ラジアン、度)
NumPyにおけるnp.sin()
, np.arcsin()
などの三角関数・逆三角関数では、角度をラジアン(弧度)で表す。
度からラジアン: np.radians(), np.deg2rad()
度からラジアンへの変換はnp.radians()
またはnp.deg2rad()
。どちらでも結果は同じ。
print(np.radians([0, 90, 180]))
# [0. 1.57079633 3.14159265]
print(np.deg2rad([0, 90, 180]))
# [0. 1.57079633 3.14159265]
ラジアンから度: np.degrees(), np.rad2deg()
ラジアンから度への変換はnp.degrees()
またはnp.rad2deg()
。どちらでも結果は同じ。
print(np.degrees([0, np.pi / 2, np.pi]))
# [ 0. 90. 180.]
print(np.rad2deg([0, np.pi / 2, np.pi]))
# [ 0. 90. 180.]
正弦、逆正弦: np.sin(), np.arcsin()
正弦(サイン、sin)はnp.sin()
、逆正弦(アークサイン、arcsin)はnp.arcsin()
。
print(np.sin(np.radians([0, 30, 90])))
# [0. 0.5 1. ]
print(np.degrees(np.arcsin([0, 0.5, 1])))
# [ 0. 30. 90.]
余弦、逆余弦: np.cos(), np.arccos()
余弦(コサイン、cos)はnp.cos()
、逆余弦(アークコサイン、arccos)はnp.arccos()
。
print(np.cos(np.radians([0, 60, 90])))
# [1.000000e+00 5.000000e-01 6.123234e-17]
print(np.round(np.cos(np.radians([0, 60, 90])), 1))
# [1. 0.5 0. ]
print(np.degrees(np.arccos([0, 0.5, 1])))
# [90. 60. 0.]
正接、逆正接: np.tan(), np.arctan(), np.arctan2()
正接(タンジェント、tan)はnp.tan()
、逆正接(アークタンジェント、arctan)はnp.arctan()
またはnp.arctan2()
。np.arctan2()
については後述。
print(np.tan(np.radians([0, 45, 90])))
# [0.00000000e+00 1.00000000e+00 1.63312394e+16]
print(np.degrees(np.arctan([0, 1, np.inf])))
# [ 0. 45. 90.]
np.inf
は無限大を表す。
np.arctan()とnp.arctan2()の違いと負のゼロ
np.arctan()
とnp.arctan2()
はどちらも逆正接を返す関数だが、引数の数と返り値の範囲が異なる。
np.arctan(x)
は引数が一つでarctan(x)
をラジアンで返す。返り値は-pi / 2
からpi / 2
(-90度から90度)の間になる。
print(np.degrees(np.arctan([-np.inf, -1, 0, 1, np.inf])))
# [-90. -45. 0. 45. 90.]
np.arctan2(y, x)
は引数が二つで、arctan(y / x)
をラジアンで返す。この角度は、極座標平面において原点から座標(x, y)
へのベクトルがx軸の正の方向となす角度(偏角)であり、返り値は-pi
からpi
(-180度から180度)の間になる。
第2象限、第3象限における角度も正しく取得できるので、極座標平面で考える場合はnp.arctan()
よりもnp.arctan2()
のほうが適当。
引数の順番がx, y
ではなくy, x
なので注意。
print(np.degrees(np.arctan2(-1, 1)))
# -45.0
print(np.degrees(np.arctan2(1, -1)))
# 135.0
第一引数、第二引数にはnumpy.ndarray
やリストなどのarray-likeオブジェクトも指定できる。対応する要素のペアで値が算出される。
print(np.degrees(np.arctan2([0, 1, 1, 1, 0],
[0, 1, 0, -1, -1])))
# [ 0. 45. 90. 135. 180.]
print(np.degrees(np.arctan2([0, -1, -1, -1, 0],
[0, 1, 0, -1, -1])))
# [ 0. -45. -90. -135. 180.]
上の例のように、x軸の負の方向(y
が0でx
が負の値)はpi
(180度)となるが、y
が負のゼロのときは-pi
(-180度)となる。符号を厳密に処理したい場合は要注意。
print(np.degrees(np.arctan2(0, -1)))
# 180.0
print(np.degrees(np.arctan2(-0.0, -1.0)))
# -180.0
なお、負のゼロは浮動小数点数float
で指定可能。整数int
では負のゼロを扱えないので-0
は0
として扱われる。
print(np.degrees(np.arctan2(-0, -1)))
# 180.0
上の例のように、ゼロの符号(正負)によって結果の符号が変わる場合はほかにもある。結果の符号は、負のゼロを負の微小な値とイメージすると理解しやすい。
print(np.degrees(np.arctan2([0.0, -0.0, 0.0, -0.0],
[0.0, 0.0, -0.0, -0.0])))
# [ 0. -0. 180. -180.]
print(np.sin(-0.0))
# -0.0
print(np.arcsin(-0.0))
# -0.0
print(np.tan(-0.0))
# -0.0
print(np.arctan(-0.0))
# -0.0