前幾天已經陸續完成缺失值、資料格式、數值範圍、重複資料以及資料一致性的檢查。
不過目前這些功能都是分開測試的,如果之後真的要拿來檢查一份醫療資料,每一個檢查都要分別執行會比較麻煩。
所以今天的目標,就是把前面完成的功能整合起來,讓PHP可以一次讀取CSV,並同時進行多種資料品質檢查,最後統一整理出檢查結果。
一、整合五種資料品質檢查
首先先建立各種問題的計數變數:
$missingCount = 0;
$formatCount = 0;
$rangeCount = 0;
$duplicateCount = 0;
$consistencyCount = 0;
另外也建立了$affectedPatients,用來記錄有哪些病人有發現問題。
$affectedPatients = [];
這樣可以避免同一位病人有多個問題時,被重複計算成不同的人。
二、整合缺失值檢查
首先檢查每一個欄位是不是空白。
foreach ($row as $index => $value) {
if (trim($value) === '') {
$missingCount++;
$affectedPatients[$row[0]] = true;
echo '【缺失值】' . $row[0] . ' → '
. $header[$index] . '<br>';
}
}
如果發現空白資料,就會增加$missingCount,並記錄這筆資料所屬的病人。
例如目前的測試資料中,P002的gender 空白,因此會被判定為缺失值。
三、整合資料格式檢查
接著檢查年齡、性別和就診日期的格式。
例如年齡必須是數字:
if (!is_numeric($row[1])) {
$formatCount++;
$affectedPatients[$row[0]] = true;
echo '【格式錯誤】' . $row[0]
. ' → age = ' . $row[1] . '<br>';
}
性別則限制為「男」或「女」:
if ($row[2] !== ''
&& $row[2] !== '男'
&& $row[2] !== '女') {
$formatCount++;
$affectedPatients[$row[0]] = true;
echo '【格式錯誤】' . $row[0]
. ' → gender = ' . $row[2] . '<br>';
}
日期則檢查是否符合YYYY-MM-DD的格式:
if ($row[8] !== ''
&& !preg_match('/^\d{4}-\d{2}-\d{2}$/', $row[8])) {
$formatCount++;
$affectedPatients[$row[0]] = true;
echo '【格式錯誤】' . $row[0]
. ' → visit_date = ' . $row[8] . '<br>';
}
四、整合數值範圍檢查
除了確認資料是不是數字,也需要確認數值是否落在這次測試設定的合理範圍內。
目前設定:
age:0~120
heart_rate:30~200
例如:
if (is_numeric($row[1])) {
if ($row[1] < 0 || $row[1] > 120) {
$rangeCount++;
$affectedPatients[$row[0]] = true;
echo '【數值異常】' . $row[0]
. ' → age = ' . $row[1] . '<br>';
}
}
心率也是使用相同的方式:
if (is_numeric($row[6])) {
if ($row[6] < 30 || $row[6] > 200) {
$rangeCount++;
$affectedPatients[$row[0]] = true;
echo '【數值異常】' . $row[0]
. ' → heart_rate = ' . $row[6] . '<br>';
}
}
這裡設定的範圍主要是為了這次資料品質檢查的測試,並不是醫療診斷標準。
五、整合重複資料檢查
接下來是前一天完成的重複資料檢查。把整列資料組合成一個字串,再利用陣列確認之前是否已經出現過。
$data = implode('|', $row);
if (isset($rows[$data])) {
$duplicateCount++;
$affectedPatients[$row[0]] = true;
echo '【重複資料】' . $row[0] . '<br>';
} else {
$rows[$data] = true;
}
目前測試資料中,P009有兩筆完全相同的資料,因此會被判定為重複資料。
六、整合資料一致性檢查
最後加入資料一致性的檢查。
例如性別雖然有些資料代表的是男性,但寫法不一致:
if ($row[2] === '男性' || $row[2] === 'M') {
$consistencyCount++;
$affectedPatients[$row[0]] = true;
echo '【格式不一致】' . $row[0]
. ' → gender = ' . $row[2]
. ' → 建議修正為:男<br>';
}
日期也是一樣,如果使用/而不是-,就會提示建議修改的格式:
if ($row[8] !== ''
&& preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $row[8])) {
$consistencyCount++;
$affectedPatients[$row[0]] = true;
$standardDate = str_replace('/', '-', $row[8]);
echo '【格式不一致】' . $row[0]
. ' → visit_date = ' . $row[8]
. ' → 建議修正為:' . $standardDate . '<br>';
}
七、統計最後的檢查結果
完成所有檢查後,再統一計算總問題數以及有問題的病人數。
$totalIssues = $missingCount
+ $formatCount
+ $rangeCount
+ $duplicateCount
+ $consistencyCount;
$affectedPatientCount = count($affectedPatients);
$affectedRate = ($affectedPatientCount / $totalRows) * 100;
最後將結果顯示在網頁上:
echo '<h3>資料品質問題統計</h3>';
echo '資料總筆數:' . $totalRows . ' 筆<br>';
echo '缺失值:' . $missingCount . ' 筆<br>';
echo '格式錯誤:' . $formatCount . ' 筆<br>';
echo '數值異常:' . $rangeCount . ' 筆<br>';
echo '重複資料:' . $duplicateCount . ' 筆<br>';
echo '一致性問題:' . $consistencyCount . ' 筆<br>';
echo '<br>';
echo '有問題的病人數:' . $affectedPatientCount . ' 人<br>';
echo '有問題的資料比例:'
. number_format($affectedRate, 1) . '%<br>';
echo '<strong>總問題數:'
. $totalIssues . ' 筆</strong><br>';