【log】numpyで対数関数を計算する方法を解説

Python

numpyを使用すると、様々な種類の対数関数を簡単に計算できます。本記事では、numpy.log、numpy.log10、numpy.log2、numpy.log1p、numpy.emath.logの使い方とそれぞれの特徴、さらにPythonの標準ライブラリのmath.logとの違いについて詳しく解説します。

log

numpy.logは自然対数(底がe)を計算する関数です。数学的には ln(x) と表記されます。

基本的な使い方

単一の値に対して自然対数を計算する例です。

import numpy as np

# 単一の値の自然対数を計算
x = 10
result = np.log(x)
print(result)  # 2.302585092994046

配列に対する計算

配列の各要素に対して自然対数を計算する例です。

import numpy as np

# 配列の各要素の自然対数を計算
arr = np.array([1, 2, 5, 10, 100])
result = np.log(arr)
print(result)  # [0.         0.69314718 1.60943791 2.30258509 4.60517019]

負の値や0に対する処理

負の値や0に対してnp.logを適用した場合の動作を確認する例です。

import numpy as np

# 負の値や0を含む配列
arr = np.array([-1, 0, 1, 2])
result = np.log(arr)
print(result)  # [       nan       -inf 0.         0.69314718]

log10

numpy.log10は常用対数(底が10)を計算する関数です。数学的には log₁₀(x) と表記されます。

基本的な使い方

単一の値に対して常用対数を計算する例です。

import numpy as np

# 単一の値の常用対数を計算
x = 100
result = np.log10(x)
print(result)  # 2.0

配列に対する計算

配列の各要素に対して常用対数を計算する例です。

import numpy as np

# 配列の各要素の常用対数を計算
arr = np.array([1, 10, 100, 1000])
result = np.log10(arr)
print(result)  # [0. 1. 2. 3.]

科学計算での活用

pH値の計算など、科学計算でlog10を使用する例です。

import numpy as np

# 水素イオン濃度からpH値を計算
h_concentration = np.array([1e-7, 1e-3, 1e-1])
ph = -np.log10(h_concentration)
print(ph)  # [7. 3. 1.]

log2

numpy.log2は底が2の対数を計算する関数です。コンピュータサイエンスの分野でよく使用されます。

基本的な使い方

単一の値に対して底2の対数を計算する例です。

import numpy as np

# 単一の値の底2の対数を計算
x = 8
result = np.log2(x)
print(result)  # 3.0

配列に対する計算

配列の各要素に対して底2の対数を計算する例です。

import numpy as np

# 配列の各要素の底2の対数を計算
arr = np.array([1, 2, 4, 8, 16])
result = np.log2(arr)
print(result)  # [0. 1. 2. 3. 4.]

ビット数の計算

データのビット数を計算する際にlog2を使用する例です。

import numpy as np

# 値を表現するのに必要なビット数を計算
values = np.array([1, 255, 1023, 65535])
bits_needed = np.ceil(np.log2(values + 1))
print(bits_needed)  # [ 1.  8. 10. 16.]

log1p

numpy.log1pは ln(1 + x) を計算する関数です。xが0に近い値の場合に数値的に安定した計算を行えます。

基本的な使い方

単一の値に対してlog1pを計算する例です。

import numpy as np

# 単一の値のlog1pを計算
x = 0.1
result = np.log1p(x)
print(result)  # 0.09531017980432496

配列に対する計算

配列の各要素に対してlog1pを計算する例です。

import numpy as np

# 配列の各要素のlog1pを計算
arr = np.array([0, 0.1, 0.5, 1.0])
result = np.log1p(arr)
print(result)  # [0.         0.09531018 0.40546511 0.69314718]

小さな値での精度比較

小さな値に対してnp.logとnp.log1pの精度を比較する例です。

import numpy as np

# 小さな値での精度比較
x = 1e-15
result_log = np.log(1 + x)
result_log1p = np.log1p(x)
print(f"np.log(1 + x): {result_log}")      # np.log(1 + x): 1.1102230246251565e-15
print(f"np.log1p(x): {result_log1p}")      # np.log1p(x): 1e-15

emath.log

numpy.emath.logは複素数に対応した対数関数です。負の実数に対しても複素数として結果を返します。

基本的な使い方

単一の値に対してemath.logを計算する例です。

import numpy as np

# 単一の値のemath.logを計算
x = 10
result = np.emath.log(x)
print(result)  # (2.302585092994046+0j)

負の値に対する計算

負の値に対してemath.logを適用する例です。

import numpy as np

# 負の値のemath.logを計算
x = -1
result = np.emath.log(x)
print(result)  # 3.141592653589793j

複素数配列に対する計算

複素数を含む配列に対してemath.logを計算する例です。

import numpy as np

# 複素数配列のemath.logを計算
arr = np.array([-1, 0+1j, 1+1j])
result = np.emath.log(arr)
print(result)  # [0.        +3.14159265j 0.        +1.57079633j 0.34657359+0.78539816j]

math.logとの比較

Pythonの標準ライブラリのmath.logとnumpyの対数関数には重要な違いがあります。

単一値での処理速度

単一の値に対する処理では、math.logの方が高速です。

import math
import numpy as np
import time

# math.logの処理時間測定
x = 10
start = time.time()
for _ in range(100000):
    result = math.log(x)
math_time = time.time() - start

# numpy.logの処理時間測定
start = time.time()
for _ in range(100000):
    result = np.log(x)
numpy_time = time.time() - start

print(f"math.log: {math_time:.6f}秒")    # math.log: 0.006677秒
print(f"numpy.log: {numpy_time:.6f}秒")  # numpy.log: 0.062678秒

配列処理の対応

math.logは単一の値のみを処理できますが、numpy.logは配列全体を一度に処理できます。

import math
import numpy as np

# numpy.logは配列を直接処理可能
arr = np.array([1, 2, 5, 10])
numpy_result = np.log(arr)
print(numpy_result)  # [0.         0.69314718 1.60943791 2.30258509]

# math.logは配列を直接処理できない(エラーになる)
try:
    math_result = math.log(arr)
except TypeError as e:
    print(f"エラー: {e}")  # エラー: only length-1 arrays can be converted to Python scalars

配列処理での性能比較

大きな配列を処理する場合、numpy.logの方が圧倒的に高速です。

import math
import numpy as np
import time

# 大きな配列を準備
arr = np.random.uniform(1, 100, 100000)

# math.logをループで適用
start = time.time()
math_results = [math.log(x) for x in arr]
math_time = time.time() - start

# numpy.logを配列に適用
start = time.time()
numpy_results = np.log(arr)
numpy_time = time.time() - start

print(f"math.log(ループ): {math_time:.6f}秒")  # math.log(ループ): 0.006725秒
print(f"numpy.log: {numpy_time:.6f}秒")         # numpy.log: 0.000536秒

エラーハンドリングの違い

負の値や0に対する処理で、math.logとnumpy.logは異なる動作をします。

import math
import numpy as np

# math.logは負の値でValueErrorを発生
try:
    result = math.log(-1)
except ValueError as e:
    print(f"math.logエラー: {e}")  # math.logエラー: math domain error

# numpy.logは警告を出してnanを返す
result = np.log(-1)
print(f"numpy.log結果: {result}")  # numpy.log結果: nan

使い分けの指針

単一値の計算が中心でパフォーマンスを重視する場合はmath.logを、配列処理や科学計算が中心の場合はnumpy.logを選択するのが適切です。

まとめ

numpyには用途に応じた様々な対数関数が用意されています。

  • numpy.log: 自然対数(底e)の計算に使用
  • numpy.log10: 常用対数(底10)の計算に使用、科学計算でよく利用
  • numpy.log2: 底2の対数の計算に使用、コンピュータサイエンス分野で活用
  • numpy.log1p: ln(1+x)の計算に使用、小さな値での数値安定性が重要な場合に有効
  • numpy.emath.log: 複素数対応の対数関数、負の値も扱える

また、Pythonの標準ライブラリのmath.logとの使い分けも重要です。単一値の計算ではmath.logが高速ですが、配列処理ではnumpyの対数関数が圧倒的に優れています。適切な対数関数を選択することで、計算の精度と効率を向上させることができます。

タイトルとURLをコピーしました