目前分類:SAS程式編輯武功秘笈 (36)

瀏覽方式: 標題列表 簡短摘要

 

若想將整個欄位的資料移動到下一格,可使用函數LAG(),若想直接計算上下兩筆資料間的數值差,可使用函數DIF(),請參考以下的示範:

利用以下程式建立一個資料檔aa, 若想計算前後兩次門診的時間間隔,可直接利用dif(opd_date)計算兩次門診的時間差,若想將門診日期向下移動,可利用lag(opd_date)

[程式一]
data aa;
        input opd_date yymmdd10.;/*-門診日期-*/
                 lag_date=lag(opd_date);

文章標籤

estat 發表在 痞客邦 留言(3) 人氣()

 

以下為簡易的Dummy variable(虛擬變項)的建立,在回歸分析中,當解釋變數為類別型資料,例如藥物的濃度分為4類,其中一類為參考組,則每一組將與參考組作比較,比較的組數有3組。在回歸模式中不能直接放該類別變項(CON_GRP),否則會視同連續型資料。

因此需要設3Dummy variable,例如以下程式的CON_1~CON_3,當3個變項為0(0,0,0),該組為參考組,當CON_11(1,0,0),為第一組與參考組間的比較,其他以此類推。而Dummy variable的程式語法如[程式一]CON_GRP=1時,CON_1=1CON_GRP=2時,CON_2=1CON_GRP=3時,CON_3=1,其他非1的數值,自動生成為0

[程式一]

data aa1;
set aa;
CON_1=(CON_GRP=1); /*Dummy variable*/
CON_2=(CON_GRP=2);
CON_3=(CON_GRP=3);
run;

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

Logistic Regression與線性迴歸最大的不同是依變項性質的不同,使得兩者在參數估計與假設上也有所不同,前者的結果變項(outcome)為類別型資料(categorical data),後者為數值型資料(numeric data)Logistic Regression分析的假定:觀察值樣本在依變項上的機率分配呈S型分佈,此分佈又稱Logistic分配。

Logistic Regression
最常應用在流行病學的Case-Control study,常見的指標是勝算比(Odds Ratio),其意義為得病的人有暴露與未暴露的比值(勝算; odd)相對於未得病的人有暴露與未暴露的比值,該值=1表示疾病與暴露間的相關性不高。由exp(β)可求得Odds RatioβLogistic Regression的估計參數。

SAS
的程式如下:以proc logistic程序分析,dependent為結果變項, 通常1為有病,0為沒病,Group為解釋變數,在此為組別,通常為有暴露(EXPOSURE)或沒暴露(NON- EXPOSURE)於特定風險的兩個組別。descending為設定dependent=0為參考組,RISKLIMITS為列出95%信賴區間。以SASODS功能(Output Delivery System)parameterestimates(參數估計值)存成SAS檔,包含p value也一起存出來,存成檔案pp;以ODS oddsratio及其95%信賴區間存出,存成檔案qq

最後利用merge指令將參數估計值與oddsratio的結果合併成一個檔案,即可直接整理至發表要用的表格上,如表格所示。

[
程式一]

文章標籤

estat 發表在 痞客邦 留言(1) 人氣()

 

如果收回的問卷,在日期部份將年、月、日各別輸入資料檔中,但當要計算時間或年齡時卻不知所措,該怎麼辦?SASMDY(month,day,year)函數可以將年月日重新組成一個新的日期,如此就可進一步計算了。

以下建立一個資料檔為AA,輸入(INPUT) YEAR, MONTH, DAY等變數。利用MDY()產生一個新變項BIRTHDAY,這個變數是透過YEAR, MONTH, DAY所組成,年月日變數依MDY()中的MONTH,DAY, YEAR順序依序放入,再以FORMAT指令將BIRTHDAY變數轉成YYMMDD10.的格式,即西元年--日,就完成日期的組合(參見程式與結果)

[ 程式 ]

data aa;
input year month day;
birthday=mdy(month,day,year);
format birthday yymmdd10.;

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

時間間隔的計算,在許多研究中是很重要的,包括用藥時間、存活時間、居住時間、曝露在特定污染環境的時間、住院時間等。所使用的SAS函數為INTCK('interval',from,to)'INTERVAL'為起迄時間的時間間隔,單位可以是day, week, month, quarter, year等。FROMTO各是「起」與「迄」的時間。

[程式一] 建立一組起迄時間,依序是start_date, end_date,日期格式是yymmdd10.,即西元年-
-日的格式。

[程式二] 在程式二中產生了5個變項(VARIABLE)DAY, MONTH1, MONTH2, YEAR1, YEAR2DAY為介於起迄間的天數;MONTH1為以SAS
預設的MONTH算起迄間的月數,從結果可知SAS將取整數的月數(128個月),小數點會被捨去(即無條件捨去)MONTH2為以DAY除以30.475計算精準的月數(128.263個月);同樣地YEAR1為以SAS預設的YEAR計算的起迄間的年數,從結果可知,SAS將取整數的年數(10),小數點會被捨去(即無條件捨去)YEAR2為以DAY除以365.25(4年潤年一次)計算精準的年數(10.6886)

[
程式一];
data aa;
input id $ start_date yymmdd10. end_date yymmdd10.;

文章標籤

estat 發表在 痞客邦 留言(3) 人氣()

 

SASLibraries/Maps下有一個檔案Taiwan, 記錄了台灣各縣市的經緯度,透過SASproc gmap,我們可以將表格內容地圖化,以民國100年各縣市之標準化死亡率為例,透過地圖化,可以很快地看出死亡率的高低與各縣市的都市化程度有關。[參見台灣地圖]


[程式一] 建立民國100年各縣市之標準化死亡率資料檔,SDR為標準化死亡率。[: 因為各縣市人口結果不同,故以2000年世界標準人口調整後的標準化率作比較]


[程式二] 為不同等級的死亡率設定在地圖上的色塊,例如 pattern5 v=ms c=brown; 其中V=MS指明區塊為實心,c=brown指明區塊顏色為棕色。


[程式三] PROC FORMAT/VALUE介定區塊對應的標準化率值,並形成一個格式化名稱degfmt,任何一個變項套用這個格式,數值在300-400間的就被定義為'350-400',其他以此類推。


[程式四] proc gmap畫地圖,map=maps.taiwan說明引用的地圖經緯來自目錄館為MAPS下的資料檔TAIWAN,繪圖的來源檔為data=aa以各縣市(ID)標示區塊,並將將SDRdegfmt. 格式套用。

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

在臨床資料或健保資分析中,時間點的定義是很重要的,例如用藥後6個月、發病前1年、住院後7天等,至於這些時間點該如何標示,是今天要介紹的重點,通常我們會採用的時間函函數為 intnx( )。函數的語法為INTNX(interval, start-from, increment)

[
程式一] 利用[程式一]建立一筆資料,共有2個欄位,身份證號(ID)、就醫日期(in_date),日期格式為yymmdd10.,即yyyy-mm-dd格式, 

[程式一];

data aa;
input id $ in_date yymmdd10.;
format in_date yymmdd10.;
cards;

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

健保資料庫的描述性統計中,常見的是計算患者的醫療費用、用藥天數、用藥的累積劑量或平均劑量等。究竟要如何透過程式語法依特定變項分層計算呢?今天將介紹SAS中的描述性統計: PROC MEANS指令。

[程式一] 建立檔案AA,檔案中有身份證號(ID)、性別(SEX)、居住地區(AREA)、醫療費用(FEE)、就醫日期(IN_DATE)5個欄位的資料。


[程式二] 利用PROC MEANS計算檔案AA中的醫療費用(FEE),但要依性別(SEX)、居住地區(AREA)分層計算,且描述醫療費用(FEE)的使用人數(n)、總和(sum)、平均值(mean)、中位數(median),因此VAR後面放醫療費用(FEE)CLASS指令後面放的是分層變數sex, area。將分層計算後的統計量存成檔案BB,檔案中的欄位名稱以與nsummeanmedian統計量同名的名稱來命名,報表見[結果一]


[程式三] [程式二] DATA=AA之後為何要加NWAY指令? 這個指令的用意在於取SEX, AREA分層的最大組合,什麼意思呢?若將[程式二] NWAY ,以及OUT=BB(DROP=_TYPE_ _FREQ_)中的(DROP=_TYPE_ _FREQ_)刪除,結果將如[結果二]所呈現。其中,_TYPE_=0為完成不分層的情況,_TYPE_=1_TYPE_=2為以AREASEX變數分層的結果,_TYPE_=3為同時考慮SEXAREA 2個變數的組合下的分層結果, DATA=AA之後加NWAY指令的目的即是取_TYPE_=3的統計結果。[見結果二]


文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

健保資料庫中的國際疾病分類碼(ICD9-CM)在資料分析中,可以用來定義感興趣的疾病,在『門診處方及治療明細檔』有3個欄位記錄國際疾病分類碼;『住院醫療費用清單明細檔』則有5個欄位。究竟要如何透過國際疾病分類碼定義疾病?一般的作法是請益臨床的醫師或其他專業人員,以瞭解一個疾病是透過幾個分類號(ICD9_CM)構成,例如糖尿病是ICD9-CM3碼為250的分類號。但病歷登錄時,有時會登錄到4位碼(例如2500為未提及併發症之糖尿病),有時會登錄到5(例如25003為第一型糖尿病,未提及併發症,無法控制)。若不需要分類到4位或是5位碼,只是以3位碼250代表所有的糖尿病,程式將如何撰寫?今日將介紹子字串函數:SUBSTR( VARIABLE, POSITION, LENGTH)

[程式一] 建立3個患者的資料,以INPUT指令讀入ID (身份證號)ICD9_CM1~ICD9_CM3(國際疾病分類號一至國際疾病分類碼三),資料型態皆為文字型($)


[程式二] PROC CONTENTS 指令查看資料檔AA的資料結構,在CONTENTS後面加上POSITION,是為了以資料建立時的欄位順序呈現資料結構,否則會以欄位名稱的字母作排序。在輸出的結果中可看到每一個欄位的順序, 欄位名稱,以及資料型態,透過這支程式可以快速建立譯碼簿(CODE BOOK)

[程式三] 透過IF指令擷取ICD9_CM中,前3碼為250(糖尿病)以及493(氣喘)的患者,因為『門診處方及治療明細檔』有3個欄位記錄國際疾病分類碼,因此每一個欄位都要檢查看看,是否有前3碼為250以及493的代號。因為文字串的資料都是左靠,因此可以由每一個ICD9_CM的最左邊的第一個字元,向右取3個字元,如此即將前3碼為250(糖尿病)493(氣喘)的患者取出。substr(ICD9_CM1,1,3)係指被擷取部份子字串的欄位是ICD9_CM1,從第1個欄位開始擷取,擷取的寬度是3個字元。此外程式中以IN 代替等號"=",且將要定義的疾病碼放在括號 ( )中,如此,可在括號( )中放2個以上的代碼,使程式更為精簡。結果,只有2個患者有250493的代碼(參見[結果])

是不是很簡單呢?

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()


今天要介紹另一支「歸戶」程式,主要的指令是SORTNODUPKEY。昨天的主要語法是first.var=1,透過10指定擷取的資料為第一筆或非第一筆NODUPKEY指令則在刪除重覆的資料,言下之意是只取第一筆,如何定義第一筆呢?

[程式三] 首先要以SORT指令將id,birthday排序,如此一來,就可以一目瞭然地看到哪幾筆資料是同一人的,藉此就可以定義排在最前面的id, birthday是第一筆,之後為重覆,加了NODUPKEY後,重覆的筆數就被刪除。被排序的資料檔為aa ,指令為data=aa;輸出的結果為bb ,指令為out=bb,是不是比FIRST.VAR=1的指令簡單呢?


[程式四] 若大家還記得昨天的資料,A01患者的就醫日期還沒排序呢,因此排序時要多加in_date,但是...支程式執行的結果會是什麼呢?就是...id, birthday取完每一個人的第一筆之後,再考慮一個人有好幾筆不同的就醫日期,每筆就醫日期都不重覆,於是所有的就醫日期都納入了,最後,等於沒有歸戶,因為所有的資料又全被擷取回來,該怎麼辦呢?方法很簡單的,不用耽心。

[程式五] 為先單獨將id, birthday, in_date排序,再執行SORTNODUPKEY的指令,就能找到真正的第一筆了。

然而,想擷取資料庫中的最後一筆,該如何執行呢?

文章標籤

estat 發表在 痞客邦 留言(1) 人氣()

 

「歸戶」是健保資料庫的資料處理過程中少不了的步驟,因為健保資料不是為學術目的而生成,而是為申請健保費用而存在的,因此資料庫中記載了每一次的就醫日期、就醫診斷、處置與費用等。若我們想知道每一個費用申報年有多少病人就醫?就必須透過「歸戶」的程序將一人多筆的資料轉為一人一筆,即可知每一個費用申報年有多少病人就醫。今天要介紹的是 first.var=1的語法。

[程式一]以程式寫入1個資料檔aa,放入id(身份證號)birthday(生日)in_date(就醫日期)icd9_cm1(
國際疾病診斷碼)id icd9_cm1為文字型態的欄位;birthday,in_date為日期格式yymmdd10. format birthday in_date yymmdd10.;係指定birthday, in_dateSAS格式是yymmdd10.,這種型式指的是西元年--日,寬度共10個位元(byte)

[
程式二]若大家有留意,會發現二件事:()資料檔aa中的第一筆資料非idA01患者的第一筆就醫日期,()A01的第4筆出生日期與前3筆不同,若研究者想取每人的一筆資料,而且是每一個費用申報年的第一筆,資料就必須利用SORT指令先將id, birthday, in_date排序。為什麼要加入birthday?因為國人的戶政會出現不同的人擁有相同id的情況,因此認定資料是否為同一人的條件必須同時加入idbirthday。再加入in_date的目的,是為了讓入院日期由前排到後。接下來,利用DATA指令產生新的檔bb,且由SET指令讀取檔案aaby id birthday; 這段程式說明以下的擷取第一筆的動作,要以id, birthday辨別哪幾筆是同一人的資料。 if (first.id=1 & first.birthday=1) | (first.id=0 & first.birthday=1);這段程式是歸戶的主要動作,簡略地表達,可以將左式改為IF A | B; A=(first.id=1 & first.birthday=1),意即先取每人的idbirthday的第一筆;B=(first.id=0 & first.birthday=1),即在相同的id中,若id不是第一筆,但birthday第一次出現,要取出來。如此即完成擷取每人的第一筆資料的歸戶動作,檔案aa中包含3個人的資料,您的程式寫對了嗎?([結果])

大家練習看看,若要依每一個就醫年度去擷取每人的第一筆,歸戶程式該如何寫?

[
程式一];

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

 

健保資料庫的資料處理過程有許多資料合併的步驟,可知道您在合併什麼嗎?過去常有人問門診檔與住院檔要怎麼合併?用SET?還是用MERGE?其實要看您的研究目的,以及您要合併的檔案內容。無論用什麼方式,或選用什麼樣的軟體,合併前必須注意三件事,首先要注意串聯兩個檔的關鍵變項(KEY VARIABLE)之名稱、屬性(文字、數值、日期)、資料寬度是否一致,其次,兩個檔案間是否還有除了關鍵變項以外,名稱與屬性一樣的變項,它會干擾合併的結果。


[程式一] 以程式寫入2個資料檔bb, cc,都放入id(身份證號)date(就醫日期)fee(醫療費用)id為文字型態的欄位;date為日期格式yymmdd10. fee為數值型態。但檔案bb與檔案ccdatefee內容並不一樣。format date yymmdd10.;係指定dateSAS格式是yymmdd10.,這種型式指的是 西元年--日,寬度共10個位元(byte)


[程式二]利用MERGE將兩檔串聯起來,  id為關鍵變項。根據結果一,會發現檔案dd的第一筆datefee都被檔案cc的第一筆取代,這真的是研究者要的結果嗎?(見結果一)

[程式三]若要同時保留所有資料檔的訊息,可以將其中的一個檔的datefee重新命名,利用RENAME指令進行修改,將date改成date1fee改成fee1,結果請見結果二。

很簡單的步驟,但真的要知道自己在合併什麼?而且一定要檢查合併結果是否符合預期。

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

   

在分析健保資料庫時,資料的合併是一個很重要的過程,但往往出錯的地方也是在此,今日要以數學「集合」的觀念來探討資料的合併,曾經有醫師抱怨這個部份很難懂,若以圖像的方式來解說,那麼就可一目瞭然了。

首先,利用 [程式一] [程式二]寫入一組資料檔,第一組的檔名為aa第二組的檔名為bb。利用INPUT指令放入一個變項 ID"$"符號說明ID屬於文字變項,@@宣告即將輸入一列多筆的資料。


大家若稍微觀察一下將發現,檔案bbaa多了17 18 19 20 21 22 23 24 25 ID;檔案aabb多了26 27 28 29 30 31 32 33 34ID,利用這兩個檔,我們來練習看看,如何進行資料的水平合併(Merge) [: SET指令後方若放兩組以上的檔案,稱為垂直合併,新的資料筆數是所有檔案的筆數總合]

[
程式三]是大家至為熟悉的程式,DATA指令後面指定新的檔案名稱為cc,透MERGE(合併)指令將檔案aa與檔案bb合併起來。但兩個檔案的後面分別加了(in=a)(in=b)的指令,它的目的即將檔案aa命名為集合a,將檔案bb命名為集合b,再以BY指令指定合併的關鍵字(KEY WORD)ID,寫上RUN(執行)即已完成,此時兩檔的所有資料都被合併進來,如圖1所示。


[
程式四][程式三]的加強說明,在by id之後,若加上if a|b;,即說明納入的ID是來自a集合或b集合,是聯集的概念。其意義與[程式三]是一致的,但我們一般不會畫蛇添足地多寫這麼一段。(見圖1) [ a|b'|'為英文字 "or"之意 ]

文章標籤

estat 發表在 痞客邦 留言(1) 人氣()

 

當我們將大批有規律的檔名讀進來,並經由巨集指令(Macro language)轉換成流水號形式的檔名,但最終還是要將每一個檔合併起來,若不以巨集指令合併檔案,傳統的作法即如[程式一]所示,利用SET語法將468個檔案合併起來,利用DATA令宣告新的檔名為e.cd,因此需要把檔名書寫468次,過程必須如屢薄冰般的謹慎。今日將以巨集指令的兩個範例[程式二][程式三],示範大批資料的合併。



[程式一]

data e.cd;
set e.cd1 e.cd2 e.cd3 e.cd4 e.cd5 e.cd6 e.cd7 e.cd8 e.cd9 e.cd10 .......e.cd468;
run; 

[程式二] %macro宣告將執行巨集指令,且巨集名稱(macro name)m1,並未給定任何參數,%mend說明巨集結束於此。巨集的迴圈為程式段[%do i=1 %to 468; ]。利用DATA指令將新的檔案命名為e.cd,以SET指令讀取一個空的檔,檔名為_NULL_NULL這個英文字即是零或虛無的意思,因為讀取零筆資料,所以DATA指令所建立的新檔案E.CD也是空的。這是一個預備動作,彷彿拿了一個空籃子,準備將球一個一個丟進來,而空藍子指得是哪一個檔呢? [答案; E.CD]

文章標籤

estat 發表在 痞客邦 留言(2) 人氣()


過去已介紹檔案間沒有關鍵字將如何合併?(資料的合併)利用該程式,今日要教各位如何讀取大批命名有規律的檔。

自「全民健康保險研究資料庫」釋出後,大型資料的研究已是台灣學術研究的優勢,在國際學術期刊上已有亮麗成績,「衛生福利資料科學中心」如今亦開放健保資料庫、癌症登記檔與死亡檔的資料比對,但面對全國性的龐大資料檔,光是讀檔案的步驟,就是惱人的大工程。不用著急,也毋需土法煉鋼,今天的程式可以讓大家以後讀檔更輕鬆了。

以下將以讀取「衛生福利資料科學中心」之健保民國87-99年「門診處方及治療明細檔」為例,其中一個檔名為h_nhi_opdte8702_01。如何拆解這個檔名呢?h_nhi_opdte 在龐大的檔案群是固定的87為年份,02為月份,01為西醫(0203為牙醫與中醫),因此所有檔案讀進來,一年有36個檔13年有468個檔,如何讀取這麼龐大的檔案群呢?

[程式一] 利用程式寫入3個資料檔,第一個資料檔檔名為year,僅放入民國年資料;第二個資料檔檔名為month,僅放入月份資料;第三個資料檔檔名為group,僅放入醫療型態(西醫、牙醫、中醫)資料。


文章標籤

estat 發表在 痞客邦 留言(1) 人氣()

 

當資料合併時必須要有一組關鍵字(KEY WORD)存在於每一個欲合併起來的檔案中,但沒有關鍵字時結果將如何?

舉以下的例子來聊聊

以下有一個經過3個資料檔合併後的檔案,這3個檔各只有一個變項: year(87~99), month(01~12), group(10~30),且3個檔的內容完全不同
但彼此間沒有關鍵字。過去我們將會寫以下這麼一隻程式(如程式一),如下所示, 其中合併後的檔案為ymg3個檔案的檔名依序為year, month, group,結果資料合併後如結果一。

 

data year; /*--檔案1 --*/

 

do year= 86 to 98;

文章標籤

estat 發表在 痞客邦 留言(0) 人氣()

«12