
はじめに
データ品質ダッシュボード (DQD) は、CDM データ品質を体系的に評価する OHDSI ツールです。 DQD は 1,500 を超えるチェックを自動的に実行し、PASS/FAIL レポートを生成して、分析前にデータの問題を検出するのに役立ちます。
So sánh ACHILLES vs DQD:
ACHILLES:
"Dữ liệu trông như thế nào?"
→ Descriptive statistics, profiling
→ Vẽ biểu đồ trong ATLAS
DQD:
"Dữ liệu có ĐẠT CHUẨN không?"
→ 1,500+ quality checks
→ PASS / FAIL judgement
→ Action items cụ thể
1. カーンのフレームワーク
1.1 3 次元データの品質
DQD dựa trên Kahn et al. (2016) framework:
┌──────────────────────────────────────────────────────┐
│ DATA QUALITY FRAMEWORK │
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ Conformance │ │ Completeness │ │
│ │ (Tuân thủ) │ │ (Đầy đủ) │ │
│ ├────────────────┤ ├────────────────┤ │
│ │ • Value │ │ • Missing data │ │
│ │ • Relational │ │ • Expected │ │
│ │ • Computation │ │ records │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ │
│ │ Plausibility │ Mỗi chiều chia thành: │
│ │ (Hợp lý) │ • Verification (internal) │
│ ├────────────────┤ • Validation (external) │
│ │ • Uniqueness │ │
│ │ • Atemporal │ │
│ │ • Temporal │ │
│ └────────────────┘ │
└──────────────────────────────────────────────────────┘
1.2 各寸法の例
Conformance — Value:
"Giá trị có đúng format/range không?"
✓ gender_concept_id ∈ {8507, 8532}
✗ gender_concept_id = 0 → unmapped!
Conformance — Relational:
"FK references có hợp lệ không?"
✓ condition_concept_id tồn tại trong concept table
✗ person_id không tìm thấy trong person table
Completeness:
"Có thiếu data quan trọng không?"
✓ 98% conditions có concept_id ≠ 0
✗ 40% measurements thiếu unit_concept_id
Plausibility — Atemporal:
"Giá trị có hợp lý không?"
✓ HbA1c values ∈ [3%, 20%]
✗ Body weight = 5000 kg
Plausibility — Temporal:
"Trình tự thời gian có đúng không?"
✓ drug_start_date ≤ drug_end_date
✗ condition_date trước birth_date
2. DQD のインストールと実行
2.1 インストール
install.packages("remotes")
remotes::install_github("OHDSI/DataQualityDashboard")
2.2 DQD の実行
library(DataQualityDashboard)
library(DatabaseConnector)
connectionDetails <- createConnectionDetails(
dbms = "postgresql",
server = "localhost/ohdsi",
user = "ohdsi_app",
password = keyring::key_get("ohdsi_password"),
port = 5432
)
# Output folder
outputFolder <- "output/dqd_results"
dir.create(outputFolder, recursive = TRUE)
# Chạy DQD
DataQualityDashboard::executeDqChecks(
connectionDetails = connectionDetails,
cdmDatabaseSchema = "cdm",
resultsDatabaseSchema = "results",
vocabDatabaseSchema = "cdm",
cdmSourceName = "Hospital_VN_2024",
numThreads = 4,
sqlOnly = FALSE,
outputFolder = outputFolder,
outputFile = "Hospital_VN_2024.json",
writeToTable = TRUE,
checkLevels = c("TABLE", "FIELD", "CONCEPT"),
checkNames = c(), # empty = run ALL checks
tablesToExclude = c() # exclude nothing
)
2.3 ダッシュボードの表示
# Mở dashboard web
DataQualityDashboard::viewDqDashboard(
jsonPath = file.path(outputFolder, "Hospital_VN_2024.json")
)
# → Mở browser tại http://localhost:xxxx
3. DQD の結果
3.1 概要
┌─────────────────────────────────────────────────────────┐
│ Data Quality Dashboard — Hospital_VN_2024 │
│ CDM Version: 5.4 | Run Date: 2024-12-15 │
│ │
│ Total Checks: 1,547 │
│ PASS: 1,389 (89.8%) │
│ FAIL: 128 (8.3%) │
│ Not Applicable: 30 (1.9%) │
│ │
│ ████████████████████░░ 89.8% PASS │
│ │
│ By Category: │
│ ┌──────────────┬──────┬──────┬──────┐ │
│ │ Category │ Pass │ Fail │ % │ │
│ ├──────────────┼──────┼──────┼──────┤ │
│ │ Conformance │ 520 │ 35 │ 93.7%│ │
│ │ Completeness │ 380 │ 48 │ 88.8%│ │
│ │ Plausibility │ 489 │ 45 │ 91.6%│ │
│ └──────────────┴──────┴──────┴──────┘ │
└─────────────────────────────────────────────────────────┘
3.2 詳細なチェック — 適合性
FAIL checks — Conformance:
┌────────────────────────────────────────────────────────────────┐
│ Check: measureValueCompleteness │
│ Table: measurement │
│ Field: unit_concept_id │
│ Status: FAIL │
│ Threshold: ≤ 40% missing → FAIL │
│ Result: 42.5% records have unit_concept_id = 0 │
│ │
│ → 42.5% measurements thiếu unit (ví dụ: mg/dL, mmol/L) │
│ → Cần mapping units trong ETL │
├────────────────────────────────────────────────────────────────┤
│ Check: cdmField (isRequired) │
│ Table: drug_exposure │
│ Field: drug_exposure_end_date │
│ Status: FAIL │
│ Result: 15,230 records (8.2%) have NULL end_date │
│ │
│ → Required field bị NULL │
│ → ETL cần set end_date = start_date + days_supply │
└────────────────────────────────────────────────────────────────┘
3.3 詳細なチェック — 妥当性
FAIL checks — Plausibility:
┌────────────────────────────────────────────────────────────────┐
│ Check: plausibleValueLow │
│ Table: measurement │
│ Field: value_as_number │
│ Concept: Body weight (concept_id = 3025315) │
│ Status: FAIL │
│ Result: 85 records with weight < 0 kg │
│ │
│ → Âm? Impossible. Check ETL conversion │
├────────────────────────────────────────────────────────────────┤
│ Check: plausibleValueHigh │
│ Table: measurement │
│ Field: value_as_number │
│ Concept: Systolic BP (concept_id = 3004249) │
│ Status: FAIL │
│ Result: 120 records with SBP > 300 mmHg │
│ │
│ → SBP > 300: data entry error hoặc unit conversion error │
├────────────────────────────────────────────────────────────────┤
│ Check: plausibleTemporalAfter │
│ Table: drug_exposure │
│ Field: drug_exposure_end_date │
│ Status: FAIL │
│ Result: 350 records where end_date < start_date │
│ │
│ → Ngày kết thúc trước ngày bắt đầu: lỗi ETL │
└────────────────────────────────────────────────────────────────┘
4. しきい値の構成
4.1 カスタムしきい値
# DQD dùng file CSV threshold mặc định
# Có thể override cho từng check
# Xem thresholds mặc định
thresholds <- DataQualityDashboard::getDefaultThresholds()
head(thresholds)
# Custom threshold file
# threshold_overrides.csv:
# checkName,tableName,fieldName,conceptId,
# thresholdValue,notesValue
# measureValueCompleteness,measurement,unit_concept_id,,
# 50,Cho phép 50% missing vì legacy data
# plausibleValueHigh,measurement,value_as_number,3004249,
# 5,Chấp nhận 5% SBP outliers
4.2 チェックの除外
# Loại bỏ checks không áp dụng
DataQualityDashboard::executeDqChecks(
connectionDetails = connectionDetails,
cdmDatabaseSchema = "cdm",
resultsDatabaseSchema = "results",
cdmSourceName = "Hospital_VN_2024",
outputFolder = outputFolder,
# Chỉ chạy TABLE-level checks
checkLevels = c("TABLE"),
# Hoặc loại bỏ bảng không có data
tablesToExclude = c("note", "note_nlp", "specimen", "episode")
)
5. 改善の計画
5.1 優先順位マトリックス
Urgency vs Impact:
High Impact
│
Fix Now │ Critical
┌───────────┼───────────┐
│ Temporal │ Missing │
│ violations│ concept_id│
│ │ (mapping) │
│───────────┼───────────│ High
│ Outlier │ Missing │ Urgency
│ values │ required │
│ (few) │ fields │
└───────────┼───────────┘
Monitor │ Plan Fix
│
Low Impact
5.2 アクションプランのテンプレート
┌────┬───────────────────────┬──────────┬───────────┬─────────┐
│ # │ Issue │ Priority │ Owner │ ETA │
├────┼───────────────────────┼──────────┼───────────┼─────────┤
│ 1 │ 42.5% missing units │ HIGH │ ETL team │ Sprint 1│
│ 2 │ 350 end < start dates │ HIGH │ ETL team │ Sprint 1│
│ 3 │ 85 negative weights │ MEDIUM │ ETL team │ Sprint 2│
│ 4 │ 120 SBP > 300 │ MEDIUM │ Data QA │ Sprint 2│
│ 5 │ 8.2% NULL end_date │ HIGH │ ETL team │ Sprint 1│
│ 6 │ 12% unmapped codes │ MEDIUM │ Vocab team│ Sprint 3│
└────┴───────────────────────┴──────────┴───────────┴─────────┘
5.3 進行状況の監視
# Chạy DQD sau mỗi sprint
# So sánh kết quả qua thời gian
# Sprint 0: 89.8% PASS (baseline)
# Sprint 1: 93.2% PASS (+3.4%) — fixed temporal + missing fields
# Sprint 2: 95.1% PASS (+1.9%) — fixed outliers
# Sprint 3: 96.8% PASS (+1.7%) — improved mapping
# Mục tiêu: ≥ 95% PASS trước khi chạy analysis
6. CI/CD の統合
6.1 ETL 後に DQD を自動的に実行する
#!/bin/bash
# /opt/ohdsi/scripts/run_dqd.sh
echo "Starting DQD run: $(date)"
Rscript -e '
library(DataQualityDashboard)
library(DatabaseConnector)
connectionDetails <- createConnectionDetails(
dbms = "postgresql",
server = Sys.getenv("CDM_DB_SERVER"),
user = Sys.getenv("CDM_DB_USER"),
password = Sys.getenv("CDM_DB_PASS"),
port = 5432
)
results <- executeDqChecks(
connectionDetails = connectionDetails,
cdmDatabaseSchema = "cdm",
resultsDatabaseSchema = "results",
cdmSourceName = "Hospital_VN_2024",
outputFolder = "/opt/ohdsi/dqd_output",
outputFile = paste0("dqd_", Sys.Date(), ".json"),
writeToTable = TRUE
)
# Check pass rate
passRate <- results$overview$percentPassed
cat("Pass rate:", passRate, "%\n")
if (passRate < 90) {
quit(status = 1) # fail pipeline
}
'
if [ $? -ne 0 ]; then
echo "DQD FAILED: Pass rate below 90%"
# Gửi alert
exit 1
fi
echo "DQD PASSED: $(date)"
概要
| 成分 | 役割 |
|---|---|
| カーン フレームワーク | 3 つの次元: 適合性、完全性、妥当性 |
| DQD チェック | 1,500 以上の自動品質チェック |
| しきい値 | 設定可能な PASS/FAIL しきい値 |
| ダッシュボード | インタラクティブな Web レポート |
| 行動計画 | 改善の優先順位マトリックス |
| CI/CD | ETL を実行するたびに自動的にチェックします |
次の記事: HADES — 観察研究のための R パッケージ