水道の蛇口をひねれば水が出る——この当たり前を支えているのは、無数のポンプ・弁・タンクと、それらを制御するコンピュータ(PLC/SCADA)が一体になった巨大なサイバー物理システム(CPS)です。もし攻撃者がこの制御に侵入し、弁をこっそり開けたり、センサの読み値を偽装したらどうなるでしょう。タンクが溢れ、配水が止まり、薬品の濃度が狂う——物理世界に直接被害が及びます。
こうした攻撃を「いつもと違う」と気づくための研究に欠かせないのが、実際のテストベッドで攻撃を再現したデータセットです。その代表格が WADI(Water Distribution) です。シンガポール工科デザイン大学(SUTD)の iTrust が公開した、上水道の配水システムを模した実機テストベッドのデータで、浄水処理版の SWaT を拡張した、より大規模で複雑なベンチマークとして知られています。
WADI を実データから読み解くと、多変量時系列の異常検知が直面する難しさが具体的に見えてきます。
- 多変量の物理的因果 — タンク水位・流量・圧力は配管でつながり、互いに連動します。攻撃はその「つながり」の崩れとして現れます。
- 連続値と離散状態の混在 — センサは連続値ですが、弁やポンプは「開/閉」「稼働/停止」の離散状態で動きます。
- 攻撃が稀で局所的 — 2日間の攻撃データの中で、攻撃はわずか5.77%。「干し草の山から針を探す」設定です。
本記事では、ローカルに展開した WADI の実データから本物の波形を描きながら、データ構造・センサの素性・攻撃の現れ方を順に見ていきます。最後に多変量マハラノビス距離による素朴なベースラインを Python で実装し、「単純な手法でどこまで攻撃を捉えられるか」を実測で正直に確かめます。
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
WADIとは — 上水道テストベッドの全体像
まず全体像をイメージしましょう。WADI は、家庭やビルに水を届ける配水(water distribution)の過程を実機で再現したテストベッドです。水は3つの段階を順に流れていきます。

- 段階1(一次給水):生水タンクに水を溜め、薬品を注入する入口の工程。タンク水位
1_LT_001、流量1_FIT_001、水質分析計1_AIT_001、電動弁1_MV_001、ポンプ1_P_xxxなどがここに属します。 - 段階2(二次配給):高架の貯水槽に汲み上げ、そこから消費者へ配る工程。貯水槽水位
2_LT_001/002、配給圧力2_PIT_xxx、消費者への弁2_MCV_xxx、ブースターポンプが働きます。 - 段階3(戻り):使われなかった水を回収し、一次給水へ戻して循環させる工程です。
各センサ・アクチュエータの名前には、頭に段階番号(1_, 2_, 2A_, 2B_, 3_)が付き、続いて種別コード(LT=水位計、FIT=流量計、AIT=水質分析計、PIT=圧力計、MV=電動弁、P=ポンプ、MCV=消費者弁など)が並びます。この命名を覚えておくと、後で波形を見るときに「どの段階の何のセンサか」がすぐ読めます。
データは2つに分かれています。正常データ(WADI_14days)は約78万行、14日間にわたり攻撃なしで運転した記録で、「正常とはどういうものか」を学ぶための教師なし学習用です。攻撃データ(WADI_attackdata)は約17万行、2日間にわたり弁・ポンプ・センサへのサイバー物理攻撃を14区間しかけた記録で、最終列に正解ラベル(1=正常、-1=攻撃)が付いています。サンプリングはどちらも1秒に1回(1 Hz)です。
ここで大事なのは、攻撃が「配管でつながった物理プロセスへの干渉」だという点です。ある弁を開ければ、下流のタンク水位も流量も圧力も連動して動きます。攻撃はセンサ間の因果関係の崩れとして波形に刻まれる——この視点を持って、まず正常運転の波形を見てみましょう。
正常運転の実波形 — 周期的な充填と排出
異常を語る前に、「正常」がどんな形をしているかを知る必要があります。正常データから代表的な4つのセンサを1日分(10秒間隔にダウンサンプル)描いてみます。

4枚のパネルから、配水プロセスのリズムが読み取れます。一番上の一次タンク水位 1_LT_001 は、ゆっくり上がっては下がる充填・排出のサイクルを描きます。水位が下限に近づくと給水が始まり、上限に達すると止まる——タンク制御の典型的な振る舞いです。2枚目の一次給水流量 1_FIT_001 は、給水中だけ立ち上がる矩形に近いパルスになり、水位の上昇局面と対応しています。3枚目の高架貯水槽 2_LT_002、4枚目の配給圧力 2_PIT_001 も、それぞれ独自の周期で揺れています。
重要なのは、これらの波形が互いに無関係ではないことです。タンクが充填されている間は流量が立ち、圧力もそれに応じて変化します。正常運転とは「複数のセンサが物理法則に従って協調して動いている状態」なのです。この協調が崩れたとき、私たちは異常を疑います。
連続値のセンサに加えて、WADI にはもう一種類、性質のまったく異なる変量があります。弁やポンプのようなアクチュエータです。次にその波形を見てみましょう。
アクチュエータは離散状態で切り替わる
タンク水位がなめらかに変化するのに対し、弁やポンプは「開いているか閉じているか」「動いているか止まっているか」という離散的な状態で表されます。代表的な3つのアクチュエータの状態コードを描いてみます。

3枚とも、なめらかな曲線ではなく階段状のステップになっています。電動弁 1_MV_001 はコード1(閉/停止)を基準に、ときどき2(開/稼働)へ跳ね上がり、切り替わりの瞬間に0(遷移中)を取ります。給水ポンプ 1_P_001 や薬注ポンプ 1_P_003 も、1と2の間を矩形的に行き来します。
この離散性は、異常検知にとって厄介な性質です。連続センサ向けに作られた手法(ガウス分布を仮定する再構成モデルなど)は、こうした2値・3値の信号をうまく扱えません。状態が1から2へ切り替わる瞬間は、連続値で見れば「急激なジャンプ」に見え、ナイーブな手法は正常な切り替えを異常と誤検知しがちです。逆に、攻撃が弁を不正に「開」へ固定しても、状態コード自体は正常範囲の値(2)を取り続けるため、値だけを見ていては気づけません。WADI が「難しい」とされる理由のひとつが、約123変量の中に連続値と離散状態が混在していることにあります。手法はこの両方を同時に相手にし、しかも「正常な状態遷移」と「攻撃による不正な遷移」を区別しなければなりません。
ここまでで正常運転の姿がつかめました。では、攻撃が起きると波形はどう変わるのでしょうか。攻撃データの実波形を見ていきましょう。
攻撃の実波形 — 弁の不正操作でタンクが溢れる
WADI の攻撃データには、14個の攻撃区間が埋め込まれています。それぞれが具体的なシナリオを持ち、付属の攻撃一覧表に「どのアクチュエータを操作し、どのセンサに影響が出るはずか」が記されています。最初の攻撃(攻撃1)は、電動弁 1_MV_001 を不正に開いて一次タンクを溢れさせるもので、影響は 1_LT_001(タンク水位)と 1_FIT_001(流量)に現れるはず、と説明されています。実データで確かめてみましょう。

赤帯が攻撃区間です。上のパネルを見ると、攻撃が始まった瞬間から一次タンク水位が通常の上限を超えて単調に上昇し、約75%まで到達しています。正常運転では充填・排出を繰り返していた水位が、攻撃中は「排出されずに溜まり続ける」——まさに溢れ(オーバーフロー)の様子です。下のパネルの流量 1_FIT_001 も、攻撃中だけ約2.0の高い値に張り付いており、弁が開きっぱなしで水が流れ続けていることを示します。
ここが WADI の面白いところです。攻撃の説明書きどおりに、実データの波形が反応しているのが確認できます。しかも、攻撃は単一のセンサだけでなく、物理的につながった複数のセンサ(水位と流量)に同時に現れます。攻撃が終わると水位は通常の制御に戻り、再び充填・排出のサイクルを描き始めます。
攻撃の手口は、この「弁を開ける」だけではありません。付属の攻撃一覧表を読むと、14区間の攻撃はいくつかのタイプに分かれます。アクチュエータの直接操作(攻撃1の弁開放、攻撃9のポンプ起動による配管破裂、攻撃5の消費者弁 2_MCV 一斉閉鎖で断水)に加えて、センサ値の偽装もあります。攻撃2では流量計 1_FIT_001 の読み値をオフに改ざんし、PLC に偽の値を信じ込ませて薬注ポンプを誤動作させます。攻撃7では水質分析計 1_AIT_002 の値を不正に書き換え、汚染を装って生水タンクを排水させます。さらに攻撃8・11・12のように、消費者弁 2_MCV_007 を開けて配水前に水漏れ(リーク)を起こし、圧力 2_PIT_002 や流量に影響を与えるシナリオもあります。
これらが厄介なのは、操作する対象(弁・ポンプ・センサ)と、影響が現れる対象(水位・流量・圧力)が必ずしも一致しない点です。流量計を偽装する攻撃2では、偽装された 1_FIT_001 自体は一見もっともらしい値を示し、異常はむしろ下流の薬品濃度や水位に間接的に現れます。だからこそ、単一センサの値だけを監視していては取りこぼし、複数センサの整合性(つじつま)を見る必要があるのです。
攻撃1は影響がはっきり出る分かりやすい例でした。しかし、すべての攻撃がこれほど派手ではありません。もっと巧妙な「ステルス攻撃」では、逸脱はわずかです。次に、攻撃の局所を拡大して、その繊細さを見てみましょう。
攻撃前後のズーム — 正常範囲からのわずかな逸脱
攻撃10は、1_MV_001 と生水ポンプを損傷させて高架貯水槽の水を抜く(ドレインする)シナリオです。貯水槽水位 2_LT_002 の周辺を拡大してみます。

緑の帯は、正常データから求めた 2_LT_002 の通常範囲(1〜99パーセンタイル)です。攻撃前(左側)の水位は、この緑帯の中で上下に振動しています。ところが攻撃区間(赤帯)に入ると、水位が緑帯の下限を割り込み、正常運転ではあまり見られない低い水準まで落ち込んでいます。その後、攻撃が終わると徐々に通常範囲へ戻っていきます。
この例が教えてくれるのは、攻撃の検出が必ずしも簡単ではないということです。値の落ち込みは攻撃1の溢れほど劇的ではなく、正常な変動の延長線上にも見えます。「1点だけ見れば正常範囲に近いが、文脈の中では異常」という、時系列ならではの難しさがここにあります。単純な上下限の閾値だけでは取りこぼしかねません。
では、こうした繊細な攻撃を捉える手がかりはどこにあるのでしょうか。鍵は、冒頭で触れたセンサ間の関係にあります。まず正常時に、センサどうしがどれだけ連動しているかを見てみましょう。
センサ間の相関 — 物理的に結合した変数群
配管でつながったセンサは、正常運転では強く連動します。正常データから連続センサ18個の相関行列を計算し、ヒートマップにしてみます。

赤いほど正の相関、青いほど負の相関です。対角線(自分自身との相関=1)の周りに、赤や青のブロック(かたまり)が見えます。たとえば高架貯水槽の水位 2_LT_001/002 と配給圧力 2_PIT_001 のグループは、物理的に直結しているため強く相関します。流量計どうし、圧力計どうしも、同じ段階に属するものは連動します。
この相関構造こそが、正常運転の「指紋」です。各センサが何の値を取るかだけでなく、センサどうしがどう連動しているかに、プロセスの健全性が表れています。たとえば「タンクを充填している間は流量が立ち、圧力も上がる」という関係は、配管と制御ロジックが正常に働いている限り必ず保たれます。逆に言えば、この連動が崩れたときこそ、何かがおかしいと疑える瞬間です。だとすれば、攻撃が起きたとき、この指紋はどう変わるのでしょうか。
攻撃で相関構造が崩れる — 関係ベース検知の根拠
攻撃は、正常な物理的因果を断ち切ります。たとえば弁を不正に操作すると、本来連動するはずのセンサどうしの関係が壊れます。攻撃3-4(高架貯水槽 2_LT_002 をステルスに排水する攻撃)の区間と、その直前の正常区間で相関行列を比べてみます。

左が攻撃前(正常)、中央が攻撃区間、右がその差分です。中央のパターンは左とは明らかに違い、差分(右)には濃いオレンジや紫のセルが多数現れています。つまり、攻撃中はセンサ間の相関が正常時から大きくずれているのです(この例では相関の平均絶対変化は約0.37に達します)。本来強く連動していたペアの連動が弱まったり、無関係だったペアが妙に相関したりします。
この「関係の崩れ」を捉えるのが、近年の多変量時系列異常検知の主流の発想です。GDN(グラフ偏差ネットワーク)はセンサ間の関係をグラフとして学習し、その逸脱を検知します。USAD や TranAD のような再構成ベースの手法も、正常な多変量パターン(=関係を含む)を再構成しようとして、攻撃時に再構成誤差が増えることで異常を捉えます。WADI が高次元かつ関係が豊かだからこそ、こうした関係ベース・再構成ベースの手法を評価する格好の舞台になるのです。
ここまで個々の波形と関係を見てきました。では、データセット全体としてはどんな素性を持つのか、数字で俯瞰しておきましょう。
データセットの素性 — 規模と攻撃の分布
WADI の規模と、14個の攻撃区間の長さを集計してみます。

左の棒グラフは、各攻撃区間の継続時間です。最長は約1700秒(約28分)、最短はわずか88秒で、長短さまざまな攻撃が含まれています。短い攻撃ほど検出は難しくなります。右の表は全体の素性です。正常データ約78万行・攻撃データ約17万行という大規模さ、約123変量という高次元、3段階のプロセス、14区間の攻撃、そして攻撃データ中の攻撃割合は5.77%です。
この「攻撃5.77%」という数字は、SMD(約4%)に近く、PSM(約28%)よりずっと低い、現実的に「異常は稀」な設定です。稀であるほど、誤検知を抑えながら確実に攻撃を当てる手法の力量が問われます。また高次元(123変量)は、SWaT(約51変量)の2倍以上で、WADI が「SWaT の拡張版」と呼ばれる所以です。
数字で性格がつかめたところで、実際に手を動かしてみましょう。素朴なベースラインを実データに適用し、「単純な手法でどこまで攻撃を捉えられるか」を確かめます。
Pythonで触る:データの読み込み
まず、正常データと攻撃データを読み込みます。攻撃ファイルは先頭1行が列番号なので読み飛ばし、最終列をラベルとして取り出します。巨大な CSV なので、解析に使う連続センサの列だけを usecols で絞って読み込みます。
import os
import numpy as np
import pandas as pd
DATA = os.path.expanduser("~/workspace/dataset/wadi/WADI.A2_19 Nov 2019")
NORM = os.path.join(DATA, "WADI_14days_new.csv")
ATK = os.path.join(DATA, "WADI_attackdataLABLE.csv")
# プロセスを代表する連続センサ(分散があり物理的に意味のある変量)
FEAT = ['1_AIT_001_PV','1_AIT_002_PV','1_FIT_001_PV','1_LT_001_PV',
'2_DPIT_001_PV','2_FIC_101_PV','2_FIT_001_PV','2_FIT_002_PV',
'2_FIT_003_PV','2_LT_001_PV','2_LT_002_PV','2_PIT_001_PV',
'2_PIT_002_PV','2_PIT_003_PV','2A_AIT_001_PV','2B_AIT_001_PV',
'3_LT_001_PV','3_FIT_001_PV']
# 正常データ(攻撃なし=学習用)
norm = pd.read_csv(NORM, usecols=FEAT, low_memory=False)
norm = norm.apply(pd.to_numeric, errors='coerce').ffill().bfill()
# 攻撃データ。先頭1行は列番号なので skiprows=[0]、最終列がラベル
atk = pd.read_csv(ATK, skiprows=[0], low_memory=False)
atk.columns = [c.strip() for c in atk.columns]
labcol = [c for c in atk.columns if c.startswith('Attack LABLE')][0]
lab = atk[labcol].astype(int).values # 1=正常, -1=攻撃
anom = (lab == -1).astype(int)
print("正常 %d 行 / 攻撃 %d 行 / 攻撃割合 %.2f%%"
% (len(norm), len(atk), 100 * anom.mean()))
# 攻撃区間の数を数える
n_seg = int((np.diff(np.r_[0, anom, 0]) == 1).sum())
print("攻撃区間数:", n_seg)
出力は次のようになります。
正常 784571 行 / 攻撃 172803 行 / 攻撃割合 5.77%
攻撃区間数: 14
正常データが約78万行、攻撃データが約17万行で、攻撃区間はちょうど14個。ラベル(攻撃割合5.77%)はあくまで採点用で、検出器には渡しません。データの形がつかめたので、いよいよ異常スコアを計算します。
Pythonで触る:マハラノビス距離ベースライン
最も素朴な多変量異常検知のひとつが、マハラノビス距離です。アイデアはこうです。正常データから各センサの平均ベクトル $\bm{\mu}$ と共分散行列 $\bm{\Sigma}$ を推定します。共分散行列はセンサ間の相関を含むので、「正常な変数どうしの連動」を織り込めます。新しい観測 $\bm{x}$ が正常からどれだけ外れているかを、相関を考慮した距離
$$ \begin{equation} D(\bm{x}) = \sqrt{(\bm{x} – \bm{\mu})^{\top} \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu})} \end{equation} $$
で測ります。$\bm{\Sigma}^{-1}$ で割ることが、各方向のばらつきと相関で「正規化」する働きをします。正常な連動から外れた点ほど、この距離は大きくなります。実装してみましょう。
# 正常データから平均・共分散を推定(5点間引きで軽量化)
Xn = norm[FEAT].values[::5]
mu = Xn.mean(0)
S = np.cov(Xn.T)
Sinv = np.linalg.pinv(S + 1e-6 * np.eye(len(FEAT))) # 数値安定化
# 攻撃データの各時刻でマハラノビス距離を計算
X = atk[FEAT].apply(pd.to_numeric, errors='coerce').ffill().bfill().values
d = X - mu
maha = np.sqrt(np.maximum(np.einsum('ij,jk,ik->i', d, Sinv, d), 0))
# 正常基準の99%点を閾値にして点ごとの精度を見る
thr = np.quantile(maha, 0.99)
pred = (maha > thr).astype(int)
tp = ((pred == 1) & (anom == 1)).sum()
fp = ((pred == 1) & (anom == 0)).sum()
fn = ((pred == 0) & (anom == 1)).sum()
prec = tp / (tp + fp); rec = tp / (tp + fn)
f1 = 2 * prec * rec / (prec + rec)
# しきい値に依存しない ROC-AUC
order = np.argsort(-maha); y = anom[order]
tpr = np.cumsum(y) / y.sum(); fpr = np.cumsum(1 - y) / (1 - y).sum()
auc = float(np.trapz(tpr, fpr))
# 14区間のうち何区間でスコア最大が閾値を超えたか
d2 = np.diff(np.r_[0, anom, 0])
segs = list(zip(np.where(d2 == 1)[0], np.where(d2 == -1)[0]))
hit = sum(1 for s, e in segs if maha[s:e].max() > thr)
print("閾値(99%%): %.2f" % thr)
print("適合率 %.3f / 再現率 %.3f / F1 %.3f" % (prec, rec, f1))
print("ROC-AUC: %.3f / 検出できた攻撃区間 %d/14" % (auc, hit))
実行結果は次のとおりです。
閾値(99%): 26.18
適合率 0.814 / 再現率 0.141 / F1 0.240
ROC-AUC: 0.793 / 検出できた攻撃区間 3/14
数字を正直に読み解きましょう。適合率は0.814と高いので、「異常だ」と言ったときはかなりの確率で本当に攻撃です。ところが再現率は0.141しかなく、攻撃の点の大半を見逃しています。閾値を超えるスコアのピークが攻撃区間に入った数を数えると、14区間のうち3区間だけ。しきい値非依存の ROC-AUC は0.793で、ランダム(0.5)よりは明確に良いものの、SOTA手法が報告する0.9超には遠く及びません。スコアの波形を可視化してみます。
import matplotlib.pyplot as plt
ds = 10 # 間引いて描画
ti = np.arange(0, len(maha), ds)
fig, axs = plt.subplots(2, 1, figsize=(12, 6), sharex=True)
axs[0].plot(ti, atk['2_LT_002_PV'].values[::ds], lw=0.5)
axs[1].plot(ti, maha[::ds], lw=0.6, color='purple')
axs[1].axhline(thr, color='orange', ls='--', label='99%閾値')
for s, e in segs: # 攻撃区間を赤帯で重ねる
axs[0].axvspan(s, e, color='red', alpha=0.25)
axs[1].axvspan(s, e, color='red', alpha=0.25)
axs[1].set_yscale('log'); axs[1].legend()
axs[1].set_xlabel("時刻インデックス(攻撃データ)")
plt.tight_layout(); plt.show()

下段のスコアを見ると、いくつかの攻撃区間(赤帯)でははっきりスコアが跳ね上がる一方、多くの攻撃区間ではスコアがほとんど立っていません。攻撃1のような派手な攻撃は捉えられても、攻撃10のようなステルスな逸脱や、相関の崩れだけが手がかりの攻撃は、点ごとの距離だけでは取りこぼします。これは失敗ではなく、WADI の難しさを正直に映した結果です。単純なマハラノビス距離は良いベースラインですが、ここから先は時間的文脈やセンサ間関係をより丁寧にモデル化する手法が必要になります。
この実測から得られる教訓は2つあります。第一に、WADI は単純な手法には手強いこと。高次元・低異常率・ステルス攻撃という三拍子が、素朴な距離法の再現率を押し下げます。第二に、だからこそ WADI は手法の真価を試すこと。新しい手法を提案するなら、まずこのベースラインを ROC-AUC で明確に上回れるかを確認するのが出発点になります。時間方向の文脈(直前の数十秒の流れ)や、本記事で見たセンサ間の相関の崩れを取り込んだ手法ほど、再現率を引き上げやすいはずです。
最後に、WADI を兄弟データセットである SWaT と並べ、CPS 異常検知ベンチマークの中での位置づけを整理しましょう。
SWaTとの対比 — CPS異常検知での位置づけ
WADI を理解するには、同じ iTrust が公開した SWaT(Secure Water Treatment)と比べるのが近道です。SWaT は水を「浄化する」工程、WADI は浄化した水を「配る」工程を扱います。

表が示すように、WADI は SWaT より変量数が約123と多く(SWaTは約51)、規模も大きくなっています。WADI が「SWaT の拡張版」と呼ばれるのはこのためで、より多くのセンサ・より複雑な配管網を相手にする分、難易度が上がっています。一方で攻撃割合は WADI のほうが低く(約5.8% 対 SWaT約12%)、稀な攻撃を見つける厳しさがあります。
この2つはしばしばセットで使われ、論文では「SWaT と WADI の両方で評価した」という記述をよく見かけます。これは、浄水と配水という異なる工程・異なる規模で手法の頑健性を示すためです。SWaT/WADI はどちらも実機テストベッドの本物のデータであり、合成データでは再現しきれない物理プロセスの癖(離散アクチュエータ、制御ループの遅れ、センサノイズ)を含んでいます。だからこそ、産業制御システムの異常検知を研究するうえで欠かせない基準になっているのです。
WADI ならではの強みは、変量数の多さと攻撃シナリオの具体性にあります。各攻撃が「どのアクチュエータを操作し、どのセンサに影響が出るはずか」まで文書化されているため、検出できた・できないだけでなく、なぜ検出できたのか(どのセンサの逸脱を捉えたのか)を物理的に解釈できます。これは、異常の根本原因(root cause)を特定する診断タスクや、攻撃の局在化(どの段階・どの機器が狙われたか)を評価するうえで貴重です。高次元であるがゆえに前処理の負荷は重く、欠損値の補完や定数列の除去といった地道な下ごしらえも必要になりますが、その手間に見合う情報量を持ったデータセットだと言えます。
なお、評価の際には SMDとPSM の記事でも触れた point-adjust 評価の水増しに注意が必要です。WADI のように攻撃区間が長いデータでは、区間内で1点でも当たれば全体を正解とみなす point-adjust が F1 を過大に見せます。論文の数値を比べるときは、PA の有無を必ず揃えて読みましょう。
まとめ
本記事では、上水道配水テストベッドのデータセット WADI を、実波形つきで読み解きました。
- 構造:水を「配る」3段プロセス(一次給水・二次配給・戻り)を実機で再現。約123変量のセンサ/アクチュエータを 1 Hz で記録。正常14日+攻撃2日。
- 波形:正常時はタンク水位・流量・圧力が周期的かつ協調的に動く。弁・ポンプは連続値でなく離散状態(開閉・稼働停止)で切り替わる。
- 攻撃:14区間の攻撃が埋め込まれ、攻撃割合は5.77%。攻撃1では弁の不正操作でタンク水位が溢れ、流量も同時に逸脱するなど、説明書きどおりに実データが反応する。
- 関係の崩れ:攻撃中はセンサ間の相関構造が正常時から大きくずれる。これが関係ベース・再構成ベース手法の検知根拠になる。
- ベースライン:マハラノビス距離は適合率0.814と精度は高いが再現率0.141・ROC-AUC0.793と、14区間中3区間しか捉えられない。WADI の高次元・低異常率・ステルス攻撃の難しさを正直に映す。
WADI は、サイバー物理システムのセキュリティという現実の課題を、再現可能なデータとして手元に持ち込んでくれます。蛇口の向こうにある巨大な制御システムを「いつもと違う」と気づく——その研究の出発点として、まず実波形に触れ、自分の手法をこのベンチマークで試してみることをおすすめします。
次のステップとして、以下の記事も参考にしてください。