EconMLで実践する ビジネス因果推論
(第8回)
手法を使い分ける
(メタラーナー4種とLinearDMLを同じデータで比べる)

EconMLで実践する ビジネス因果推論(第8回)手法を使い分ける(メタラーナー4種とLinearDMLを同じデータで比べる)

EconMLには SLearner、TLearner、XLearner、DRLearner……と手法が並んでいます。「結局どれを使えばいいのか」。いちばん多い質問です。

今回は事例を変えて、BtoB法人営業の「重点フォロー」を扱います。フォローを実施した企業が全体の8%しかないデータで、5つの手法を同じ物差しで並べます。

結論を先に3行で書きます。

  1. 同じデータ・同じ機械学習モデルで5手法を並べると、平均の効果は5つとも正解の近く(47〜56万円、正解47万円)です。差が出るのは「誰に効くか」の精度と、信頼区間を出せるかどうかです。
  2. 処置群8%で最も崩れたのは TLearner(正解との相関0.72)。DRLearner は0.93、LinearDML は0.99でした。処置群を50%に増やしても TLearner は直りません。弱点は「2つのモデルの誤差が引き算で残る」ことです。
  3. 迷ったら DRLearner か LinearDML。ある4つの問いに答えれば決まります。

この記事を読み終えると、次のことができるようになります。

  • 5つの手法を同じデータに当てて、同じ物差しで比べられる
  • 各手法が「何をしているか」を1行で言える
  • 処置群が少ないときに崩れる手法を避けられる
  • 4つの問いで、自分の案件に合う手法を選べる

事例とデータ:重点フォローは契約金額を増やしたのか

法人営業6,000社のうち476社(8%)に、担当者が訪問頻度を上げる「重点フォロー」を実施しました。実施した企業の今年度契約金額は未実施の1.9倍。

ただし現場は大口・A担当の企業にフォローを集中させています。第4回で見た交絡そのものです。

データは btob_follow.csv。真の効果を仕込んであります。

以下からダウンロードできます。

btob_follow.csv

列 意味 役割
size_class 従業員規模(1〜4) 効果修飾 X
industry 業種(製造/卸売/サービス/IT) 効果修飾 X
years 取引年数 効果修飾 X
rep_rank 担当者ランク(1〜3) 交絡 W
last_year_sales 前年度の契約金額(万円) 交絡 W
follow 重点フォロー実施(0/1) 施策 T
sales 今年度の契約金額(万円) 成果 Y
_true_cate 仕込んだ真の効果(万円) 答え合わせ用

 

まず、動かしてみる:5手法を同じ条件で並べる

中で使う機械学習モデルは、5手法とも同じ勾配ブースティングにそろえます。手法ごとに引数の名前が違うので、そこだけ注意してください。

以下、コードです。

import numpy as np
import pandas as pd
from sklearn.ensemble import (
    GradientBoostingRegressor, 
    GradientBoostingClassifier
)
from econml.metalearners import (
    SLearner, 
    TLearner, 
    XLearner
)
from econml.dr import DRLearner
from econml.dml import LinearDML

# データの読み込み
df = pd.read_csv("btob_follow.csv")

# 変数の定義
Y = df["sales"]
T = df["follow"]
X = pd.DataFrame({
    "size_class":      
        df["size_class"],
    "industry":        
        df["industry"].map({"製造":0,"卸売":1,"サービス":2,"IT":3}),
    "years":           
        df["years"],
    "rep_rank":        
        df["rep_rank"],
    "last_year_sales": 
        df["last_year_sales"],
})

# フォロー実施率と、単純比較の差を計算
naive = Y[T == 1].mean() - Y[T == 0].mean()
print(f"フォロー実施率: {T.mean():.1%}  単純比較の差: {naive:.0f}万円")

# 5手法とも、中の機械学習モデルは同じ勾配ブースティングにそろえる
reg = lambda: GradientBoostingRegressor(random_state=0)
clf = lambda: GradientBoostingClassifier(random_state=0)
models = {
    "SLearner":  
        SLearner(overall_model=reg()),
    "TLearner":  
        TLearner(models=reg()),
    "XLearner":  
        XLearner(
            models=reg(), 
            propensity_model=clf()
        ),
    "DRLearner": 
        DRLearner(
            model_regression=reg(), 
            model_propensity=clf(),
            cv=5, random_state=0
        ),
    "LinearDML": 
        LinearDML(
            model_y=reg(), 
            model_t=clf(), 
            discrete_treatment=True,
            cv=5, random_state=0
        ),
}

# 各手法のATEを推定
for name, est in models.items():
    est.fit(Y, T, X=X)
    df[name] = est.effect(X)
    print(f"{name:<10} 推定ATE {df[name].mean():5.1f}万円")

 

以下、実行結果です。

フォロー実施率: 7.9%  単純比較の差: 435万円
SLearner   推定ATE  46.7万円
TLearner   推定ATE  56.0万円
XLearner   推定ATE  53.1万円
DRLearner  推定ATE  51.7万円
LinearDML  推定ATE  51.5万円

 

単純比較の435万円が、どの手法でも47〜56万円まで落ちました。平均の効果だけなら、5手法の差は小さい。

1つ気づいてほしいのは、X に交絡(rep_rank、last_year_sales)も入れていることです。メタラーナー3種の fit には W の引数がありません。交絡も X に入れるのが、第4回の仕分けをメタラーナーで守る方法です。

 

答え合わせ:差が出るのは「誰に効くか」

6,000社分の効果を正解と突き合わせます。区間を出せるのは DRLearner と LinearDML だけです。

以下、コードです。

# 正解のATE
truth = df["_true_cate"]

# 正解のATEとの比較
print(
    f"正解のATE {truth.mean():.1f}万円   "
    f"正解のばらつき {truth.std():.1f}万円"
)
# 各手法の正解との相関と誤差
for name in models:
    corr = df[name].corr(truth)
    rmse = np.sqrt(((df[name] - truth) ** 2).mean())
    print(
        f"{name:<10} 正解との相関 {corr:.3f}   誤差 {rmse:5.1f}万円  "
        f"ばらつき {df[name].std():5.1f}万円"
    )
# 各手法のATEの95%区間
for name in ["DRLearner", "LinearDML"]:
    lo, hi = models[name].ate_interval(X, alpha=0.05)
    print(f"{name:<10} 推定ATEの95%区間 [{lo:.1f}, {hi:.1f}]")

 

以下、実行結果です。

正解のATE 47.4万円   正解のばらつき 33.8万円
SLearner   正解との相関 0.848   誤差  18.0万円   ばらつき  28.2万円
TLearner   正解との相関 0.717   誤差  31.6万円   ばらつき  43.5万円
XLearner   正解との相関 0.794   誤差  26.2万円   ばらつき  42.1万円
DRLearner  正解との相関 0.927   誤差  17.3万円   ばらつき  42.4万円
LinearDML  正解との相関 0.986   誤差   7.0万円   ばらつき  32.7万円
DRLearner  推定ATEの95%区間 [24.2, 79.2]
LinearDML  推定ATEの95%区間 [43.3, 59.7]
5手法の推定ATEと正解との相関(フォロー実施率8%)正解のATEは47.4万円。SLearnerはATE46.7万円・相関0.848、TLearnerはATE56.0万円・相関0.717、XLearnerはATE53.1万円・相関0.794、DRLearnerはATE51.7万円・相関0.927、LinearDMLはATE51.5万円・相関0.986。95%区間はDRLearner[24.2, 79.2]とLinearDML[43.3, 59.7]だけが出せる。同じデータ・同じ機械学習モデルで、5手法を並べる(フォロー実施率8%)n=6,000社、フォロー実施 476社。左:推定ATEと95%区間(出せる手法だけ)。右:6,000社分の効果と正解の相関20406080推定ATE(万円)正解 47.4万円0.60.70.80.91.0正解との相関(1に近いほど良い)SLearner区間なし46.70.848誤差(RMSE) 18万円TLearner区間なし56.00.717誤差(RMSE) 32万円XLearner区間なし53.10.794誤差(RMSE) 26万円DRLearner[24, 79]51.70.927誤差(RMSE) 17万円LinearDML[43, 60]51.50.986誤差(RMSE) 7万円点推定は5手法とも正解の近く。差が出るのは「誰に効くか」の精度と、区間を出せるかどうか

順位は TLearner < XLearner < SLearner < DRLearner < LinearDML。SLearner は相関こそ悪くないものの、効果のばらつきが28万円と正解の34万円より小さく、効く企業と効かない企業の差を縮めています。DRLearner の区間は幅55万円と広く、処置群476社という薄さを正直に映しています。

 

処置群を増やすと、どの手法が直るか

同じ企業属性・同じ真の効果のまま、フォロー実施率だけを50%にしたデータでも動かしました。

フォロー実施率8%と50%での正解との相関の比較SLearnerは8%で0.848・50%で0.872、TLearnerは8%で0.717・50%で0.709、XLearnerは8%で0.794・50%で0.946、DRLearnerは8%で0.927・50%で0.985、LinearDMLは8%で0.986・50%で0.987。処置群が少ないと、どの手法が崩れるか:実施率8%と50%で比べる同じ企業属性・同じ真の効果で、フォローの実施率だけを変えたデータ。棒は「効果と正解の相関」0.60.70.80.91.0正解との相関0.850.87SLearner+0.020.720.71TLearnerほぼ同じ0.790.95XLearner+0.150.930.98DRLearner+0.060.990.99LinearDMLほぼ同じ実施率8%(476社)実施率50%(2,962社)X と DR は処置群が増えると大きく改善。T は増えても直らない(弱点は基礎モデルの誤差)

XLearner は0.79から0.95へ、DRLearner は0.93から0.99へ大きく改善します。ところが TLearner は0.72から0.71で、処置群が6倍に増えても直りません。弱点は処置比率そのものではなく、次に説明する仕組みにあります。

 

裏で何が起きているのか:5手法を1行ずつ

SLearnerは、施策 T を特徴量の1つにして1本のモデルを作り、「T=1 の予測 − T=0 の予測」を効果とします。安定ですが、T はたくさんある特徴量の1つにすぎず、影響が薄まって効果が縮みます。

TLearnerは、処置群と対照群で別々のモデルを作り、予測の差を効果とします。2本のモデルはそれぞれ別の場所で近似を誤り、その誤差が引き算でそのまま残ります。試しに中のモデルを線形回帰にすると相関は0.98に上がります。このデータは売上も効果も直線だからで、メタラーナーの精度は、中のモデルの精度そのものです。

XLearnerは、T の2本のモデルに加えて「もし逆の群だったら」の代理値を作り、傾向スコア(第2回)で重み付けして合成します。処置群が少ないとき、対照群の情報を借りられます。

DRLearnerは、成果の回帰モデルと傾向スコアの2本を組み合わせ、どちらか一方が当たっていれば正しい答えに近づく設計です。二重頑健(Doubly Robust)の名前はここから来ています。たとえるなら命綱を2本かけている状態です。

LinearDMLは第2回のとおり、効果が X に対して直線と仮定する代わりに区間が狭い。仮定が正しいこのデータでは最強でした。

DRLearner と LinearDML が強い理由は共通しています。第2回の交差適合と直交化によって、中のモデルの誤差が効果の推定に入りにくい。メタラーナーにはこの仕掛けがありません。

 

手法を選ぶ4つの問い

ここまでを1枚にしたのが以下の図です。上から順に答えてください。

手法を選ぶ4つの問いのフローチャートQ1 施策が2値でなければDML系。Q2 信頼区間が要るならDRLearnerかLinearDML。Q3 処置群が少なければXLearnerかDRLearner。Q4 効果の形が単純ならLinearDML、不明ならCausalForestDML。メタラーナーは交絡もXに入れる。手法を選ぶ4つの問い:上から順に答えるこの連載で扱った手法の範囲での目安。迷ったら DRLearner か LinearDML から始めるQ1施策は「やる/やらない」の2値か?いいえDML系(LinearDML・CausalForestDML)回数・金額など連続量の施策。第10回で扱うはいQ2区間を意思決定に使うか?はいDRLearner か LinearDMLS・T・X は区間を出せない(要ブートストラップ)いいえQ3処置群が少ないか?(10%未満)はいXLearner か DRLearnerTLearner は避ける。処置群のモデルが薄くなるいいえQ4効果の形が単純と分かっているか?はい/いいえ単純 → LinearDML / 不明 → CausalForestDML第5回の結論。因果フォレストで当たりをつけ、単純なら直線へメタラーナー(S・T・X)に共通の注意:W を分けて渡せないので、交絡も X に入れる中の機械学習モデルの誤差がそのまま効果の誤差になる。DR・DML は交差適合と直交化でその影響を小さくしている

連続量の施策(訪問回数や値引き額)はメタラーナーでは扱えず、DML系になります(第10回)。迷ったら DRLearner か LinearDML から始めれば、大きく外しません。

 

ありがちな失敗

1つ目:手法を変えて、都合のいい数字を採用する。 今回の推定ATEは46.7〜56.0万円の幅がありました。5つ動かして最大の56.0万円を報告すれば、それは分析ではなく選択です。手法は動かす前に決める。複数出すなら全部見せる。これが第9回のレビューで最初に問われる点です。

2つ目:メタラーナーに効果修飾変数だけを渡す。 第3回・第5回の流れで X を「効く変数」だけにすると、交絡が消えます。

以下、コードです。

# 効果修飾変数だけ(交絡を外す)
X_only = X[["size_class", "industry", "years"]] 

# 交絡を外したATEの推定
for name in ["SLearner", "TLearner", "XLearner"]:
    models[name].fit(Y, T, X=X_only)
    print(
        f"{name:<10} 交絡を外した推定ATE "
        f"{models[name].effect(X_only).mean():6.1f}万円"
    )

 

以下、実行結果です。

SLearner   交絡を外した推定ATE  142.0万円
TLearner   交絡を外した推定ATE  136.0万円
XLearner   交絡を外した推定ATE  133.7万円

 

正解47万円の3倍です。エラーは出ません。DRLearner と LinearDML は X=修飾変数, W=交絡 と分けて渡しても51.7万円のままでした。メタラーナーは、X に交絡も入れる。これだけは忘れないでください。

 

まとめ

今回のポイントです。

  • 平均の効果は5手法とも正解の近く。差が出るのは「誰に効くか」の精度と、区間を出せるか
  • TLearner は2本のモデルの誤差が引き算で残る。処置群を増やしても直らない。メタラーナーの精度は中のモデルの精度
  • DRLearner と LinearDML は交差適合と直交化で中のモデルの誤差に強く、区間も出る
  • 4つの問い:2値か/区間が要るか/処置群が少ないか/効果の形が単純か。迷ったら DRLearner か LinearDML
  • メタラーナーは W を分けられない。交絡も X に入れる。手法は動かす前に決める
Screenshot

【月1 特定テーマ講座(10月)】
Python で学ぶ 明日からできる「欠損値処理」超入門

【開催日時】 全2回(土)2026/10/17,10/31(13:30〜18:00)
【受講形式】 当日Zoom( or 復習用に後日動画視聴)
【参加費用】 2万2千円(税込み)/人