機械学習モデルを訓練データで完璧に仕上げても、いざ本番環境に投入すると性能がガクッと落ちる——よくある失敗です。その大きな原因の一つが 共変量シフト(covariate shift)、つまり「訓練データと本番データで入力の分布が違う」という問題です。
たとえば、ある地域・季節で集めたデータで学習したモデルを、別の地域・季節に適用する。あるいは、過去のユーザー層で学習したモデルを、新しいユーザー層に使う。こうした場面では入力分布がずれており、訓練時に最適化したモデルが本番でうまく働きません。この記事では、この共変量シフトを重要度重み付け(importance weighting)で補正する方法を、理論から実装まで解説します。
具体的には次の問いに答えます。
- 問い1: 入力分布がずれると、なぜモデルの性能が落ちるのか?
- 問い2: 訓練データしか手元にないのに、本番分布での性能を改善するにはどうすればよいか?
共変量シフトの補正は、ドメイン適応・転移学習の基礎であり、転移学習の負の転移で見た「ドメイン間距離」を実際に縮める具体的な道具にもなります。

まず全体像です。図のように、訓練データの入力分布 $p_{train}(x)$(青)と本番データの入力分布 $p_{test}(x)$(オレンジ)がずれているのが共変量シフトです。モデルは青の領域で学習しますが、本番ではオレンジの領域で使われます。この「学習した場所」と「使われる場所」のズレが、性能劣化を生みます。
前提知識
この記事は確率分布と期待値、線形回帰の基礎を前提にします。関連して以下も参考になります。
共変量シフトとは
共変量シフトは、次のように定義されます。

図のように、入力分布は変わる($p_{train}(x) \neq p_{test}(x)$)が、入力から出力への関係は変わらない($p_{train}(y\mid x) = p_{test}(y\mid x)$)——これが共変量シフトです。「世界のルール($y$ と $x$ の関係)は同じだが、どんな $x$ が来るかの頻度が変わった」という状況です。
たとえば「気温から電力需要を予測する」モデルで、気温→需要の関係(物理)は同じでも、観測される気温の分布が夏と冬で違う、というのが共変量シフトです。$p(y\mid x)$ まで変わる場合は、より一般的な「概念ドリフト」になり、共変量シフトの枠を超えます。
共変量シフトは至るところで起きます。医療では、ある病院の患者データで学習したモデルを別の病院に適用すると、患者層の違いで入力分布がずれます。推薦システムでは、過去のユーザー行動で学習したモデルが新規ユーザー層で劣化します。センサー機器では、設置環境や個体差で観測値の分布が変わります。いずれも「$y$ と $x$ の関係(病気の機序、嗜好の論理、物理法則)は同じでも、観測される $x$ の分布が変わった」という共変量シフトです。逆に言えば、関係そのものが変わっていない限り、適切な補正で本番性能を取り戻せる余地がある、ということでもあります。
なぜ問題になるのか
「$p(y\mid x)$ が同じなら、モデルも同じでいいのでは?」と思うかもしれません。モデルが正しく特定されている(真の関係を表現できる)なら、その通りです。問題は、現実のモデルがたいてい誤特定されている(真の関係を完全には表現できない)ことにあります。

図を見てください。真の関係(黒)は非線形なのに、線形モデルで近似しているとします。訓練領域(青、$x\approx0$)で最もよく当てはまる直線を引くと、その直線は本番領域(オレンジ、$x\approx3$)では真の関係から大きくずれてしまいます。モデルが真の関係を完全に表現できないとき、「どの領域のデータを重視して当てはめるか」が結果を左右し、訓練分布で最適化した近似は本番分布では最適でなくなるのです。
この問題を、訓練データだけを使って補正するのが重要度重み付けです。
重要度重み付けの理論
私たちが本当に小さくしたいのは、本番分布での期待リスクです。
$$ R_{test}(\theta) = \mathbb{E}_{p_{test}(x,y)}\big[\ell(f_\theta(x), y)\big] $$
しかし手元にあるのは訓練データだけです。ここで共変量シフトの仮定($p(y\mid x)$ が共通)を使うと、本番リスクを訓練分布での期待値に書き換えられます。
$$ \begin{align} R_{test}(\theta) &= \iint \ell(f_\theta(x), y)\, p_{test}(x)\, p(y\mid x)\, dx\, dy \\ &= \iint \ell(f_\theta(x), y)\, \frac{p_{test}(x)}{p_{train}(x)}\, p_{train}(x)\, p(y\mid x)\, dx\, dy \\ &= \mathbb{E}_{p_{train}(x,y)}\big[\, w(x)\, \ell(f_\theta(x), y)\,\big] \end{align} $$
2行目では、分母分子に $p_{train}(x)$ を掛けただけです。最後の行で現れた
$$ \begin{equation} w(x) = \frac{p_{test}(x)}{p_{train}(x)} \end{equation} $$
が重要度重み(importance weight)です。この式が意味するのは、訓練データに重み $w(x)$ を掛けて期待値をとれば、本番分布での期待リスクが計算できるということ。つまり訓練データだけで本番性能を評価・最適化できるのです。

重み $w(x) = p_{test}(x)/p_{train}(x)$ の形を図で見ましょう。本番で多く現れるのに訓練では少ない領域(図の右側)で重みが大きくなり、逆に訓練で多い領域では重みが小さくなります。「本番で重要なのに訓練では軽視されていたサンプル」を持ち上げる、という直感そのものです。
実際の学習では、この重みを掛けた重み付き経験リスクを最小化します。

図の式のように、各訓練サンプルの損失に重み $w(x_i)$ を掛けて平均をとり、それを最小化します。重みの大きいサンプル(本番で重要な領域)を重視してモデルを当てはめるので、本番分布に適したモデルが得られます。
この重み付き経験リスクは、本番期待リスク $R_{test}(\theta)$ の不偏推定量になっています。先ほど導いた期待値の変換 $\mathbb{E}_{p_{train}}[w(x)\,\ell] = R_{test}$ がそのまま成り立つためです。つまり、訓練データを重み付けて平均するだけで、本番性能を偏りなく見積もれる——これが重要度重み付けの理論的な強みです。残る問題は「重み $w(x)$ をどう推定するか」です。
重みの推定
重み $w(x) = p_{test}(x)/p_{train}(x)$ を求めるには、2つの密度を別々に推定して割り算すればよさそうですが、これは悪手です。高次元では密度推定そのものが難しく、しかも推定誤差が分母の割り算で大きく増幅されます。たとえば $p_{train}(x)$ をわずかに小さく見積もっただけで、$w$ は大きく跳ね上がってしまいます。そこで、2つの密度を個別に求めるのではなく、その比 $w(x)$ だけを直接推定する手法が好まれます。比は密度そのものより滑らかで推定しやすいことが多く、誤差の増幅も避けられます。
確率分類器による推定
最も手軽なのが、訓練データと本番データを見分ける分類器を使う方法です。

図のように、訓練データにラベル0、本番データにラベル1を付けて分類器を学習します。ベイズの定理から、その分類確率 $P(\text{test}\mid x)$ を使って密度比が得られます。
$$ w(x) = \frac{p_{test}(x)}{p_{train}(x)} \propto \frac{P(\text{test}\mid x)}{P(\text{train}\mid x)} = \frac{P(\text{test}\mid x)}{1 – P(\text{test}\mid x)} $$
密度を直接推定せず、「訓練か本番かを当てる確率」のオッズだけで重みが求まる、という巧妙な方法です。ロジスティック回帰など任意の確率分類器が使えます。
なぜオッズが密度比になるのか、ベイズの定理で確かめましょう。$P(\text{test}\mid x) = p(x\mid\text{test})P(\text{test})/p(x)$、$P(\text{train}\mid x) = p(x\mid\text{train})P(\text{train})/p(x)$ なので、その比は
$$ \frac{P(\text{test}\mid x)}{P(\text{train}\mid x)} = \frac{p_{test}(x)}{p_{train}(x)}\cdot\frac{P(\text{test})}{P(\text{train})} $$
となります。訓練と本番を同数ずつ集めれば $P(\text{test})/P(\text{train})=1$ なので、分類確率のオッズがそのまま密度比 $w(x)$ に比例します。「2つの分布を見分ける問題」を解くだけで、その副産物として密度比が得られる、というのがこの方法の美点です。
Kernel Mean Matching(KMM)
もう一つの代表的手法が Kernel Mean Matching(KMM) です。これは密度比を陽に推定せず、「重み付けした訓練データの分布が、本番データの分布に一致するように重みを決める」というアプローチです。

図のように、KMMは再生核ヒルベルト空間(RKHS)において、重み付き訓練データの特徴平均と本番データの特徴平均が一致するよう重みを最適化します。
$$ \min_{\bm{w}} \left\| \frac{1}{n}\sum_{i=1}^{n} w_i\, \phi(x_i^{tr}) – \frac{1}{m}\sum_{j=1}^{m} \phi(x_j^{te}) \right\|_{\mathcal{H}}^2 \quad \text{s.t.}\quad w_i \in [0, B],\ \left|\frac{1}{n}\sum_i w_i – 1\right| \leq \epsilon $$
$\phi$ はカーネルが定める特徴写像で、カーネルトリックによりこの問題は二次計画問題に帰着します。RKHSでの平均(カーネル平均)が一致すれば、十分豊かなカーネルのもとで分布が一致するため、重み付き訓練分布を本番分布に合わせられる、という理論的裏付けがあります。
この目的関数を展開すると、重み $\bm{w}$ についての二次形式になります。カーネル行列 $K_{ij} = k(x_i^{tr}, x_j^{tr})$ と、本番データとの平均カーネル $\kappa_i = \frac{n}{m}\sum_j k(x_i^{tr}, x_j^{te})$ を用いると、
$$ \min_{\bm{w}} \ \frac{1}{2}\bm{w}^\top K \bm{w} – \bm{\kappa}^\top \bm{w} \quad \text{s.t.}\quad 0 \leq w_i \leq B,\ \left|\textstyle\frac{1}{n}\sum_i w_i – 1\right| \leq \epsilon $$
という標準的な二次計画問題に帰着します。既存のソルバで解けるため、密度比を陽に推定する必要がありません。確率分類器法より頑健ですが、$n\times n$ のカーネル行列を扱うため計算は重くなります。
重要度重み付けの落とし穴
重要度重み付けは万能ではなく、実用上はいくつかの注意点があります。
重みの高分散: $p_{train}(x)$ が小さい領域では $w = p_{test}/p_{train}$ が極端に大きくなり、少数のサンプルが学習を支配します。重みの分散が大きいほど、重み付き推定量の分散も増え、かえって不安定になります。
有効サンプルサイズ(ESS): 重みが偏ると、実質的に使えるサンプル数が減ります。有効サンプルサイズ $\mathrm{ESS} = (\sum_i w_i)^2 / \sum_i w_i^2$ は、重みが均一なら $n$、一点に集中すると $1$ に近づきます。ESSが小さいと、見かけのデータ数より遥かに少ないサンプルで学習しているのと同じで、過学習の危険が高まります。
重みのクリッピング: そこで実務では、極端に大きい重みを上限 $B$ で打ち切る(クリッピング)ことで分散を抑えます。バイアスはわずかに増えますが分散が減り、全体として安定します。これはバイアスと分散のトレードオフの調整です。
台(サポート)の重なりが前提: $p_{train}(x)=0$ なのに $p_{test}(x)>0$ の領域があると、$w$ が定義できず重み付けでは補正できません。本番領域が訓練領域に「含まれている」ことが、重要度重み付けが機能する前提条件です。
他の分布シフトとの違い
分布シフトには共変量シフト以外もあり、それぞれ対処法が異なります。
| シフトの種類 | 何が変わるか | 例 | 対処 |
|---|---|---|---|
| 共変量シフト | $p(x)$ が変化、$p(y\mid x)$ は不変 | 入力分布のズレ | 重要度重み付け |
| ラベルシフト | $p(y)$ が変化、$p(x\mid y)$ は不変 | クラス比率の変化 | クラス重み補正 |
| 概念ドリフト | $p(y\mid x)$ 自体が変化 | ルールの変化 | 再学習・オンライン適応 |
重要度重み付け(入力の重み)が直接効くのは共変量シフトです。ラベルシフトでは $p_{test}(y)/p_{train}(y)$ のクラス重みで補正します。概念ドリフトは $y$ と $x$ の関係そのものが変わるため、重み付けでは対応できず、新しいデータでの再学習やオンライン適応が必要です。自分の問題がどのシフトなのかを見極めることが、正しい対処の第一歩になります。
Pythonで実装する
確率分類器法で重みを推定し、共変量シフトのある回帰問題で「重みなし」と「重要度重み付き」を比較します。
共変量シフトデータの生成
真の関係を $y = \sin(x)$(非線形)とし、訓練は $x\approx0$、本番は $x\approx2.5$ に集中させて共変量シフトを作ります。モデルは線形回帰(誤特定)です。
import numpy as np
from sklearn.linear_model import LogisticRegression
rng = np.random.default_rng(0)
n = 200
x_tr = rng.normal(0, 0.7, n) # 訓練: x ~ 0 付近
x_te = rng.normal(2.5, 0.7, n) # 本番: x ~ 2.5 付近
f_true = lambda x: np.sin(x)
y_tr = f_true(x_tr) + 0.05 * rng.normal(size=n)
y_te = f_true(x_te) + 0.05 * rng.normal(size=n)

図が生成したデータです。訓練データ(青)は $x\approx0$、本番データ(オレンジ)は $x\approx2.5$ に固まっており、真の関係 $\sin(x)$ の異なる部分をカバーしています。線形モデルで両方を同時にうまく当てるのは不可能で、まさに誤特定の状況です。
確率分類器で重みを推定
訓練(ラベル0)と本番(ラベル1)を見分けるロジスティック回帰を学習し、そのオッズから重みを求めます。
# 訓練=0, 本番=1 を見分ける分類器
X = np.concatenate([x_tr, x_te]).reshape(-1, 1)
y = np.concatenate([np.zeros(n), np.ones(n)])
clf = LogisticRegression().fit(X, y)
p = clf.predict_proba(x_tr.reshape(-1, 1))[:, 1] # 訓練点が「本番」と判定される確率
w = p / (1 - p + 1e-6) # オッズ = 密度比
w = w / w.mean() # 平均1に正規化

図は推定された重みです。本番側($x$ が大きい)に近い訓練サンプルほど大きな重みを受け取っています。「本番領域に近いデータを重視する」という重要度重みの狙い通りの結果です。
なお、コードで重みを平均1に正規化(w / w.mean())したのは、自己正規化重要度重み付けと呼ばれる工夫です。重みの総和を揃えることで推定の分散を抑えます。厳密には小さなバイアスが入りますが、実用上は安定性の向上が勝ることが多く、広く使われています。
重み付き回帰の効果
重みなし・重みありの線形回帰を当てはめ、本番データでの誤差を比べます。
def weighted_least_squares(x, y, weights):
A = np.c_[x, np.ones_like(x)]
W = np.diag(weights)
return np.linalg.solve(A.T @ W @ A, A.T @ W @ y) # 重み付き正規方程式
c_no = weighted_least_squares(x_tr, y_tr, np.ones(n)) # 重みなし
c_w = weighted_least_squares(x_tr, y_tr, w) # 重要度重み付き
mse_no = np.mean((np.polyval(c_no, x_te) - y_te) ** 2)
mse_w = np.mean((np.polyval(c_w, x_te) - y_te) ** 2)
print(f"本番MSE 重みなし: {mse_no:.3f} 重みあり: {mse_w:.3f}")
print(f"改善率: {(1 - mse_w/mse_no)*100:.0f}%")
実行すると、本番データでのMSEは重みなしで約 3.35、重要度重み付きで約 2.24 となり、約33%の改善が得られました。

図がその結果です。重みなし(灰の破線)は訓練領域($x\approx0$)に引っ張られて本番領域でずれていますが、重要度重み付き(赤)は本番領域(オレンジの帯)を重視した当てはめになり、その領域で真の関係に近づいています。重みなしのMSE 3.35 に対し重み付きは 2.24 と、誤差を約3分の1削減できました。線形モデルという表現力の限界の中で、「本番で重要な領域に注力する」ことで最大限の性能を引き出した好例です。訓練データしか使っていないのに本番性能を改善できた——これが重要度重み付けの実用的な価値です。
重要度重み付き交差検証
重要度重み付けは学習だけでなく、モデル選択(ハイパーパラメータ調整)にも必要です。通常の交差検証は訓練分布での性能を測りますが、共変量シフト下ではそれが本番性能とずれてしまいます。最良のモデルを訓練分布基準で選ぶと、本番では最良でないかもしれません。
そこで、検証スコアにも重要度重みを掛ける 重要度重み付き交差検証 を使い、本番分布での性能を推定したうえでモデルを選びます。
$$ \hat{R}_{test}^{\text{CV}} = \frac{1}{|\text{val}|}\sum_{i \in \text{val}} w(x_i)\, \ell(f(x_i), y_i) $$
学習・評価・モデル選択のすべてで、本番分布を意識した重み付けを一貫して行うことが、共変量シフト下で性能を引き出す鍵です。重み推定そのものに誤差があるため、ESSのチェックやクリッピングと組み合わせて、安定性を確認しながら使うのが実務の定石です。
重要度重み付けとドメイン適応
共変量シフトへの対処には、重要度重み付けとは別のアプローチもあります。ドメイン適応(特に敵対的手法 DANN など)は、サンプルを重み付けるのではなく、特徴表現そのものを訓練・本番で揃えることで分布差を消します。重要度重み付けが入力空間で「重みを変える」のに対し、ドメイン適応は特徴空間で「分布を寄せる」わけです。
負の転移の記事で見たドメイン間距離 $d_{\mathcal{H}\triangle\mathcal{H}}$ を小さくする操作は、まさにこのドメイン適応にあたります。両者の住み分けは次のように整理できます。重要度重み付けは「分布が重なっている」前提で重みを調整する古典的かつ軽量な手法。ドメイン適応は「分布が大きく離れていても特徴を学習で寄せる」より強力だが学習コストの高い手法。分布のズレが小さく台が重なるなら重要度重み付け、ズレが大きく入力空間では補正しきれないならドメイン適応、と使い分けます。実際には両者を組み合わせることもあります。
まとめ
共変量シフトと重要度重み付けを、理論から実装まで解説しました。
- 共変量シフト: 入力分布が変わる($p_{train}(x)\neq p_{test}(x)$)が、入力→出力の関係は同じ($p(y\mid x)$ 共通)という問題。モデルが誤特定だと本番で性能が落ちる。
- 重要度重み付け: 本番リスクは $R_{test} = \mathbb{E}_{p_{train}}[w(x)\,\ell]$ と書け、重み $w(x)=p_{test}(x)/p_{train}(x)$ を掛けた重み付き経験リスクを最小化すれば本番性能を改善できる。
- 重みの推定: 訓練/本番を見分ける確率分類器のオッズ、または密度比を直接合わせる Kernel Mean Matching(KMM)で求める。
- 実装: 共変量シフトのある回帰で、重要度重み付けにより本番MSEを約33%改善できた。
重要度重み付けは、ドメイン適応や転移学習で分布のズレを補正する基本道具です。負の転移の文脈で見た「ソースとターゲットのドメイン間距離」を、実際に縮める一手にもなります。
次のステップとして、以下もあわせて読むと理解が深まります。