データサイエンスや科学技術計算の分野において、PythonのライブラリであるNumPyは欠かすことのできない強力なツールです。
NumPyは数値計算を効率化するための多機能を備えていますが、その中でも「三角関数」の扱いは物理演算や信号処理、機械学習など幅広い領域で基礎となります。
本記事では、NumPyを用いてsin(正弦)やcos(余弦)を正しく計算するための具体的な方法を詳しく解説します。
特に初心者の方が陥りやすい「度数法」と「弧度法」の変換ミスや、配列を用いた効率的な一括計算のポイントに焦点を当てていきます。
これからPythonでの数値計算を本格的に学びたい方にとって、実戦で役立つ知識を整理していきましょう。
NumPyにおける三角関数の基本:sinとcosの使い方
NumPyで三角関数を計算する際、最も頻繁に使用されるのがnp.sin()とnp.cos()です。
これらの関数は、与えられた数値に対して正弦(サイン)や余弦(コサイン)の値を返します。
まずは、最もシンプルな単一の数値に対する計算方法を確認してみましょう。
import numpy as np
# 0ラジアンのsinとcosを計算する
sin_value = np.sin(0)
cos_value = np.cos(0)
print(f"sin(0): {sin_value}")
print(f"cos(0): {cos_value}")
sin(0): 0.0
cos(0): 1.0
上記のように、NumPyの関数を呼び出すだけで簡単に値を求めることができます。
しかし、ここで非常に重要な注意点があります。
それは、NumPyの三角関数に渡す引数は、常に「ラジアン(弧度法)」でなければならないという点です。
私たちが日常的に使う「90度」や「180度」といった度数法の値をそのまま入力すると、意図しない結果が返ってきます。
例えば、90度のsinは1ですが、np.sin(90)と記述すると、NumPyは「90ラジアン」の値を計算してしまいます。
弧度法(ラジアン)と度数法の変換を正しく行う
プログラムの中で角度を扱う際、人間にとって理解しやすい「度」から、計算機が理解する「ラジアン」へ変換する必要があります。
1ラジアンは、円の半径と弧の長さが等しくなる時の角度として定義されています。
具体的には、180度がπ(パイ)ラジアンに相当します。
NumPyには、この変換を簡単に行うための専用関数が用意されています。
np.radiansを用いた変換
度数法をラジアンに変換するには、np.radians()関数を使用するのが最も一般的です。
また、同じ機能を持つ関数としてnp.deg2rad()も存在します。
以下のコードで、90度をラジアンに変換してsinを計算する方法を見てみましょう。
import numpy as np
# 90度を定義
degrees = 90
# 度をラジアンに変換する
radians = np.radians(degrees)
# ラジアンを用いて計算
result = np.sin(radians)
print(f"{degrees}度のラジアン表記: {radians}")
print(f"sin({degrees}度)の結果: {result}")
90度のラジアン表記: 1.5707963267948966
sin(90度)の結果: 1.0
このように、np.radians()を介することで、直感的な角度指定が可能になります。
np.degreesを用いた逆変換
計算結果として得られたラジアンを、再び度数法に戻したい場合はnp.degrees()を使用します。
あるいは、np.rad2deg()という関数名でも同様の処理が可能です。
逆三角関数などの戻り値を確認する際に非常に役立ちます。
import numpy as np
# π/4 ラジアン(45度)を定義
rad = np.pi / 4
# ラジアンを度に戻す
deg = np.degrees(rad)
print(f"{rad}ラジアンは {deg}度 です。")
0.7853981633974483ラジアンは 45.0度 です。
これらの変換関数を適切に使い分けることが、計算ミスを防ぐ第一歩です。
NumPy配列(ndarray)を用いた一括計算のポイント
NumPyの真価は、単一の数値ではなく、大量のデータを一度に処理できる点にあります。
Python標準のmathモジュールでも三角関数の計算は可能ですが、NumPyは配列(ndarray)を直接引数として受け取ることができるという大きな強みがあります。
ループを使わないベクトル演算
リスト内の複数の角度に対してsinを計算したい場合、Pythonのfor文を使う必要はありません。
NumPyの関数は「ユニバーサル関数(ufunc)」と呼ばれ、配列の各要素に対して自動的に適用されます。
import numpy as np
# 0度、30度、45度、60度、90度の配列を作成
degrees_array = np.array([0, 30, 45, 60, 90])
# 配列全体を一括でラジアンに変換
radians_array = np.radians(degrees_array)
# 配列全体を一括でsin計算
sin_values = np.sin(radians_array)
print("角度(度):", degrees_array)
print("sinの値 :", sin_values)
角度(度): [ 0 30 45 60 90]
sinの値 : [0. 0.5 0.70710678 0.8660254 1. ]
この「ベクトル演算」により、コードの記述量が減り、可読性が大幅に向上します。
さらに、内部処理がC言語で最適化されているため、大規模なデータに対しても非常に高速な計算が可能です。
等間隔な配列の生成と活用
特定の範囲の角度について一斉に値を求めたい場合は、np.linspace()が便利です。
例えば、0度から360度までを等間隔に分割したデータセットを簡単に作成できます。
# 0から2π(360度)までを10分割する
x = np.linspace(0, 2 * np.pi, 10)
y = np.cos(x)
print("x (radians):", x)
print("y (cos x) :", y)
この手法は、後述するグラフの描画や信号波形の生成において必須のテクニックとなります。
逆三角関数の活用:arcsin, arccos, arctan
三角関数の逆演算、つまり「ある値から角度を求める」場合には、逆三角関数を使用します。
NumPyでは、np.arcsin(), np.arccos(), np.arctan()がそれに対応します。
戻り値はラジアン単位となるため、必要に応じてnp.degrees()で変換しましょう。
arctan2による精度の高い角度算出
座標(x, y)から角度を求める際、np.arctan(y/x)を使用すると、xが0の場合にエラーが発生したり、象限の判別が正しくできなかったりします。
そこで推奨されるのが、np.arctan2(y, x)です。
この関数は、y座標とx座標を個別の引数として受け取り、正しい象限(-πからπの範囲)の角度を返してくれます。
import numpy as np
x = -1
y = 1
# 通常のarctan(y/x)では、象限の判断が難しい場合がある
# arctan2を使用すると正確な角度が得られる
angle_rad = np.arctan2(y, x)
angle_deg = np.degrees(angle_rad)
print(f"座標({x}, {y})の角度は {angle_deg}度 です。")
座標(-1, 1)の角度は 135.0度 です。
ロボットの制御やゲームの向き判定など、幾何学的な計算を行う際にはnp.arctan2が非常に強力な武器になります。
浮動小数点数による誤差と注意点
コンピュータで三角関数を扱う際、避けて通れないのが「浮動小数点数の計算誤差」です。
数学的にはsin(π)はちょうど0になりますが、プログラム上の計算では完全な0にならないことがあります。
誤差が発生する具体例
以下のコードを実行して、計算結果を確認してみましょう。
import numpy as np
# πのsinを計算
val = np.sin(np.pi)
print(f"sin(π)の計算結果: {val}")
sin(π)の計算結果: 1.2246467991473532e-16
結果は1.2246...e-16となっており、極めて0に近いものの、完全な0ではありません。
これは、np.pi自体が有限の桁数で近似された値であるために生じる現象です。
そのため、計算結果が0かどうかを判定する際は、== 0ではなく、一定の許容誤差を含めて比較を行うべきです。
NumPyには、近似的に等しいかを判定するnp.isclose()という便利な関数も用意されています。
応用編:正弦波(サインカーブ)の生成
NumPyの三角関数は、データ分析や音声信号のシミュレーションによく使われます。
ここでは、特定の周波数を持つ正弦波(サイン波)を生成する例を紹介します。
import numpy as np
# サンプリングレート(Hz)
fs = 44100
# 信号の周波数(Hz)
f = 440
# 期間(秒)
t_duration = 0.01
# 時間軸の配列を作成
t = np.linspace(0, t_duration, int(fs * t_duration), endpoint=False)
# 正弦波の式: y = sin(2 * pi * f * t)
wave = np.sin(2 * np.pi * f * t)
print("生成された波形の最初の5サンプル:")
print(wave[:5])
生成された波形の最初の5サンプル:
[0. 0.06264832 0.12505052 0.18696144 0.24813784]
この例では、440Hzの音(音楽の「ラ」の音に近い周波数)の波形の一部を数値化しています。
このように時間軸を配列として定義し、一括で三角関数を適用する手法は、NumPyの最も標準的な活用パターンの一つです。
NumPyの定数とその他の関数
三角関数の計算に関連して、NumPyが提供する定数や便利なバリエーションについても知っておくと役立ちます。
np.piの精度
円周率πを扱う際は、自分で数値を入力するのではなく、必ずnp.piを使用しましょう。
np.piは浮動小数点数として最大限の精度を持って定義されています。
tanと双曲線関数
正弦・余弦以外にも、正接を求めるnp.tan()が用意されています。
さらに、物理現象の解析などで用いられる双曲線関数np.sinh(), np.cosh(), np.tanh()も完備されています。
これらもすべて配列処理(ベクトル演算)に対応しているため、統一された操作感で利用可能です。
行列計算と三角関数
座標変換や画像処理における「回転行列」の作成にも、NumPyの三角関数が欠かせません。
例えば、ある点を原点周りにθだけ回転させる行列は、sinとcosを組み合わせた2×2の配列として表現されます。
NumPyなら、こうした行列の構築もシンプルに記述できます。
まとめ
本記事では、NumPyで三角関数(sin, cos)を扱うための基本的な知識から、実践的な応用方法までを解説しました。
まず最も重要な点は、入力値がラジアン単位であることを常に意識することです。
度数法からの変換にはnp.radians()を活用し、ミスを未然に防ぎましょう。
また、NumPyの配列(ndarray)を活用することで、大量のデータをループなしで高速に処理できるというメリットを最大限に引き出してください。
逆三角関数やnp.arctan2を使いこなすことで、複雑な幾何学計算も効率的に実装できるようになります。
浮動小数点数特有の微小な誤差には注意が必要ですが、NumPyが提供する豊富な関数群は、あなたのデータ分析や科学計算を強力にサポートしてくれるはずです。
今回の内容を基礎として、ぜひより高度な数値計算の世界に挑戦してみてください。
