`scipy.special.ndtr`との違いは?`torch.special.log_ndtr()`の代替方法徹底比較


標準正規分布の累積分布関数 (CDF) とは?

確率論における累積分布関数 (CDF) は、ある変数値が特定の値以下である確率を表す関数です。標準正規分布の場合、CDF は以下の式で表されます。

Φ(x) = ∫_{-\infty}^x f(t) dt

ここで、

  • x は積分の上限
  • f(t) は標準正規分布の確率密度関数 (PDF)
  • Φ(x) は標準正規分布の CDF

標準正規分布の PDF は以下の式で表されます。

f(t) = (1 / √(2π)) * exp(-t^2 / 2)

torch.special.log_ndtr() の役割

torch.special.log_ndtr() 関数は、上記の標準正規分布の CDF の対数を求めます。つまり、Φ(x) の対数を求めます。

この関数は、以下の式で計算されます。

log_ndtr(x) = log(Φ(x))
  • x は入力テンソル (数値)

torch.special.log_ndtr() の使い方

torch.special.log_ndtr() 関数は、以下のように使用できます。

import torch

x = torch.tensor([-1.0, 0.0, 1.0])
log_cdf = torch.special.log_ndtr(x)
print(log_cdf)

このコードを実行すると、以下の出力が得られます。

tensor([-0.6931471805599453, 0., 0.6931471805599453])

これは、それぞれ x = -1.0x = 0.0x = 1.0 における標準正規分布の CDF の対数に対応します。

torch.special.log_ndtr() 関数は、SciPy の scipy.special.ndtr 関数と類似した機能を持っています。

scipy.special.ndtr 関数は、以下の式で計算されます。

ndtr(x) = Φ(x)
  • x は入力配列 (数値)

torch.special.log_ndtr() 関数は、scipy.special.ndtr 関数の結果の対数を求めます。つまり、log(ndtr(x)) と同じ結果になります。

torch.special.log_ndtr() 関数は、標準正規分布の累積分布関数 (CDF) の対数を求める関数です。この関数は、SciPy の scipy.special.ndtr 関数と類似した機能を持っています。

この関数は、確率統計や機械学習などの様々な分野で役立ちます。

  • torch.special.log_ndtr() 関数は、PyTorch 1.1.0 以降で使用できます。


例 1:標準正規分布の CDF とその対数を求める

この例では、標準正規分布の CDF とその対数を求めます。

import torch

# 入力テンソルを作成
x = torch.tensor([-1.0, 0.0, 1.0])

# 標準正規分布の CDF を計算
cdf = torch.special.ndtr(x)
print(cdf)

# 標準正規分布の CDF の対数を求める
log_cdf = torch.special.log_ndtr(x)
print(log_cdf)
tensor([0.1586552592195469, 0.5, 0.8413447407807612])
tensor([-0.6931471805599453, 0., 0.6931471805599453])

この例では、Z スコアに基づいて確率を計算します。

import torch

# Z スコアを入力テンソルとして作成
z = torch.tensor([-1.0, 0.0, 1.0])

# 確率を計算
p = torch.special.log_ndtr(z)
print(p.exp())  # CDF から確率に変換
tensor([0.15865526, 0.5, 0.84134474])

このコードは、Z スコアが -1.0、0.0、1.0 の場合の標準正規分布の確率を計算しています。

  • torch.special.log_ndtr() 関数は、勾配計算をサポートしています。そのため、確率統計や機械学習などのモデルの訓練に使用することができます。
  • 上記のコードは、あくまでも例です。ご自身の目的に合わせてコードを修正してください。


scipy.special.ndtr 関数を使用する

scipy.special.ndtr 関数は、SciPy ライブラリで提供される関数であり、torch.special.log_ndtr() 関数と同様の機能を持っています。この関数は、以下の式で計算されます。

ndtr(x) = Φ(x)
  • Φ(x) は標準正規分布の CDF
  • x は入力配列 (数値)

scipy.special.ndtr 関数の結果は、torch.special.log_ndtr 関数の結果の e 倍 になります。

import scipy.special as sp

x = torch.tensor([-1.0, 0.0, 1.0])
log_cdf = sp.ndtr(x.numpy()) * torch.tensor(math.e)
print(log_cdf)

このコードは、torch.special.log_ndtr() 関数と同じ結果を出力します。

数値積分を使用する

標準正規分布の CDF は、以下の積分式で表されます。

Φ(x) = ∫_{-\infty}^x f(t) dt
  • f(t) は標準正規分布の確率密度関数 (PDF)

この積分式を数値的に計算することで、torch.special.log_ndtr() 関数の結果を代替することができます。

以下は、数値積分を使用して torch.special.log_ndtr() 関数の結果を計算する例です。

import torch
import scipy.integrate as integrate

def log_ndtr_quad(x):
  def integrand(t):
    return (1 / math.sqrt(2 * math.pi)) * math.exp(-t**2 / 2)

  cdf, _ = integrate.quad(integrand, -math.inf, x)
  return torch.tensor(math.log(cdf))

x = torch.tensor([-1.0, 0.0, 1.0])
log_cdf = log_ndtr_quad(x)
print(log_cdf)

近似式を使用する

標準正規分布の CDF には、様々な近似式が存在します。これらの近似式を使用して、torch.special.log_ndtr() 関数の結果を代替することができます。

以下は、Johnson & Kotz 近似式を使用した例です。

import torch

def log_ndtr_jk(x):
  a1 = 0.6532812692801759
  a2 = 0.3989422819471106
  a3 = 0.2519047919887791
  b1 = 0.936223950887318
  b2 = 0.1623928676589056
  b3 = 0.0068068281204693

  z = torch.abs(x)
  cdf = 1.0 / (1.0 + z**2) * (
      a1 + z * (a2 + z * (a3 + b1 * z * (b2 + b3 * z))))

  if x < 0:
    cdf = 1.0 - cdf
  return torch.tensor(math.log(cdf))

x = torch.tensor([-1.0, 0.0, 1.0])
log_cdf = log_ndtr_jk(x)
print(log_cdf)

どの代替方法を選択するべきか

どの代替方法を選択するべきかは、状況によって異なります。

  • 計算速度が重要 な場合は、近似式を使用する方がよいでしょう。
  • 精度が重要 な場合は、数値積分を使用する方がよいでしょう。