(青島科技大學 信息科學技術學院,山東 青島 266000)
根據國際腎病協(xié)會、歐洲腎病學會-歐洲透析和移植學會、美國腎病學會估計,全球至少有8.5億人患有腎病,占世界總人口的11%[1]。在2017年全球發(fā)布的腎臟地圖中,僅慢性腎病每10個人就有一個人是患者,由此可見慢性腎病占比之高。而慢性腎病的發(fā)展不可逆轉,因而患者只能通過長期藥物治療來控制病情發(fā)展。若患者不盡早接受治療,極易出現(xiàn)病情惡化導致終末期腎臟病[2]。因此盡早進行診斷慢性腎病對于后期治療具有重大意義和價值。
隨著醫(yī)療信息化建設的推進,醫(yī)療數據量正在急劇膨脹,導致數據挖掘技術在醫(yī)療領域的應用也更加廣泛。目前數據挖掘應用于醫(yī)療領域主要是用來預防、診斷、治療和預后。應用于預防是通過尋找疾病的誘病因子以及通過疾病早期篩查來預防疾病。應用于診斷是利用電子病歷文本信息或圖像信息輔助[3]醫(yī)生對疾病進行診斷。應用于治療是通過關聯(lián)規(guī)則等算法挖掘出藥物對疾病的治療作用并且能制定臨床路徑,方便醫(yī)生開處方。應用于預后通過對原始數據的分析,能輔助預測患者手術后的身體指標狀況,從而起到預警作用[4]。本文研究的慢性腎病輔助診斷是數據挖掘應用于醫(yī)療診斷的體現(xiàn),并通過利用慢性腎病數據建立隨機森林分類模型對慢性腎病進行分類來建立慢性腎病輔助診斷系統(tǒng)。
本系統(tǒng)的主要工作是慢性腎病的輔助診斷,對于該系統(tǒng)的主要流程就是將患者的化驗信息以及患者的身份信息輸入到該系統(tǒng)中,通過已經訓練好的慢性腎病診斷模型,讓該模型對該患者進行診斷,判斷是否患有慢性腎病。本系統(tǒng)采用B/S架構[5]進行設計,分為顯示層、業(yè)務層、服務層和數據層,系統(tǒng)架構如圖1所示。
圖1 系統(tǒng)總體架構圖
按圖1所示,表示層是系統(tǒng)用于界面交互的一層,其重要利用HtmL和js進行編寫,用jsp輔助傳值,實現(xiàn)數據交互;業(yè)務層采用SSM框架[6]進行設計,用于實現(xiàn)系統(tǒng)的功能邏輯;服務層利用tomcat服務器進行項目部署工作;數據層采用oracle數據庫對數據進行存儲和處理。
本系統(tǒng)的腎病輔助診斷功能如圖2所示。
圖2 腎病輔助診斷系統(tǒng)框架圖
由圖2可以看出,本系統(tǒng)在功能上應具備以下幾個功能模塊。
2.1.1 化驗數據錄入模塊
該模塊的功能是將病人的基本信息和病人的本次化驗數據錄入系統(tǒng),提交診斷后進入后臺由腎病輔助診斷模型進行數據處理和慢性腎病診斷,最后將輸出結果0,1轉換成是否患有慢性腎病并輸出(0代表病人未患慢性腎病,1代表病人診斷結果為慢性腎病),并即時將結果顯示在頁面醒目的位置。
2.1.2 腎病輔助診斷模塊
該模塊有應具備兩部分功能:1)是腎病診斷模型構建功能,該模塊利用原始數據對慢性腎病輔助診斷模型進行構建。首先將原始數據集分為訓練數據集和測試數據集,然后利用訓練集訓練慢性腎病輔助診斷分類模型,利用測試集測試訓練后的模型性能,根據測試結果調節(jié)模型參數,以使模型達到最佳性能;2)是利用醫(yī)生輸入進來的基本信息和化驗項目參數封裝成實例對象通過慢性腎病輔助診斷模型進行診斷,并將診斷結果返回。
2.1.3 數據處理模塊
該模塊應具備的主要功能有:存儲診斷結果及化驗項目信息的功能、能夠即時查看患者歷史診斷記錄的功能、提供患者診斷記錄增、刪、改的功能。
2.1.4 用戶管理模塊
該模塊的主要功能是提供添加、刪除、更改用戶信息的功能及密碼修改重置功能。
2.2.1 化驗指標錄入模塊
該錄入模塊有病人基本信息(如化驗單號、姓名、年齡、性別等)5項,病人化驗指標(如血壓、比重、白蛋白、血尿素、血清肌酐等)23項,用v1~v23表示。其中只有v1~v23作為模型訓練的特征屬性被使用,病人基本信息只是為了方便醫(yī)生查找和數據庫記錄而被添加的。23項特征屬性如表1所示。
表1 慢性腎病輔助診斷模型特征屬性
由于純手工錄入這28個指標會耗時較長,為了解決時耗問題,本實驗設計了自動填充功能,利用AJAX[7]傳值如下:
/*
自動填充病人信息
*/
function fillInfo(keyword,keydate){
.ajax({
url:'{sysPath}patient/patientInfoSearch.do',
type:'POST', //GET
async:true, //或false,是否異步
data:{
keyword:keyword,
keydate:keydate
},
//timeout:5000, //超時時間
dataType:'json', //返回的數據格式:json/xml/html/script/jsonp/text
success:function(data,textStatus,jqXHR){
(" sampleNo").val(data[0].sampleNo); //sampleNo,化驗單號
(" patientId").val(data[0].patientId);
(" patientName").val(data[0].patientName);
(" sex").val(data[0].sex);
(" age").val(data[0].age);
(" v1").val(data[0].v1);
(" v2").val(data[0].v2);
(" v3").val(data[0].v3);
(" v4").val(data[0].v4);
(" v5").val(data[0].v5);
(" v6").val(data[0].v6);
.......... //省略部分為v7~v23的填充項
},
error:function(xhr,textStatus){
alert("系統(tǒng)錯誤");
},
complete:function(){
console.log('結束')
}
});
}
2.2.2 慢性腎病輔助診斷模塊
此模塊主要功能是利用輸入的化驗指標判斷該患者是否患有慢性腎病。因此該診斷模塊需要數據建模。本次慢性腎病輔助診斷建模利用隨機森林分類算法的建模方案如下:
1)隨機森林中決策樹的數目n是一個重要參數,需要根據設置數目的模型準確度反復調節(jié),一般設置為100~1 000,多次調節(jié)選取最優(yōu)參數;
2)將慢性腎病數據按是否慢性腎病分別1:1的比例劃分出訓練集和測試集,將腎病訓練數據進行有放回的隨機抽樣,抽取n次,得到n個樣本,每個腎病訓練數據樣本容量約為總樣本數的2/3;
3)屬性子集的選?。郝阅I病數據集的特征屬性有血壓、比重、白蛋白、血尿素、血清肌酐等共23個,設每次隨機選取的屬性子集中屬性的個數為x,log223約為4.5,取4,以4為屬性子集的屬性個數最小值,分別取4,5,6,7,8,9,10作為每次隨機選取的屬性子集中屬性的個數。以x=4為例,隨機抽取n個特征數目為4的特征子集進行建模實驗,用慢性腎病測試數據測試建模準確率;x=5時也進行相同實驗,將所有x不同取值的模型準確率進行對比,選擇最優(yōu)x的取值;
4)將n個樣本和n個屬性子集一對一組成n個決策樹;
5)將腎病測試樣本實例輸入到n個決策樹中,以投票法確認該測試實例的腎病類別即為隨機森林模型測得的腎病類別。
利用隨機森林算法建立慢性腎病輔助診斷模型的建模流程如圖3所示。
圖3 慢性腎病輔助診斷的隨機森林建模流程圖
本實驗按照上述隨機森林的腎病輔助診斷建模流程,利用weka[8]包里的隨機森林(randomForest)類建立分類模型,模型的訓練數據和測試數據來源于機器學習庫UCI的慢性腎病[9]數據集。該數據集共400條數據、24個特征屬性,2個診斷類別。本文將其分為200條訓練數據,200條測試數據對隨機森林模型進行訓練[10]。模型訓練測試設計如下:
public static void main(String[] args) throws Exception {
Classifier m_classifier = new WriteRandomForest();
File inputFile = new File("C:UsersAdministratorDesktopuciChronic_Kidney_Disease rain.csv.arff");
ArffLoader atf = new ArffLoader();
atf.setFile(inputFile);
Instances instancesTrain = atf.getDataSet(); // 讀入訓練文件
inputFile = new File("C:UsersAdministratorDesktopuciChronic_Kidney_Disease est.csv.arff");//A類下的測試語料文件
atf.setFile(inputFile);
Instances instancesTest = atf.getDataSet(); // 讀入測試文件
instancesTest.setClassIndex(instancesTest.numAttributes()-1); //設置最后一行為分類類別行。instancesTest.numAttributes()可以取得屬性總數
double sum = instancesTest.numInstances(),//取實例數
right = 0.0f;
instancesTrain.setClassIndex(instancesTest.numAttributes()-1);
m_classifier.buildClassifier(instancesTrain); //訓練
System.out.println(m_classifier);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:UsersAdministratorDesktop1RandomForest.model"));
oos.writeObject(m_classifier);
oos.flush();
oos.close();
// 保存模型
SerializationHelper.write("RandomForest.model", m_classifier);//參數一為模型保存文件,classifier4為要保存的模型
for(int i = 0;i { System.out.println(m_classifier.classifyInstance(instancesTest.instance(i))+","+instancesTest.instance(i).classValue()); if(m_classifier.classifyInstance(instancesTest.instance(i))==instancesTest.instance(i).classValue()) { right++;//正確值加1 } } // 獲取上面保存的模型 Classifier classifier8 = (Classifier) weka.core.SerializationHelper.read("RandomForest.model"); double right2 = 0.0f; for(int i = 0;i { if(classifier8.classifyInstance(instancesTest.instance(i))==instancesTest.instance(i).classValue()) { right2++;//正確值加1 } } Evaluation eval = new Evaluation(instancesTrain); //構造評價器 eval.evaluateModel(m_classifier, instancesTest);//用測試數據集來評價m_classifier System.out.println(eval.toClassDetailsString("===ClassDetailsString===")); System.out.println(eval.toSummaryString("=== Summary ===",false)); //輸出信息 System.out.println(eval.toMatrixString("=== Confusion Matrix ==="));//Confusion Matrix } 該隨機森林模型的主要參數是m_numTrees和m_KValue。其中m_numTrees代表的是隨機森林模型中樹的數目,KValue代表的是每個結點建造時選擇隨機特征的數量。本實驗默認樹數目100,默認隨機特征數量為log2(data.numAttributes()-1)+1。為了確定最優(yōu)參數,本文進行了多次實驗,將樹的數量分別設置為100,200,300,400,500,600,700,800,所得結果以折線圖的形式呈現(xiàn),見圖4。在樹的數量取到最優(yōu)的情況下,隨機特征的數量設置為4,5,6,7,8,9,10,所得結果見圖5。 圖4 隨機森林建模參數對照圖1 圖5 隨機森林建模參數對照圖2 由以上兩折線圖可以看出,當樹的數量取400時,分類準確率達到最優(yōu),此時準確率為92.5%。在樹數量取400的前提下,隨機特征數量為5時模型達到最大值,準確率為93.7%。因此當m_numTrees=400且m_KValue=5時,本次慢腎病輔助診斷實驗的隨機森林模型達到最優(yōu)準確率,為93.7%。本次慢性腎病輔助診斷系統(tǒng)設計將應用最優(yōu)參數進行系統(tǒng)設計實現(xiàn)。 2.2.3 數據處理模塊 該模塊主要有兩個功能:(1)是讓醫(yī)生可以查看病人診斷歷史記錄,可以通過病人ID、病人姓名查看某患者在該系統(tǒng)的所有歷史診斷記錄,通過化驗單編號可查患者唯一記錄。在數據列表展示區(qū)點擊化驗單編號可以看到患者此次診斷的詳細化驗信息和診斷結果信息,并且具備修改和刪除以及導出功能;(2)是數據庫設計[11],本文數據庫表結構如圖6所示。 圖6 腎病輔助診斷系統(tǒng)數據庫結構 用戶管理及密碼修改模塊:用戶管理模塊為僅系統(tǒng)管理員可見模塊,該模塊主要有用戶添加、編輯功能、用戶科室配置功能、用戶修改密碼功能。修改密碼功能通過輸入原密碼、新密碼和確認新密碼后,點擊確定修改即可。該部分有原密碼校驗功能、新密碼和確認新密碼是否一致功能。密碼校驗功能代碼如下: /** * 校驗新舊密碼 */ function checkContent() { var oldPWD =.trim((" oldPWD").val());//舊密碼 var newPWD1 =.trim((" newPWD1").val());//新密碼 var newPWD2 =.trim((" newPWD2").val());//確認新密碼 if (oldPWD == null || oldPWD == undefined || oldPWD == "") { alert("舊密碼不能為空!"); return false; } if (newPWD1 == null || newPWD1 == undefined || newPWD1 == "") { alert("新密碼不能為空!"); return false; } if (newPWD2 == null || newPWD2 == undefined || newPWD2 == "") { alert("確認新密碼不能為空!"); return false; } if (oldPWD == newPWD1) { alert("新密碼與原密碼一致!"); return false; } if (newPWD1 != newPWD2) { alert("新密碼與確認密碼不一致!"); return false; } } 該模塊在用戶通過正確輸入用戶名和密碼,登錄成功后進入系統(tǒng)界面如圖7所示。 圖7 腎病輔助診斷系統(tǒng)主頁 從主界面上看該系統(tǒng)一共分為3部分,分別是指標錄入平臺、選擇查詢平臺以及系統(tǒng)幫助平臺。指標錄入平臺和選擇查詢平臺分別是對患者化驗項目指標的錄入和對已經診斷的患者記錄進行查詢。系統(tǒng)幫助平臺的本地用戶管理僅系統(tǒng)管理員可見,修改密碼功能普通用戶可使用。 指標錄入模塊是醫(yī)生用來將患者的基本信息和化驗指標輸入到系統(tǒng)中,該部分利用了AJAX傳值通過輸入患者化驗單號后使用自動填充功能,無需醫(yī)生再輸入患者的其他信息就可以將該患者的所有信息自動填充到頁面中。 慢性腎病輔助診斷指標錄入頁面如圖8所示。 圖8 指標錄入模塊頁面 該模塊通過錄入病人基本信息及化驗結果后點擊“診斷”按鈕,數據就會被后臺診斷功能接收并處理,并將診斷結果以JS彈框輸出,方便醫(yī)生查看輔助診斷結果。同時,診斷數據和診斷醫(yī)生也被保存到數據庫中,方便醫(yī)生查看歷史診斷記錄。 該模塊主要為用作醫(yī)生查看病人診斷歷史記錄,可以通過病人ID、病人姓名查看某患者在該系統(tǒng)的所有歷史診斷記錄,通過化驗單編號可查患者唯一記錄。在數據列表展示區(qū)點擊化驗單編號可以看到患者此次診斷的詳細化驗信息和診斷結果信息,并且具備修改和刪除以及導出功能。該模塊如圖9所示。 圖9 診斷結果查詢頁面 用戶管理模塊為僅系統(tǒng)管理員可見模塊,該模塊主要有用戶添加、編輯功能、用戶科室配置功能、用戶重置密碼功能。 用戶科室配置功能頁面如圖10所示,該功能在用戶點擊進入該頁面時先從session中調取用戶的科室,然后查詢除用戶所在科室以外的所有科室,將結果放入“未在科室”的控件中。通過“>>”可將用戶“所在科室”刪掉,并且“未在科室”會增加所刪內容;通過“<<”可將“未在科室”中選中的內容放入到用戶“已在科室”,即添加用戶“已在科室”,同時“未在科室”作相應刪減。配置科室功能是為以后研究其他疾病的輔助診斷功能預留了空間[12]。 本文利用數據挖掘的隨機森林分類技術和web開發(fā)技術[13]構建了慢性腎病輔助診斷系統(tǒng)[14]。該系統(tǒng)通過對病患的基本信息數據和化驗指標數據的錄入,利用數據挖掘隨機森林分類模型對患者是否患有慢性腎病進行分類,并將 圖10 用戶科室配置頁面 分類結果通過JS彈框形式及時返回到頁面,直觀地便于醫(yī)生查看慢性腎病輔助診斷結果,同時將診斷信息存入數據庫以備醫(yī)生查詢該患者的歷史診斷記錄。該系統(tǒng)在功能上可以給經驗不足的腎病醫(yī)生提供借鑒,從而幫助他們提高診斷技能,降低誤診率,從而使患者盡早進行正確的治療,避免慢性腎病治療延誤帶來的嚴重后果。3 系統(tǒng)效果
3.1 系統(tǒng)登錄模塊
3.2 腎病輔助診斷指標錄入及診斷模塊
3.3 腎病診斷記錄查詢模塊
3.4 用戶管理及密碼修改模塊
4 結束語