Pythonはデータサイエンスや人工知能、物理シミュレーションなど、幅広い分野で活用されているプログラミング言語です。
これらの分野で欠かせない数学的要素の一つが、sin(正弦)やcos(余弦)に代表される三角関数です。
Pythonでは標準ライブラリのmathモジュールや、外部ライブラリのNumPyを使用することで、これらの計算を非常に簡単に実行できます。
しかし、プログラムの実装においては、角度の単位である「ラジアン」と「度」の扱いや、計算速度を重視したライブラリの選択が重要となります。
本記事では、Pythonで三角関数を扱うための基本的な方法から、実践的な活用シーンまでを詳しく解説します。
三角関数の基本とPythonでの役割
三角関数は、直角三角形の辺の比率や、円運動、波動などを記述するために用いられる数学的な関数です。
Pythonでこれらの関数を扱う場合、主に数値計算やグラフィックス、信号処理といった領域で頻繁に登場します。
プログラムの中で三角関数を正しく扱うためには、まず数学的な前提条件を理解しておく必要があります。
ラジアン(弧度法)と度(度数法)の違い
Pythonの三角関数を扱う上で最も注意すべき点は、角度の単位です。
日常生活や一般的な数学の授業では、30度や90度といった「度(degree)」という単位がよく使われます。
しかし、Pythonの標準ライブラリであるmathやNumPyの関数は、すべて「ラジアン(radian)」を引数として受け取ります。
180度はπ(パイ)ラジアンに相当するため、度をラジアンに変換する計算を忘れると、意図しない計算結果が得られてしまいます。
初心者が陥りやすいミスの一つが、math.sin(90)と記述して、90度のサイン値を求めようとすることです。
この場合、Pythonは「90ラジアン」の値を計算してしまうため、注意が必要です。
円周率πの取り扱い
三角関数の計算には、円周率であるπが不可欠です。
Pythonではmath.piやnumpy.piを使用することで、高精度な円周率の値を呼び出すことができます。
手動で「3.14」といった近似値を入力するのではなく、ライブラリが提供する定数を使用することが、計算精度を保つための鉄則です。
mathモジュールを使用した基本的な計算方法
Pythonの標準ライブラリであるmathモジュールは、追加のインストールなしですぐに使用できる非常に便利なツールです。
単一の数値に対して計算を行う場合や、シンプルなスクリプトを作成する場合には、このモジュールが最適です。
math.sinとmath.cosの使い方
まずは、特定の角度に対するsin値とcos値を求める基本的なコードを見ていきましょう。
以下の例では、45度のサインとコサインを計算しています。
import math
# 角度を度数法で定義
degree_angle = 45
# 度をラジアンに変換
radian_angle = math.radians(degree_angle)
# sinとcosを計算
sin_value = math.sin(radian_angle)
cos_value = math.cos(radian_angle)
print(f"{degree_angle}度のsin: {sin_value}")
print(f"{degree_angle}度のcos: {cos_value}")
45度のsin: 0.7071067811865476
45度のcos: 0.7071067811865476
このように、math.radians()関数を使用して度をラジアンに変換してから計算を行います。
計算結果は浮動小数点数(float)として返されます。
角度の変換(math.radiansとmath.degrees)
mathモジュールには、角度の単位変換をサポートする関数が用意されています。
math.radians(x)は「度からラジアン」へ、math.degrees(x)は「ラジアンから度」へ変換します。
自分で「角度 * π / 180」といった計算式を書く必要がないため、コードの可読性が向上します。
import math
# 度からラジアンへ変換
r = math.radians(180)
print(f"180度は {r} ラジアンです。")
# ラジアンから度へ変換
d = math.degrees(math.pi)
print(f"πラジアンは {d} 度です。")
180度は 3.141592653589793 ラジアンです。
πラジアンは 180.0 度です。
これらの関数を適切に使い分けることで、数学的なミスを未然に防ぐことができます。
NumPyモジュールを使用した高度な計算
大量のデータを一度に処理したい場合や、行列演算を行いたい場合には、NumPy(ナンパイ)ライブラリの使用が推奨されます。
NumPyは「ベクトル演算」を得意としており、リスト内のすべての要素に対して一括で三角関数を適用することが可能です。
配列データに対する一括処理のメリット
標準のmathモジュールは、一度に一つの数値しか処理できません。
一方、NumPyのnp.sin()やnp.cos()は、NumPy配列(ndarray)を引数に取ることができます。
これにより、ループ処理(for文)を記述することなく、高速に大量の計算を完了させることができます。
import numpy as np
# 0度, 30度, 45度, 60度, 90度の配列を作成
degrees = np.array([0, 30, 45, 60, 90])
# 配列全体をラジアンに変換
radians = np.radians(degrees)
# 配列に対して一括でsinを適用
sin_values = np.sin(radians)
print(f"角度配列: {degrees}")
print(f"sin値の配列: {sin_values}")
角度配列: [ 0 30 45 60 90]
sin値の配列: [0. 0.5 0.70710678 0.8660254 1. ]
このように、コードが非常に簡潔になり、実行速度も劇的に向上します。
np.linspaceと組み合わせた波形データの作成
NumPyの強力な機能の一つに、一定間隔の数値を生成するnp.linspace()があります。
これと三角関数を組み合わせることで、サイン波などの波形データを簡単に作成できます。
これは、音声波形の分析や、時系列データのシミュレーションなどで非常によく使われるテクニックです。
import numpy as np
# 0から2π(1周期)の間を10等分した配列を生成
x = np.linspace(0, 2 * np.pi, 10)
# サイン波の値を計算
y = np.sin(x)
# 結果の確認(各地点での値)
for i, val in enumerate(y):
print(f"地点 {i}: {val:.4f}")
地点 0: 0.0000
地点 1: 0.6428
地点 2: 0.9848
地点 3: 0.8660
地点 4: 0.3420
地点 5: -0.3420
地点 6: -0.8660
地点 7: -0.9848
地点 8: -0.6428
地点 9: -0.0000
生成する要素数を増やすことで、より滑らかな曲線データを構築することが可能です。
mathとNumPyの使い分けのポイント
Pythonで三角関数を計算する際、どちらのライブラリを使うべきか迷うことがあるかもしれません。
基本的には、以下の基準で判断すると良いでしょう。
| 項目 | mathモジュール | NumPyライブラリ |
|---|---|---|
| 主な用途 | 単一の数値計算、軽量なスクリプト | 大量のデータ処理、行列演算、科学技術計算 |
| 処理スピード | 単一計算なら高速 | 大規模な配列計算で圧倒的に高速 |
| 依存関係 | 標準ライブラリ(インストール不要) | 外部ライブラリ(インストールが必要) |
| 関数の豊富さ | 基本的な数学関数が中心 | 線形代数や統計など多機能 |
「一つだけの値を計算したいときはmath、複数の値をまとめて処理したいときはNumPy」と覚えておけば間違いありません。
実践的な活用シーン
三角関数は、単に数値を求めるだけでなく、現実世界の課題を解決するためにも使われます。
ここでは、Pythonを用いた具体的な応用例を2つ紹介します。
2次元座標の回転計算
ゲーム開発やグラフィック処理において、点を特定の角度だけ回転させたい場合があります。
この回転の計算には、sinとcosを用いた「回転行列」の考え方が使われます。
点 (x, y) を原点を中心に θ 度回転させた後の座標 (x’, y’) は、以下の式で求められます。
- x’ = x * cos(θ) – y * sin(θ)
- y’ = x * sin(θ) + y * cos(θ)
import math
def rotate_point(x, y, angle_degrees):
# 角度をラジアンに変換
rad = math.radians(angle_degrees)
# 新しい座標を計算
nx = x * math.cos(rad) - y * math.sin(rad)
ny = x * math.sin(rad) + y * math.cos(rad)
return nx, ny
# (10, 0) の点を90度回転させる
new_x, new_y = rotate_point(10, 0, 90)
print(f"回転後の座標: ({new_x:.1f}, {new_y:.1f})")
回転後の座標: (0.0, 10.0)
このように、三角関数を使えば2次元平面上の自由な移動や回転を制御できます。
周期的なデータのシミュレーション
気温の変化や電力需要、機械の振動など、周期的に繰り返される事象のモデル化にも三角関数が使われます。
例えば、1日の気温の変化を簡易的にサインカーブで表現することができます。
周期、振幅、位相の3つの要素を調整することで、様々な波形を表現することが可能です。
import numpy as np
# 24時間の時間軸を作成(0.1時間刻み)
times = np.arange(0, 24, 0.1)
# 平均気温20度、振幅5度の気温変化をシミュレーション
# (12時に最高気温が来ると仮定した位相調整)
amplitude = 5
mean_temp = 20
temperatures = mean_temp + amplitude * np.sin((times - 6) * np.pi / 12)
print(f"6時の気温: {temperatures[60]:.2f}度")
print(f"12時の気温: {temperatures[120]:.2f}度")
print(f"18時の気温: {temperatures[180]:.2f}度")
6時の気温: 20.00度
12時の気温: 25.00度
18時の気温: 20.00度
こうしたシミュレーションは、機械学習における特徴量エンジニアリングなどでも応用されています。
逆三角関数と双曲線関数
Pythonではsinやcosだけでなく、その逆関数である逆三角関数もサポートされています。
辺の比率から角度を求めたい場合には、asin (arcsin) や acos (arccos)、atan (arctan) を使用します。
角度を求めるmath.asinとmath.acos
例えば、sinの値が0.5になる角度を知りたい場合、以下のように記述します。
import math
# sin値からラジアンを求める
rad = math.asin(0.5)
# ラジアンを度に変換
deg = math.degrees(rad)
print(f"sinが0.5のときの角度は {deg} 度です。")
sinが0.5のときの角度は 30.000000000000004 度です。
また、より特殊な数学的計算で使われる「双曲線関数(sinh, cosh, tanh)」も、同様にmath.sinhやnumpy.sinhとして用意されています。
これらはカテナリー曲線(吊り橋の形状)の計算などに用いられる重要な関数です。
注意点とエラーへの対処
三角関数をPythonで扱う際には、コンピュータ特有の「浮動小数点数の精度」に注意しなければなりません。
例えば、数学的に cos(90度) は 0 になるはずですが、Pythonで計算すると極めて小さな値(例:6.1232e-17)になることがあります。
これは、πの値が有限の桁数で打ち切られているために発生する微細な誤差です。
import math
# cos(90度)を計算
val = math.cos(math.radians(90))
print(f"cos(90度)の結果: {val}")
# ほぼ0であるか判定する場合
print(f"ほぼ0であるか: {math.isclose(val, 0, abs_tol=1e-9)}")
cos(90度)の結果: 6.123233995736766e-17
ほぼ0であるか: True
値を比較する際には、== 0 ではなく、math.isclose() を使用して一定の許容誤差(しきい値)を持たせることが実務上のテクニックです。
また、math.asin(x) の引数に「-1から1」の範囲外の数値を入れると ValueError が発生します。
引数の値が適切な範囲に収まっているかを事前にチェックすることも重要です。
まとめ
Pythonでsin・cosといった三角関数を計算する方法について解説してきました。
標準ライブラリのmathモジュールは、個別の数値を計算する際に手軽で強力なツールとなります。
一方で、データ分析や科学計算のように大量のデータを扱う場面では、NumPyのベクトル演算を活用することで効率的な開発が可能になります。
いずれの場合も、「角度はラジアンで指定する」という原則を忘れないことが、正確なプログラムを作成するための第一歩です。
今回紹介した基本操作や単位変換、座標回転などの応用例を参考に、ぜひ自身のプロジェクトで三角関数を活用してみてください。
数学的な背景を理解し、適切なライブラリを選択することで、Pythonでの数値計算の幅は大きく広がるはずです。
