からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

【Python】1次元ガウス分布から1次元ガウス分布の生成

はじめに

 機械学習や統計学で登場する各種の確率分布について、「計算式の導出・計算のスクラッチ実装・計算過程や結果の可視化」などの「数式・プログラム・図」を用いた解説により、様々な角度から理解を目指すシリーズです。

 この記事では、ガウス分布の乱数とガウス分布の関係についてPythonを使って確認します。

【前の内容】

www.anarchive-beta.com

【他の内容】

www.anarchive-beta.com

【今回の内容】

1次元ガウス分布から1次元ガウス分布の生成

 1次元ガウス分布(Gaussian distribution・正規分布・Normal distribution)に従う乱数をパラメータとして用いることで、1次元ガウス分布を生成します。この記事では、Pythonを利用して生成します。
 ガウス分布については「1次元ガウス分布の定義式 - からっぽのしょこ」、Rを利用する場合は「【R】1次元ガウス分布から確率分布の生成 - からっぽのしょこ」を参照してください。

 利用するライブラリを読み込みます。

# ライブラリを読込
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt


確率分布の生成

 1次元ガウス分布から1次元ガウス分布を作成します。

数式の設定

 平均パラメータ  \mu、標準偏差パラメータ  \sigma (分散パラメータ  \sigma^2 )の1次元ガウス分布  \mathcal{N}(m \mid \mu, \sigma^2) をパラメータの生成分布とします。
 生成分布からサンプル分布のパラメータ  m_n を生成します。

 \displaystyle
m_n
    \sim
      \mathcal{N}(\mu, \sigma^2)

 平均パラメータ  m_n、標準偏差パラメータ  s (分散パラメータ  s^2 )の1次元ガウス分布  \mathcal{N}(x \mid m_n, s^2) をサンプリングした確率分布とします。標準偏差パラメータ  s は固定とします。

生成分布の設定

 1次元ガウス分布については「【Python】1次元ガウス分布の作図 - からっぽのしょこ」や「【Python】1次元ガウス分布の乱数生成 - からっぽのしょこ」を参照してください。

 生成分布のパラメータ  \mu, \sigma を設定します。

# ガウス分布のパラメータを指定
mu    = 0.0
sigma = 2.5
print(mu)
print(sigma)
0.0
2.5

 平均  \mu、標準偏差(正の値)  \sigma \gt 0 を指定します。

 サンプルサイズ  N を指定して、生成分布の乱数(サンプル分布のパラメータ)  m_n を生成します。

# サンプルサイズを指定
N = 6

# ガウス分布の乱数を生成
m_n = np.random.normal(loc=mu, scale=sigma, size=N)
m_n.sort() # 昇順に並べ替え
print(m_n[:5])
[-2.40190527 -0.65720578  0.67387146  1.53138036  4.20901637]

 サンプルサイズ(データ数)  N を指定します。
  N 個のサンプル(ガウス分布の乱数)  m_1, \cdots, m_N を作成して、サンプル分布(ガウス分布)の平均パラメータ  m_n として用います。

 ガウス分布の確率変数  m の作図範囲を設定します。

# m軸の範囲を設定
#x_min = -10.0
#x_max = 10.0
u = 5.0
m_size = sigma # 基準値を指定
m_size *= 3.0 # 倍率を指定
m_size = max(m_size, *np.abs(m_n - mu)) # サンプルと比較
m_size = np.ceil(m_size /u)*u  # u単位で切り上げ
m_min  = mu - m_size
m_max  = mu + m_size
print(m_min, m_max)

# m軸の値を作成
m_vec = np.linspace(start=m_min, stop=m_max, num=1001)
print(m_vec[:5])
-10.0 10.0
[-10.    -9.98  -9.96  -9.94  -9.92]

 この例では、標準偏差  \sigma の倍数、またはサンプルの偏差  m_n - \mu の絶対値の最大値、の大きい方の値を使って、範囲を設定しています。

 生成分布の確率密度  \mathcal{N}(m \mid \mu, \sigma^2) を計算します。

# ガウス分布の確率密度を計算
gen_dens_vec = norm.pdf(x=m_vec, loc=mu, scale=sigma)
print(gen_dens_vec[:5])
[5.35320903e-05 5.52710516e-05 5.70628501e-05 5.89089654e-05
 6.08109148e-05]

 確率密度を計算して、配列に格納します。

 生成分布とサンプルのグラフを作成します。

# カラーマップを作成:(配色の共通化用)
cmap = plt.get_cmap('tab10') # カラーマップを指定
color_num = 10               # カラーマップの色数を設定

# ラベル用の文字列を作成
param_lbl = f'$N = {N}, \\mu = {mu}, \\sigma = {sigma}$'

# 生成分布を作図
plt.figure(figsize=(9, 6), dpi=100, facecolor='white')
plt.plot(
    m_vec, gen_dens_vec, 
    color='black', linewidth=1.0
) # 生成分布
for n in range(N):
    m = m_n[n] # 平均パラメータ
    plt.scatter(
        x=m, y=0.0, 
        color=cmap(n%color_num), alpha=0.5, s=50, 
        label=f'$m_{{{n+1}}} = {m:.2f}$'
    ) # サンプル
plt.xlabel('$m$')
plt.ylabel('density')
plt.suptitle('Gaussian distribution', fontsize=20)
plt.title(param_lbl, loc='left')
plt.grid()
plt.legend(title='sample', prop={'size': 8}, loc='upper left')
plt.show()

1次元ガウス分布の乱数

 生成分布  \mathcal{N}(m \mid \mu, \sigma) を曲線、 N 個のサンプル  m_n を色付けした点として描画します。

サンプル分布の作図

 サンプル分布の固定するパラメータ  s を設定します。

# ガウス分布のパラメータを指定
s = 1.0
print(s)
1.0

 標準偏差(正の値)  s \gt 0 を指定します。

 サンプル分布の確率変数  x の作図範囲を設定します。

# x軸の範囲を設定
x_min = m_min
x_max = m_max

# x軸の値を作成
x_vec = m_vec.copy()
print(x_vec[:5])
[-10.    -9.98  -9.96  -9.94  -9.92]

 作図の都合上、生成分布の確率変数  m と同じ範囲にします。

 サンプル  m_n ごとにサンプル分布の確率密度  \mathcal{N}(x \mid m_n, s^2) を計算します。

# ガウス分布の確率密度を計算
smp_dens_lt = [
    norm.pdf(x=x_vec, loc=m_n[n], scale=s) for n in range(N)
]
print(np.array(smp_dens_lt).shape)
print(smp_dens_lt[0][:5])
(6, 1001)
[1.16084236e-13 1.35108478e-13 1.57187583e-13 1.82801668e-13
 2.12504609e-13]

 リスト内包表記により、 N 個のパラメータ  m_n ごとに確率密度を計算して、リストに格納します。

 サンプル分布のグラフを作成します。

# ガウス分布を作図
plt.figure(figsize=(9, 6), dpi=100, facecolor='white')
for n in range(N):
    m = m_n[n] # 平均パラメータ
    plt.plot(
        x_vec, smp_dens_lt[n], 
        color=cmap(n%color_num), linewidth=1.0, 
        label=f'$m_{{{n+1}}} = {m:.2f}, s = {s}$'
    ) # サンプル分布
plt.xlabel('$x$')
plt.ylabel('density')
plt.suptitle('Gaussian distribution', fontsize=20)
plt.title(param_lbl, loc='left')
plt.grid()
plt.legend(title='parameter', prop={'size': 8}, loc='upper left')
plt.show()

1次元ガウス分布

  N 個のサンプル  m_n を平均パラメータとして用いたガウス分布  \mathcal{N}(x \mid m_n, s) を色付けした曲線として描画します。

 以上で、基本的な確率分布の生成の処理を確認しました。続いて、生成分布のサンプルとサンプル分布の関係を図で確認します。

サンプルとパラメータの対応関係

 生成分布とサンプル分布の対応関係を図で表します。

・作図コード(クリックで展開)

# カラーマップを作成:(配色の共通化用)
cmap = plt.get_cmap('tab10') # カラーマップを指定
color_num = 10               # カラーマップの色数を設定

# ガウス分布からガウス分布の生成を作図
fig, axes = plt.subplots(
    nrows=2, ncols=1, constrained_layout=True, 
    figsize=(12, 9), dpi=100, facecolor='white'
)

# 生成分布を描画
ax = axes[0]
ax.plot(
    m_vec, gen_dens_vec, 
    color='black', linewidth=1.0, 
    label=f'$\\mu = {mu}, \\sigma = {sigma}$', 
    zorder=1
) # 生成分布

for n in range(N):
    
    # 値を取得
    m = m_n[n] # サンプル
    smp_dens_vec = smp_dens_lt[n] # 確率密度
    color_tp = cmap(n%color_num) # 色

    # 生成分布を描画
    ax = axes[0]
    ax.axvline(
        x=m, 
        color=color_tp, linewidth=1.0, linestyle='--', 
        zorder=0
    ) # サンプルの位置
    ax.scatter(
        x=m, y=0.0, 
        color=color_tp, s=50, 
        zorder=2
    ) # サンプル

    # サンプル分布を描画
    ax = axes[1]
    ax.axvline(
        x=m, 
        color=color_tp, linewidth=1.0, linestyle='--', 
        zorder=0
    ) # サンプルとの対応
    ax.plot(
        x_vec, smp_dens_vec, 
        color=color_tp, linewidth=1.0, 
        label=f'$m_{{{n+1}}} = {m:.2f}, s = {s}$', 
        zorder=1
    ) # サンプル分布

# 生成分布を装飾
ax = axes[0]
ax.set_xlabel('$m$') # m軸ラベル
ax.set_ylabel('$p(m \\mid \\mu, \\sigma^2)$') # 確率密度軸ラベル
ax.set_title('Gaussian distribution', fontsize=20)
ax.legend(title='generator', prop={'size': 8}, loc='upper left')
ax.grid()
ax.set_xlim(xmin=m_min, xmax=m_max) # (軸の対応用)

# 第2軸を設定
ax2 = ax.twiny() # 2軸用のオブジェクトを取得
ax2.set_xticks(ticks=m_n, labels=[f'$m_{{{n+1}}}$' for n in range(N)]) # サンプルラベル
ax2.set_xlim(xmin=x_min, xmax=x_max) # (軸の対応用)

# サンプル分布を装飾
ax = axes[1]
ax.set_xlabel('$x$') # x軸ラベル
ax.set_ylabel('$p(x \\mid m, s^2)$') # 確率密度軸ラベル
ax.set_title('Gaussian distribution', fontsize=20)
ax.legend(title='sample', prop={'size': 8}, loc='upper left')
ax.grid()
ax.set_xlim(xmin=x_min, xmax=x_max) # (軸の対応用)

# 第2軸を設定
ax2 = ax.twiny() # 2軸用のオブジェクトを取得
ax2.set_xticks(ticks=m_n, labels=[f'$m_{{{n+1}}}$' for n in range(N)]) # サンプルラベル
ax2.set_xlim(xmin=x_min, xmax=x_max) # (軸の対応用)

plt.show()

1次元ガウス分布の乱数と1次元ガウス分布の関係

 生成分布(ガウス分布)のサンプル  m_n とサンプル分布(ガウス分布)の期待値(平均パラメータ)  \mathbb{E}[x] = m_n が一致するのを確認できます。

 以上で、基本的な確率分布の生成の処理を確認しました。

スポンサードリンク

ハイパーパラメータの影響

 次は、生成分布のパラメータ(ハイパーパラメータ・超パラメータ)の値を少しずつ変化させて、生成分布とサンプル分布のグラフの変化をアニメーションで確認します。
 作図コードについては「Probability-Distribution/code/gaussian/generate_gaussian.py at main · anemptyarchive/Probability-Distribution · GitHub」を参照してください。

ハイパーパラメータとサンプル分布の関係

 生成分布(ガウス分布)  \mathcal{N}(m \mid \mu, \sigma) における累積確率が等間隔になるように  N 個のパラメータ(サンプル)  m_n を作成し、それぞれを平均パラメータとする  N 個のサンプル分布(ガウス分布)  \mathcal{N}(x \mid m_n, s) を描画して、ハイパーパラメータを変化させます。

 平均パラメータ  \mu を変化させたときのガウス分布の形状の変化をアニメーションにします。

  \mu の値に応じて、 m_n の期待値  \mathbb{E}[m] = \mu が変化するので、 \mu の値の付近に集中するようにサンプル  m_n が変化するのが分かります。
 それに対応して、各サンプル分布の  x の期待値  \mathbb{E}[x] = m_n が変化するので、サンプル分布の中心の位置(山全体)も変化します。

 標準偏差パラメータ  \sigma による変化をアニメーションにします。

  \sigma が大きくなるほど、 m_n の分散  \mathbb{V}[m] = \sigma^2 が大きくので、 m_n の散らばり具合が大きくなるのが分かります。
 それに対応して、各サンプル分布の  x の期待値  \mathbb{E}[x] = m_n が変化するので、サンプル分布の中心の位置(山全体)の散らばり具合も大きくなります。

 以上で、ハイパーパラメータの影響を確認しました。

 この記事では、1次元のガウス分布から1次元ガウス分布を生成しました。

参考文献

おわりに

  • 2025.12.27:『1次元ガウス分布の作図』から記事を独立して、加筆修正しました。

 初稿時にはアニメーション化できなかったので、今回の修正で満足のいく図を作れてよかったです。

 2025年12月27日は、カントリー・ガールズとJuice=Juiceの元メンバーの稲場愛香さんの28歳のお誕生日です。

 器用に何でもできる方なのでもっといろんなメディアで活躍している姿が見たいですっ!
 ここには今年リリースされたシングル曲のMVを貼りましたが、「初恋サイダー」の歌唱動画とかもみてください。よろしくお願いします。
 がんばりまなかん♪

【次の内容】

www.anarchive-beta.com