【Python】シグモイド関数で年齢データから購入確率をフィッティングする

■概要

シグモイド関数は、入力値を (-∞, ∞) から (0, 1) の範囲に変換する関数であり、ロジスティック回帰など「ある事象が起きる確率」を予測するモデルの基本となる関数である。
今回は、年齢と商品の購入有無(0:未購入, 1:購入)のサンプルデータに対してシグモイド関数をフィッティングし、年齢から「購入する確率」を予測できるようにする処理を実装する。

■実装するサンプル処理の概要

以下に今回実装する処理概要を記載する。

  • シグモイド関数 sigmoid(x, a, b) を定義(パラメータ a:傾き、b:中心位置)
  • CSVファイル(age, buy)を読み込み、転置してage列・buy列を持つテーブルに変換
  • age列・buy列をNumPy配列として取得
  • scipy.optimize.curve_fitで実データにシグモイド関数をフィッティングし、最も当てはまりの良いパラメータ a, b を算出
  • フィッティング曲線描画用のx軸データを生成
  • 実データを散布図として描画
  • フィッティングしたシグモイド曲線を描画
  • グラフを装飾(タイトル・軸ラベル・凡例・グリッド)して表示

なお使用するデータは以下とする。

・./sigmoid_data/sigmoid_data.csv

age,10,12,13,23,27,31,33,42,47,50,59,65,66,78,79,80,85
buy,0,0,0,0,1,0,0,0,1,1,1,1,1,0,1,1,1

■フローチャート

以下に今回実装する処理のフローチャートを示す。

flowchart TD
    A([開始]) --> B["シグモイド関数 sigmoid:x, a, b を定義"]
    B --> C["CSVファイルを読み込む<br/>sigmoid_data.csv"]
    C --> D["age列・buy列を<br/>NumPy配列として取得"]
    D --> E["curve_fitで実データに<br/>シグモイド関数をフィッティング<br/>パラメータ a, b を算出"]
    E --> F["フィッティング曲線描画用の<br/>x軸データを生成"]
    F --> G[実データを散布図として描画]
    G --> H[フィッティング曲線を描画]
    H --> I["グラフを装飾<br/>タイトル・軸ラベル・凡例・グリッド"]
    I --> J[グラフを表示]
    J --> K([終了])

■サンプルコード

以下に今回実装するサンプルコードを示す。

・sigmoid_func.py

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.optimize import curve_fit


def sigmoid(x, a, b):
    """
    シグモイド関数
    x を (-∞, ∞) の範囲から (0, 1) の範囲に変換する関数。
    ロジスティック回帰では、この (0, 1) の出力値を「購入する確率」とみなす。

    a: カーブの傾き(大きいほど境目で急に立ち上がる)
    b: カーブの中心位置(左右にずらすオフセット)
    """
    return 1 / (1 + np.exp(-a * (x - b)))


# CSVを読み込む
# 1行目:「age」ラベル + 年齢の値が横並び
# 2行目:「buy」ラベル + 購入有無(0:未購入, 1:購入)が横並び
# → 先頭列をインデックスとして読み込み、転置(.T)することで
#   「age列」「buy列」を持つ縦持ちのテーブルに変換する
input_data = pd.read_csv('sigmoid_data/sigmoid_data.csv', header=None, index_col=0).T

# 年齢(説明変数)と購入有無(目的変数)を取り出す
ages = input_data['age'].to_numpy(dtype=float)
buys = input_data['buy'].to_numpy(dtype=float)

# 実データにシグモイド関数をフィッティングし、
# 最も当てはまりの良いパラメータ a, b を求める
(param_a, param_b), _ = curve_fit(sigmoid, ages, buys, p0=[1.0, np.mean(ages)])

# フィッティングしたシグモイド曲線を描画するためのx軸データを作成
x_line = np.linspace(ages.min() - 5, ages.max() + 5, 300)
y_line = sigmoid(x_line, param_a, param_b)

# 実データ(散布図)を描画
plt.scatter(ages, buys, color='navy', label='actual data (0:not purchased, 1:purchased)')

# フィッティングしたシグモイド曲線を描画
plt.plot(x_line, y_line, color='crimson', label=f'sigmoid fit (a={param_a:.2f}, b={param_b:.2f})')

# グラフの装飾
plt.title('Sigmoid Function Fit: Age vs Purchase')
plt.xlabel('age')
plt.ylabel('purchase probability')
plt.ylim(-0.1, 1.1)
plt.grid(True)
plt.legend()

# グラフの表示
plt.show()

■実行結果

上記コードを実行すると、curve_fitにより以下のパラメータが算出される。

a = 4.39
b = 44.52

算出されたパラメータをもとに描画されるグラフでは、44歳付近を境に購入確率が0から1へ急激に立ち上がるS字カーブが確認できる。
実データの散布図(navy色の点)とフィッティングされたシグモイド曲線(crimson色の線)が重なって表示され、年齢が上がるにつれて購入確率が高くなる傾向にモデルがよく当てはまっていることがわかる。

コメント

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