データ品質のテストとは、「このデータはこうなっているはずだ」という期待を検査としてコードに書き、データが次の工程へ渡る境目で毎回自動実行する方法です。主キーの重複、必須列の欠損、想定外の区分値、参照先が存在しない外部キー、更新が止まったテーブルといった不具合を、ダッシュボードや機械学習モデルに届く前に止めます。
この記事では、ISO/IEC 25012のデータ品質特性から検査項目を選ぶ手順、テストを置く場所、止めるか警告で済ますかの閾値の決め方を整理し、dbtとpanderaで実際に動かした検査コードと出力を載せます。後半では、AI学習データで追加すべき検査(学習・テスト間のリーク、ラベルの偏り、代表性)を、AIセーフティ・インスティテュートのガイドブックに沿って扱います。
まとめ:データ品質テストで最初に決めること
- 検査項目:ISO/IEC 25012の15特性のうち、コードで判定できるのは主に完全性・一意性(一貫性)・正確性の形式面・最新性。まず「主キーの一意と非NULL」「必須列の非NULL」「区分値の許容リスト」「外部キーの参照整合」「鮮度」の5種類から始める。
- 置き場所:取り込み直後(ソースの形と鮮度)、変換後(業務ルール)、公開前(集計値の妥当性)の3か所。下流の数字を壊す検査は変換の直後に置く。
- 重大度:主キーの重複や、非負と定義した金額列の負値など、集計を誤らせる違反は error で止め、参照先の遅延や新しい区分値のように業務が先行して起きるものは warn にする。dbtは severity・warn_if・error_if で件数の閾値を書ける。
- AI学習データ:形式の検査に加え、学習とテストのID重複・時刻の逆転(リーク)、ラベル比率、カテゴリの偏りを検査する。ISO/IEC 5259-2はAI/ML向けに均衡性・代表性・類似性などの特性を追加している。
データ品質テストの検査項目|ISO/IEC 25012の特性との対応
検査項目をゼロから考えると、思いついた順に足して抜けが出ます。出発点にするのは、データ品質モデルの国際規格ISO/IEC 25012です。データ品質を15の特性で定義し、データそのものに由来する特性(固有)、システムに由来する特性(システム依存)、その両方にまたがる特性に分けています。国内ではAIセーフティ・インスティテュート(AISI)の「データ品質マネジメントガイドブック」(1.02版・2026年5月14日)が、この分類に沿って特性ごとの評価観点と不適切な例を並べています。
なお、国内の解説で今も参照されることが多いデジタル庁の「データ品質管理ガイドブック」(DS-468-1・2022年3月31日正式版)も同じくISO/IEC 25012に沿った15特性で評価する文書ですが、GIF(政府相互運用性フレームワーク)のv2.2(2026年1月8日)で管理対象から外れ、今後の更新と公式説明の対象外になりました。これから検査項目を決めるなら、改訂が続いているAISIのガイドブックを基準にするほうが安全です。
15特性のうち自動テストにできる特性
15特性のすべてが自動テストに向くわけではありません。アクセシビリティ・標準適合性・機密性・可用性・回復性などはデータ基盤やアクセス権の設計で担保するもので、行や列を数える検査では判定できません。テストとして書けるのは、次のように行・列・集計値で白黒をつけられる特性です。
| 特性(ISO/IEC 25012) | 検査の例 | dbtでの書き方 |
|---|---|---|
| 完全性 | 必須列にNULLがない | not_null |
| 一貫性 | 主キーが重複しない/外部キーの参照先がある | unique/relationships |
| 正確性(形式) | 区分値が許容リスト内/値の範囲 | accepted_values/単体のSQLテスト |
| 最新性 | 最終更新から一定時間内 | source の freshness |
| 精度 | 小数桁・単位・粒度がそろう | 単体のSQLテスト |
AISIのガイドブックは正確性の不適切な例として「学習データセットの誤ラベル」「数値データの単位不一致」を、一貫性の例として「データセット内で異なる日付形式」「詳細が矛盾する重複レコード」を挙げています。誤ラベルのように突き合わせる正解が手元に無い特性は、全件の自動判定ではなく抜き取りのレビューで扱うと割り切ってください。
データ品質の測定方法:件数・比率・経過時間の使い分け
テストの合否とは別に、品質を数値で追いたい場合は測定量を定義します。測定方法はISO/IEC 25024:2015(Measurement of data quality)が規格化しており、日本産業規格ではJIS X 25024:2018「データ品質の測定」が対応します。実務では「NULLの行数÷全行数」「重複があるキー値の種類数÷全キー値の種類数」のように、分子・分母とNULLの扱いを固定した比率で記録すると、テーブルの行数が増えても前月と比べられます。テストは件数や比率が許容閾値を満たすかを判定し、継続的な測定では同じ指標の推移を記録します。主キーの重複など、許容しない違反には0件を条件にします。
テストを置く場所|取り込み・変換・公開前の3か所
AISIのガイドブックは「データ品質を維持するには、プロセスの境界やトランザクションの節目で確認する必要がある」とし、現場の負荷を増やさないよう「品質確認は可能な限り自動化すべき」としています。パイプラインの境界は、次の3か所に置くと過不足が出にくくなります。層の分け方そのものはメダリオンアーキテクチャとは:Bronze・Silver・Goldの層設計と再処理をコード付きで解説が詳しく扱っています。
| 置き場所 | 見るもの | 失敗したとき |
|---|---|---|
| 取り込み直後 | 列の有無・型・鮮度・行数 | 取り込みを止め、ソース側へ連絡 |
| 変換の直後 | 主キー・必須列・区分値・参照整合 | 下流のモデルを作らない |
| 公開の直前 | 集計値の範囲・前日比 | 前回の公開データを残す |
取り込み直後の検査は「ソースが壊れた」のか「自分の変換が壊れた」のかを切り分けるためにあります。ここを省いて変換後だけに検査を置くと、失敗したときに原因の調査がソースまでさかのぼることになります。ソースとの間で列や型の約束を明文化する方法はデータ契約(Data Contract)とは?ODCSとdbtでスキーマ破壊を止める実装を解説【2026年版】で扱っています。
閾値と重大度の決め方|止めるテストと警告で済ますテスト
全部のテストを「1件でも失敗したら止める」にすると、業務側の事情で毎朝パイプラインが止まり、やがて誰もテスト結果を見なくなります。判断基準は1つで、その不具合が下流の数字を誤らせるかです。
- 止める(error):主キーの重複(集計が二重になる)、非負と定義した金額列の負値、許容範囲を超える金額、必須の日付の欠損。
- 警告(warn):マスタ登録が後から追いつく外部キーの欠け、業務側が先行して追加した新しい区分値、任意項目のNULL増加。
- 件数で切り替える:参照先の欠けが数件なら警告、10件を超えたら停止、のように閾値で段階を付ける。
dbtの公式ドキュメントでは、warn_if・error_if はどちらも既定が !=0 の条件式で、severity が error のときは先に error_if を評価し、満たさなければ warn_if を評価すると説明されています。失敗件数を条件式で書けるので、上の「数件なら警告、10件超で停止」をそのまま設定にできます。severity が warn のときは error_if を評価せず、warn_if だけを見ます。Great Expectationsでは件数でなく比率で緩める mostly というパラメータがあり、検証に成功した行の割合がその値以上ならExpectation全体を成功とみなします。
dbtでデータ品質テストを書く手順
dbtを使っているなら、データ品質テストはYAMLに数行書くだけで始められます。dbt自体の仕組みとdbt Core・dbt Cloudの違いはdbtとは?ELTのTを担う仕組みとdbt Core・Cloudの選び方【2026年版】を参照してください。
組み込みテスト4種と重大度の設定
dbtには unique・not_null・accepted_values・relationships の4つの組み込みテストがあります。YAMLのキーは、dbt 1.8でユニットテストが加わったときに tests: から data_tests: へ改名されました(tests: も別名として使えます)。テストの引数を arguments: の下に書く形式は、公式ドキュメントでは v1.10.5 以降で使えるとされています。
次の例は、注文データ stg_orders に5つの検査を掛けたものです。主キーは重複・欠損とも停止、顧客IDの欠けと未知の区分値は警告、参照先の欠けは1件以上で警告・11件以上で停止にしています。
# models/schema.yml
models:
- name: stg_orders
columns:
- name: order_id
data_tests:
- unique
- not_null
- name: customer_id
data_tests:
- not_null:
config:
severity: warn
- relationships:
arguments:
to: ref('stg_customers')
field: customer_id
config:
warn_if: ">0"
error_if: ">10"
- name: status
data_tests:
- accepted_values:
arguments:
values: ["pending", "shipped", "cancelled"]
config:
severity: warn
組み込みテストで書けない業務ルールは、違反する行を返すSELECT文を tests/ に置きます。返った行数が失敗件数になります。
-- tests/assert_amount_non_negative.sql
select order_id, amount
from {{ ref('stg_orders') }}
where amount < 0
dbt buildの実行結果と下流モデルのスキップ
重複した注文ID・顧客IDの欠け・存在しない顧客ID・未知の区分値「refund」・負の金額を1件ずつ含むデータで、dbt-core 1.12.6とdbt-duckdb 1.11.0を使って dbt build を実行した結果が次のとおりです(時刻は省略)。この実行には、掲載した検査に加えて顧客マスタのunique・not_null各1件も含まれます。
7 of 13 WARN 1 accepted_values_stg_orders_status__pending__shipped__cancelled .. [WARN 1 in 0.06s]
8 of 13 FAIL 1 assert_amount_non_negative ...................................... [FAIL 1 in 0.02s]
9 of 13 WARN 1 not_null_stg_orders_customer_id ................................. [WARN 1 in 0.05s]
10 of 13 PASS not_null_stg_orders_order_id ..................................... [PASS in 0.04s]
11 of 13 WARN 1 relationships_stg_orders_customer_id__customer_id__ref_stg_customers_ [WARN 1 in 0.10s]
12 of 13 FAIL 1 unique_stg_orders_order_id ..................................... [FAIL 1 in 0.05s]
13 of 13 SKIP relation main.fct_daily_sales .................................... [SKIP]
Done. PASS=7 WARN=3 ERROR=2 SKIP=1 NO-OP=0 REUSED=0 TOTAL=13
押さえるべき点は2つです。1つ目に、stg_orders を参照する日次売上 fct_daily_sales はSKIPになり、重複を含んだ売上は作られませんでした。dbt run と dbt test を別々に流すとこの止まり方にならないので、本番は dbt build で回します。2つ目に、終了コードは1でした。error の2件を除外して警告だけが残る状態で流し直すと終了コードは0になり、既定設定では warn はジョブを失敗させませんが、–warn-errorなどで警告をエラーへ昇格させる場合は別です。警告を誰かが見る仕組み(通知先や日次の確認)を別に用意しないと、warn は記録されるだけで終わります。
dbt buildの公式ドキュメントも、上流リソースのテストが失敗すると下流リソースは「skip entirely」になると明記しています。失敗した行を後から調べるには store_failures を有効にします。既定では {{ profile.schema }}_dbt_test__audit というスキーマに失敗行のテーブルが作られます。
Pythonでデータを検査する|pandera・Great Expectations・Sodaの使い分け
dbtを使わないパイプラインや、学習前にpandasのDataFrameを検査したい場面では、Pythonのライブラリを使います。2026年10月25日時点のPyPIの最新版は次のとおりです。
| ツール | 最新版(PyPI) | 向いている場面 |
|---|---|---|
| dbt-core | 1.12.6 | DWH上のSQL変換と一緒に検査 |
| pandera | 0.35.0 | DataFrameの型・値をスキーマで検査 |
| Great Expectations(GX Core) | 1.24.1 | 検査結果の記録・共有まで含めて管理 |
| Soda Core | 4.28.0 | YAMLで書いた検査を複数のDBへ |
選び方は、検査対象がどこにあるかで決めます。DWHのテーブルならdbtかSoda、Pythonのメモリ上のDataFrameならpanderaが最短です。Great Expectationsは検査結果をデータドキュメントとして残し、関係者と共有する運用まで面倒を見ますが、そのぶん部品が多くなります。組み込み4種で書けない統計的な検査をdbtで足すパッケージとしてdbt-expectationsが知られていますが、元のcalogica版は2024年12月16日にREADMEで積極的なサポートの終了を告知しており、保守はmetaplaneのフォーク(2026年10月25日時点の最新タグは0.10.10)が引き継いでいます。新しく入れるならフォーク側を指定してください。Great Expectationsの部品構成と導入手順はGreat Expectationsとは?GX Core 1.xの部品構成・実装手順と採用判断を解説【2026年版】にまとめています。
AI学習データで追加する検査|リーク・均衡性・代表性
機械学習に使うデータは、型も値の範囲も正しいまま品質不良になることがあります。偏ったラベル、同じ人の行が学習とテストにまたがる分割、本番と違う分布です。何を足すかは規格の特性から決めます。
ISO/IEC 5259-2とAISIガイドブックが追加する特性
AISIのデータ品質マネジメントガイドブックは、ISO/IEC 25012に加えて、分析・機械学習向けのデータ品質規格ISO/IEC 5259-2の特性を「AI/ML向け追加データ品質特性」として整理しています。挙げられているのは監査可能性・均衡性・多様性・有効性・識別可能性・関連性・代表性・類似性・適時性の9特性です。このうちコードで検査しやすいのは次の4つです。
- 均衡性:カテゴリやラベルの比率が利用目的に照らして偏っていないか。ラベルの正例率やカテゴリ別の件数を閾値で見る。
- 類似性:重複・近似重複のサンプルが多すぎないか。ガイドブックは「似た文書の焼き直しが大半」を不適切な例に挙げている。
- 有効性:カテゴリごとに十分なサンプル数があるか。クラス別の最小件数を検査する。
- 代表性:本番で遭遇する条件を反映しているか。学習データと本番データの分布の差を比べる。
ガイドブックは代表性について「現実世界データが必ずしも均等分布しないため、均衡性とは異なる場合がある」と書いています。ラベルを50対50にそろえれば良いわけではなく、本番の比率と学習の比率のどちらに合わせるかを先に決めてから閾値を書く必要があります。
学習データとテストデータのリーク検査
形式の検査より見落とされやすいのが、学習データとテストデータの間のリークです。未知のユーザーへの汎化を評価する場合はユーザー単位で分割し、未来を予測する場合は学習期間より後のデータで評価します。同じユーザーの混在や時刻の逆転をリークとして扱うかは、評価対象に応じて決めます。次のスクリプトは、panderaで型と値を検査したあと、IDの重複と時刻の逆転を検査します。
import sys
import pandas as pd
import pandera.pandas as pa
from pandera.errors import SchemaErrors
schema = pa.DataFrameSchema(
{
"user_id": pa.Column(int, nullable=False),
"age": pa.Column(int, pa.Check.in_range(0, 120)),
"plan": pa.Column(str, pa.Check.isin(["free", "pro", "team"])),
"label": pa.Column(int, pa.Check.isin([0, 1])),
"event_at": pa.Column("datetime64[ns]"),
},
unique=["user_id"],
strict=True,
)
train = pd.DataFrame({
"user_id": [1, 2, 3, 3],
"age": [34, 151, 28, 28],
"plan": ["pro", "free", "enterprise", "enterprise"],
"label": [0, 1, 0, 0],
"event_at": pd.to_datetime(["2026-09-01", "2026-09-10", "2026-09-30", "2026-09-30"]),
})
test = pd.DataFrame({
"user_id": [3, 4],
"age": [28, 45],
"plan": ["team", "free"],
"label": [1, 0],
"event_at": pd.to_datetime(["2026-09-20", "2026-10-05"]),
})
failed = False
try:
schema.validate(test, lazy=True)
except SchemaErrors as e:
failed = True
print("test:")
print(e.failure_cases[["column", "check", "failure_case"]].to_string(index=False))
try:
schema.validate(train, lazy=True)
except SchemaErrors as e:
failed = True
print(e.failure_cases[["column", "check", "failure_case"]].to_string(index=False))
overlap = set(train["user_id"]) & set(test["user_id"])
if overlap:
failed = True
print(f"leak: user_id {sorted(overlap)} が学習とテストの両方にある")
if test["event_at"].min() <= train["event_at"].max():
failed = True
print(f"leak: テスト最小時刻 {test['event_at'].min().date()} <= 学習最大時刻 {train['event_at'].max().date()}")
rate = train["label"].mean()
if not 0.05 <= rate <= 0.5:
failed = True
print(f"label: 正例率 {rate:.2f} が想定範囲 0.05-0.50 の外")
sys.exit(1 if failed else 0)
pandera 0.35.0・pandas 3.1.0・Python 3.12で実行した出力です。終了コードは1で、CIに組み込めば学習ジョブの手前で止まります。
column check failure_case
user_id multiple_fields_uniqueness 3
user_id multiple_fields_uniqueness 3
age in_range(0, 120) 151
plan isin(['free', 'pro', 'team']) enterprise
plan isin(['free', 'pro', 'team']) enterprise
leak: user_id [3] が学習とテストの両方にある
leak: テスト最小時刻 2026-09-20 <= 学習最大時刻 2026-09-30
lazy=True を付けると最初の違反で止まらず、すべての違反を集めてから SchemaErrors を送出します。付けないと1件目の違反で例外になり、残りの不具合は次の実行まで見えません。時刻の逆転は、時系列で予測するモデルに限って問題になります。ランダムに分割してよいデータかどうかの判断と分割手法の選び方は交差検証とは?分割手法の選び方とデータリーク対策を実装目線で解説【2026年版】で扱っています。ラベルそのものの品質(アノテーター間の一致率など)はデータラベリングとは?ラベル設計・一致率・自動化を実装目線で解説を参照してください。
モデル評価とデータ品質テストの目的・評価指標の違い
AIシステムの品質保証の枠組みでも、データとモデルは別の品質特性として扱われます。産総研の機械学習品質マネジメントガイドライン(第4版 Rev.4.2.0・2024年4月4日公開)は、内部品質のうちデータに関わるものとしてA-2「データ設計の十分性」、B-1「データセットの被覆性」、B-2「データセットの均一性」、B-3「データの妥当性」、B-4「外部品質ごとのデータセットの妥当性」を挙げ、モデルの正確性や安定性とは別項目にしています。
データが検査を通っても、モデルの精度が保証されるわけではありません。正解率・適合率・再現率などの評価指標で合否を決めるのはモデルのテストで、データ品質テストとは目的も実行タイミングも違います。運用開始後に入力分布が学習時からずれていないかを監視するのはモデルモニタリングの役割で、指標としきい値の決め方はモデルモニタリングとは?ドリフト検知の仕組み・指標・しきい値設計を実装目線で解説【2026年版】にまとめています。データ・モデル・監視を1つの運用として回す全体像はMLOpsとは?機械学習の運用を支える仕組みと導入判断をわかりやすく解説を参照してください。
テストが失敗したときの運用|失敗行の保存と対応の分担
テストを書いた後に詰まるのは、失敗した後の動きです。次の3点を、テストを本番に入れる前に決めておきます。
- 失敗行を残す:dbtなら
store_failures、panderaならfailure_casesを保存する。件数だけでは原因を追えない。 - 担当を検査の置き場所で分ける:取り込み直後の失敗はソースの持ち主、変換後の失敗は変換を書いた人、と置き場所で振り分ける。
- 警告の行き先を決める:既定設定では warn だけで終了コードは失敗にならないため、通知チャンネルか日次の確認に流す。警告をエラーへ昇格させる設定の有無も確認する。
テストで拾えるのは「事前に書いた期待」から外れたものだけです。行数の急減や分布の変化など、期待として書いていない異常まで拾いたい場合は、テストとは別に監視を足します。その考え方はデータオブザーバビリティとは?五つの柱とデータ品質監視の導入判断【2026年8月時点】で整理しています。パイプライン全体の設計から相談したい場合は、当社のデータ分析基盤構築・MLOps構築支援でも対応しています。
データ品質テストを厚くしすぎる失敗と、書かなくてよい場面
テストは多いほど安全に見えますが、次の場面では書かない判断のほうが正しいことがあります。
- 一度きりの分析用データ:再利用せず、判断を誤った場合の影響も小さい分析では、手動確認で済ませる選択肢がある。ただし、件数とNULL率だけでなく、目的に応じて重複・範囲・集計値も確認する。
- ソース側の制約と重なる取り込み直後のunique:ソース側の主キー制約だけでは、取り込み先の一意性までは保証できない。取り込み時の再送や再実行による重複も防げる場合に限り、取り込み直後のuniqueの省略を検討する。結合後の主キーは別途検査する。
- 全列へのnot_null一括付与:任意項目までnot_nullにすると、業務上正しいNULLで毎日警告が出て、本当の欠損が埋もれる。
- 大きなテーブルの全件検査:巨大なテーブルに毎回全件のuniqueを掛けると、実行のたびに列全体を読み直すことになり、スキャン量で課金されるDWHでは費用が積み上がる。増分内の検査に加え、増分のキーが既存データと重複していないかも検査する。全体の一意性を保証できない場合は、定期的な全件検査も併用する。
警告が毎日出ても誰も対応していない場合は、まず担当者・通知先・対応期限と実際の品質不良の有無を確認します。そのうえで、不要な検査や過剰に厳しい閾値を見直します。警告を減らすことは品質を下げることではありません。
よくある質問
データ品質テストとは何ですか?
データが満たすべき条件(主キーが重複しない、必須列が空でない、区分値が決まった値の中にある等)をコードで書き、パイプラインの境目で自動実行して、満たさないデータを下流へ渡さないようにする方法です。ソフトウェアのテストがプログラムを検査するのに対し、データ品質テストは毎回入れ替わるデータそのものを検査します。
データ品質はどうやって測定しますか?
ISO/IEC 25024がデータ品質の測定方法を定めています。実務では、NULLの行の比率、重複したキーの比率、最終更新からの経過時間のように、特性ごとに比率や時間で測り、前月と比べられる形で記録します。テストの合否(許容閾値を満たすかどうか)とは別に測定値を記録すると、推移を追えます。
dbtのテストとGreat Expectationsはどちらを使うべきですか?
検査対象がDWHのテーブルで、変換をdbtで書いているならdbtのテストが最短です。Pythonのパイプラインで扱うデータや、検査結果をドキュメントとして共有する運用まで必要ならGreat Expectationsを検討します。同じデータに同じ検査を重複実装する必要はありません。DWH内の変換はdbt、取り込み前のPython処理はGreat Expectationsという分担も可能なので、検査対象と担当工程を決めます。
AIのデータ品質はどう評価しますか?
形式の検査(型・NULL・範囲)に加えて、学習データとテストデータのリーク、ラベル比率の偏り、カテゴリ別のサンプル数、本番データとの分布の差を見ます。ISO/IEC 5259-2とAISIのデータ品質マネジメントガイドブックが、均衡性・代表性・類似性などAI向けの特性と評価観点を示しています。
データ品質テストはどの頻度で回すべきですか?
データが更新されるたびに回します。日次バッチなら毎日の変換の直後、ストリーミングなら取り込みの単位ごとです。テストだけを週1回まとめて流すと、壊れたデータが数日分下流に出た後で気づくことになります。