Machine Learning: ロジスティック回帰 — 分類とECユーザー行動予測の入門ガイド

最終更新:2026-08-26

ロジスティック回帰は実は「回帰」ではありません。確率を出力する強力な分類器です。

1. この章で学ぶこと


2. SaaS運営の実例

(1) 課題:解約の発見が遅れ、取り戻すコストが高い

Aliceは月間アクティブユーザー5万人、月間解約率8%のSaaSプラットフォームを運営しています。つまり毎月4,000人のユーザーが流失していることになります。1ユーザーあたりの年間価値は約2,000ドルなので、月間の損失は約67万ドルに達します。問題は、ユーザーが解約した時点で手遅れであり、取り戻しの成功率は5%未満という点です。

(2) ロジスティック回帰による解決策

ロジスティック回帰を使えば、ユーザーの行動に警告シグナルが現れた時点で解約確率を予測でき、2〜4週間前の早期警告が可能になります。これにより、取り戻しの成功率を30%まで引き上げることができます。

PYTHON
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

model = LogisticRegression(class_weight="balanced")
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names=["Retained", "Churned"]))

(3) 効果:救った顧客1人あたり2,000ドルの価値

ロジスティック回帰を活用して、Aliceは解約リスクの高いユーザーを事前に特定し、毎月1,200人のユーザーを引き留めています。これにより年間約240万ドルの収益増加につながります。既存顧客の取り戻しコストは約50ドルで、新規顧客の獲得コスト500ドルと比べてはるかに低コストです。


3. 線形回帰からロジスティック回帰へ

(1) シグモイド関数

ロジスティック回帰では、シグモイド関数を使って線形出力を[0,1]の範囲に圧縮し、確率として扱います:$\sigma(z) = \frac{1}{1+e^{-z}}$

100%
graph LR
    INPUT[Input Features x] --> LINEAR[Linear Combination<br/>z = w·x + b]
    LINEAR --> SIGMOID[Sigmoid Function<br/>σ = 1/(1+e^(-z))]
    SIGMOID --> PROB[P(y=1) = σ]
    PROB --> DECISION{P ≥ 0.5?}
    DECISION -->|Yes| CLASS1[Class 1<br/>e.g. Churned]
    DECISION -->|No| CLASS0[Class 0<br/>e.g. Retained]

▶ サンプル:シグモイド関数の可視化

PYTHON
import numpy as np
import matplotlib.pyplot as plt

z = np.linspace(-8, 8, 100)
sigmoid = 1 / (1 + np.exp(-z))

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(z, sigmoid, linewidth=2, color="#2196F3")
ax.axhline(0.5, color="red", linestyle="--", alpha=0.5, label="Decision boundary")
ax.axvline(0, color="gray", linestyle="--", alpha=0.3)
ax.set_xlabel("z (linear combination)")
ax.set_ylabel("σ(z) = P(y=1)")
ax.set_title("Sigmoid Function")
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("sigmoid.png", dpi=150)

出力:

TEXT 📖 参照専用
# Executed successfully

(2) 交差エントロピー損失

ロジスティック回帰の損失関数は交差エントロピー(Log Loss)です:

$L = -\frac{1}{n}\sum[y\log(\hat{y}) + (1-y)\log(1-\hat{y})]$

正解ラベル 予測確率 損失 直感的な意味
y=1 ŷ=0.99 0.01 ペナルティはほぼなし
y=1 ŷ=0.5 0.69 中程度のペナルティ
y=1 ŷ=0.01 4.60 非常に大きなペナルティ
y=0 ŷ=0.01 0.01 ペナルティはほぼなし
y=0 ŷ=0.99 4.60 非常に大きなペナルティ

4. scikit-learnによるロジスティック回帰

▶ サンプル:二値分類 — ユーザーの購買意欲の予測

PYTHON
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import numpy as np

rng = np.random.default_rng(42)
n = 1000
X = rng.standard_normal((n, 4))  # [browsing_time, pages_viewed, cart_value, visit_count]
y = (X[:, 0] * 0.5 + X[:, 1] * 1.2 + X[:, 2] * 2.0 + rng.normal(0, 0.5, n) > 1.5).astype(int)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("model", LogisticRegression(random_state=42)),
])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
y_prob = pipe.predict_proba(X_test)[:, 1]  # Probability of class 1

print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"\nConfusion Matrix:\n{confusion_matrix(y_test, y_pred)}")
print(f"\nClassification Report:\n{classification_report(y_test, y_pred)}")
print(f"\nSample probabilities: {y_prob[:5].round(3)}")

出力:

TEXT 📖 参照専用
# Executed successfully

▶ サンプル:AliceのSaaSユーザー解約予測

PYTHON
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, precision_recall_fscore_support
import pandas as pd
import numpy as np

rng = np.random.default_rng(42)
n = 5000
df = pd.DataFrame({
    "tenure_months": rng.integers(1, 60, n),
    "monthly_usage_hours": rng.exponential(20, n),
    "support_tickets": rng.poisson(2, n),
    "payment_delay_days": rng.integers(0, 30, n),
    "plan_tier": rng.choice([1, 2, 3], n, p=[0.5, 0.35, 0.15]),
})

# Churn logic: short tenure + low usage + many tickets + delays
churn_score = (
    -0.05 * df["tenure_months"]
    - 0.1 * df["monthly_usage_hours"]
    + 0.5 * df["support_tickets"]
    + 0.1 * df["payment_delay_days"]
    + rng.normal(0, 1, n)
)
df["churned"] = (churn_score > 2).astype(int)
print(f"Churn rate: {df['churned'].mean():.1%}")

# Train with class_weight="balanced" for imbalanced data
X = df.drop(columns=["churned"])
y = df["churned"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

model = LogisticRegression(class_weight="balanced", max_iter=500, random_state=42)
model.fit(X_train, y_train)

y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, y_prob)
precision, recall, f1, _ = precision_recall_fscore_support(y_test, y_pred, average="binary")

print(f"AUC-ROC: {auc:.4f}")
print(f"Precision: {precision:.4f}, Recall: {recall:.4f}, F1: {f1:.4f}")

出力:

TEXT 📖 参照専用
# Executed successfully

5. 多クラス拡張

(1) One-vs-RestとSoftmaxの比較

▶ サンプル:多クラス分類 — 商品カテゴリの自動分類

PYTHON
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score

X, y = load_iris(return_X_y=True)

# One-vs-Rest (default)
ovr_model = LogisticRegression(multi_class="ovr", max_iter=200)
ovr_scores = cross_val_score(ovr_model, X, y, cv=5, scoring="accuracy")

# Softmax (Multinomial)
softmax_model = LogisticRegression(multi_class="multinomial", max_iter=200)
softmax_scores = cross_val_score(softmax_model, X, y, cv=5, scoring="accuracy")

print(f"One-vs-Rest:  {ovr_scores.mean():.4f} +/- {ovr_scores.std():.4f}")
print(f"Softmax:      {softmax_scores.mean():.4f} +/- {softmax_scores.std():.4f}")

出力:

TEXT 📖 参照専用
# Executed successfully
観点 One-vs-Rest Softmax(多項ロジスティック回帰)
原理 K個の二値分類器 1つの多クラス分類器
確率の較正 合計が1になる保証はない 厳密に合計が1になる
計算効率 並列化が可能 結合最適化が必要
適した場面 クラス数が多い場合 クラス数が少なく、確率が必要な場合

6. 分類指標とビジネスでの選択

(1) 混同行列とそこから導出される指標

▶ サンプル:ROC曲線とPR曲線

PYTHON
from sklearn.metrics import roc_curve, auc, precision_recall_curve
import matplotlib.pyplot as plt
import numpy as np

# Assume y_test and y_prob from previous example
rng = np.random.default_rng(42)
y_test = rng.choice([0, 1], 500, p=[0.85, 0.15])
y_prob = np.clip(y_test * 0.8 + rng.normal(0, 0.3, 500), 0, 1)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# ROC Curve
fpr, tpr, _ = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)
axes[0].plot(fpr, tpr, color="#2196F3", lw=2, label=f"AUC = {roc_auc:.3f}")
axes[0].plot([0, 1], [0, 1], "r--", alpha=0.5)
axes[0].set_xlabel("False Positive Rate")
axes[0].set_ylabel("True Positive Rate")
axes[0].set_title("ROC Curve")
axes[0].legend()

# PR Curve
precision_vals, recall_vals, _ = precision_recall_curve(y_test, y_prob)
axes[1].plot(recall_vals, precision_vals, color="#4CAF50", lw=2)
axes[1].set_xlabel("Recall")
axes[1].set_ylabel("Precision")
axes[1].set_title("Precision-Recall Curve")

plt.tight_layout()
plt.savefig("roc_pr_curves.png", dpi=150)

出力:

TEXT 📖 参照専用
# Executed successfully

(2) ビジネスシーンに合わせた指標の選び方

シナリオ 重視する指標 理由 閾値戦略
ユーザー解約予測 再現率 解約顧客の見逃しコストが高い 閾値を下げる(0.3)
スパムフィルタリング 適合率 正常なメールの誤検知は許容できない 閾値を上げる(0.7)
商品レコメンデーション F1スコア 適合率とカバレッジのバランスが必要 デフォルト(0.5)
不正検知 再現率 不正の見逃しコストが極めて高い 閾値を下げる(0.2)
📌 ポイント: 解約予測では、適合率よりも再現率が重要です。解約顧客を1人見逃すと2,000ドルの損失になりますが、継続顧客への誤ったアラートは取り戻しコスト50ドルの無駄で済みます。決定閾値を調整することで、ビジネス価値を最適化できます。


❓ よくある質問

Q なぜロジスティック回帰は「回帰」と呼ばれるのですか?
A 歴史的な理由です。回帰手法(線形結合)でモデル化しますが、出力はシグモイド関数を通ってクラス確率になります。本質的には分類アルゴリズムであり、名前はやや紛らわしいものです。
Q class_weight="balanced"とはどういう意味ですか?
A 各クラスの重みをその出現頻度の逆数で自動的に設定し、少数クラスにより高い重みを与えます。解約率8%の場合、解約クラスの重み = 1/0.08 = 12.5、継続クラスの重み = 1/0.92 = 1.09 となります。
Q 決定閾値は必ず0.5でなければなりませんか?
A そんなことはありません。0.5はあくまでデフォルト値であり、ビジネスシーンでは調整が必要なことがよくあります。解約予測では0.3に下げて再現率を高めたり、スパム検知では0.7に上げて適合率を高めたりします。ビジネスコストに基づいて閾値を決めましょう。
Q ROC曲線のAUCとPR曲線のAUC、どちらが良いですか?
A クラスが均衡している場合はROC曲線のAUCを、不均衡が大きい場合はPR曲線のAUCを見ます。解約予測(8% vs 92%)のようなケースでは、PR曲線のAUCが推奨されます。
Q ロジスティック回帰は非線形な関係を扱えますか?
A デフォルトでは扱えません。ただし、多項式特徴量(PolynomialFeatures)を追加すれば、非線形な決定境界を学習できます。これは本質的に、より高次元の空間で線形分類を行っているのと同じです。
Q ロジスティック回帰におけるL1正則化の利点は何ですか?
A 線形回帰と同じく、L1正則化はスパースな解を生成し、自動的な特徴量選択を行います。LogisticRegression(penalty="l1", solver="saga")でL1正則化を有効にできます。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):ロジスティック回帰を使ってIrisデータセットの多クラス分類を行い、accuracyとclassification_reportを出力してください。ヒント:LogisticRegression(max_iter=200) + classification_report
  2. 応用(難易度 ⭐⭐):不均衡データセット(95:5)をシミュレートし、デフォルトのロジスティック回帰とclass_weight="balanced"の再現率を比較してください。ヒント:make_classification(weights=[0.95, 0.05])を使用します。
  3. 発展(難易度 ⭐⭐⭐):Aliceの解約予測パイプラインを完全に実装してください。SaaSユーザーのシミュレーションデータを生成し、ロジスティック回帰モデルを訓練し、ROC曲線/PR曲線を描画し、異なる閾値での再現率/適合率/F1スコアを計算して、ビジネス最適な閾値を見つけてください。ヒント:roc_curve + precision_recall_curve + 閾値の反復処理。

← 前へ:線形回帰 | 次へ:決定木とランダムフォレスト →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%