SAS---修改SAS資料集
第三章 修改SAS資料集
一.利用視窗編輯資料
上一章我們介紹過利用FSEDIT和FSVIEW過程建立SAS資料集,並在新的資料集中輸入資料。現在,我們介紹利用FSEDIT和FSVIEW過程對已有的SAS資料集中的資料進行編輯和修改。
1.呼叫FSEDIT或FSVIEW過程
首先,我們要進入FSEDIT或FSVIEW窗口才能進行編輯,呼叫FSEDIT或FSVIEW過程的一般形式為:
PROC FSEDIToptions;
或 PROC FSVIEW options;
例:proc fsedit data=clinic.admit label; run;
或 proc feviewdata=clinic.admit; run;
在程式編輯器中輸入上述程式,並提交,就可進入FSEDIT或FSVIEW視窗,對指定的SAS資料集進行編輯。
2.用FSEDIT過程編輯資料
1)改變當前顯示的資料
在FSEDIT視窗中,每次顯示一條觀測的內容,為改變其中某一變數的內容,可利用TAB鍵將游標移至相應位置,輸入新值,將舊值覆蓋即可。
2)改變當前顯示的觀測
在FSEDIT視窗中,只能改變當前顯示的觀測中的內容。為了改變多條觀測中的內容,你需要改變當前顯示的觀測,你可以利用下列操作命令在不同觀測之間移動:
操作命令 功能
View à Next observation 顯示下一條觀測
View à Previous observation 顯示下一條觀測
3)改變當前顯示的螢幕
有時候,SAS資料集中的變數太多,無法在一個螢幕(screen)中顯示,只好用多個螢幕顯示一條觀測的內容,發生這種情況時,系統會在你FSEDIT視窗時給你一個提示,例如:
NOTE:This application uses 2 screens.
為了編輯觀測中的某一個變數的資料,你可能需要在不同的螢幕之間移動,你可以使用下列操作命令:
操作命令 功能
View à Next screen 顯示下一個螢幕
View à Previous screen 顯示下一個螢幕
4)取消修改
如果你在修改某個資料後發現有錯,你可以用下述操作取消修改:
FileàCancel
該資料會恢復原先值。注意,你必須在離開當前觀測之前才能取消修改,一旦移到其它觀測,就無法再恢復原先值了。
5)結束編輯
當你完成資料集的修改後,可用下述操作結束FSEDIT過程:
Fileà End
結束過程時,你對資料集所做的修改會被自動儲存。
3.用FSVIEW過程編輯資料
在FSVIEW視窗中,你可以對以表格形式顯示的資料進行修改。
1)修改資料
FSVIEW視窗剛開啟時,其預設模式是瀏覽模式,也就是說這時候你不能改變它的內容,在FSVIEW視窗的標題欄中會顯示一個字母‘B’,例如:
FSVIEW: CLINIC.ADMIT2 (B)
為了對SAS資料集進行修改,要將FSVIEW視窗的模式改為編輯模式,可如下操作:
EditàUpdate àRECORD
這時,FSVIEW視窗的標題欄中會顯示一個字母‘B’,例如:
FSVIEW: CLINIC.ADMIT2 (E)
在這種模式下,你每次可對一條觀測進行修改,將游標移到你想要修改的觀測處即可進行。
2)改變顯示
FSVIEW視窗可顯示多條觀測,每一行顯示一條觀測,但一般來說,一個螢幕不可能顯示一個數據集中所有的內容。你可以使用滾動欄,或功能鍵來改變當前螢幕中顯示的內容。功能鍵應對應下列命令:
Forward
Backward
Right
Left
你可以開啟KEYS視窗檢視或改變功能鍵的設定。
3)結束編輯
當你完成資料集的修改後,可用下述操作結束FSEDIT過程:
Fileà End
結束過程時,你對資料集所做的修改會被自動儲存。
4.WHERE條件
利用WHERE條件可從你的資料集中產生一個臨時的子集,以簡化編輯過程。
例如,你只需對資料集中變數AGE的值大於30的觀測進行修改,利用WHERE條件,可使FSEDIT或FSVIEW視窗中只顯示滿足條件的觀測。
1)設定一個WHERE條件
選擇 Search à Where
然後在出現的Where視窗中輸入你的條件表示式,例如:
age> 30
再選擇‘OK’即可。這時,在FSEDIT或FSVIEW視窗的標題欄的右側顯示‘Where……’,同時,視窗中僅顯示滿足條件的觀測。
2)條件表示式中的比較符號
條件表示式的一般形式為:
variablecomparison-operator value
其中variable是一個變數名,comparison-operator是一個比較符號,value是這個變數可取的值。可用的比較符號有:
= (eq) ^= (ne) > (gt)
< (lt) >= (ge) <= (le)
3)附加一個WHERE條件
在設定一個WHERE條件後,重新設定一個WHERE條件,新的條件將覆蓋舊的條件。如果希望新舊條件都起作用的話,可附加一個WHERE條件:
選擇 Search à Where also
然後在出現的Where視窗中輸入新的條件表示式,再選擇‘OK’即可。
4)取消一個WHERE條件
選擇 Search à Undo last where
可取消最近的一個WHERE條件
5)取消所有WHERE條件
若想取消所有WHERE條件,可作如下操作:
選擇 Search à Where
然後在出現的Where視窗中,不輸入任何條件表示式,直接選擇‘OK’即可。這時,在FSEDIT或FSVIEW視窗的標題欄的右側不再顯示‘Where……’,同時,視窗中顯示資料集中所有的觀測。
二.利用DATA步修改資料
1)利用DATA步修改SAS資料集內容
上一章我們介紹了利用DATA步從原始資料檔案中讀取資料,建立SAS資料集的過程和方法。這裡,我們介紹利用原有的SAS資料集,對其中的資料進行系統的修改,從而建立新的資料集的方法。也就是說,新建的資料集是通過對原有資料集的修改而得的,原有資料集可以保持不便。
為了完成這一工作,在DATA步中將主要包含下列語句:
SAS 語句 |
作用 |
DATA語句 |
命名新的資料集及其包含的變數 |
SET語句 |
命名新的資料集及在建立新資料集時需要用到的變數 |
IF語句 |
選擇觀測 |
賦值語句 |
建立變數或改變變數值 |
2)命名資料集
你可以用LIBNAME語句指定一個數據庫,然後就可以用一個DATA步對資料庫中的資料集進行操作,包括讀取已有的資料集的內容和建立新的資料集。
首先,在DATA語句中命名一個你要建立的資料集,一般形式為:
DATASAS-data-set options;
然後,用SET語句指定一個你將要從中讀取資料的SAS資料集,一般形式為:
SETSAS-data-set options;
例: data lab123.drug1h;
set research.cltrials;
run;
注意,在上述例子中,沒有INPUT語句,也沒有賦值語句,也沒有加入一些選項,如果提交這樣幾個簡單的資料步的話,系統會建立一個名為LAB123.DRUG1H的資料集,它的內容與原有的資料集RESEARCH.CLTRIALS的內容完全一樣。
3)根據條件對觀測進行處理
由於我們的目的不是複製一個數據集,而是要在原有資料集的基礎上作一定的修改,因此要對從原有資料集中讀取的觀測和變數進行某種處理,再寫入新資料集中。例如,你可以選擇只有滿足某種條件的觀測才會被寫入新資料集中,可採用IF語句,IF語句的形式和用法在上一章已介紹過,這裡不再重複。
例: data lab123.drug1h;
set research.cltrials;
if placebo='yes';
run;
4)建立和改變變數
有時候,僅僅對觀測進行選擇並不能滿足你的要求,你可能希望新的資料集中有舊資料集中所沒有的變數,或則,某個變數的值要進行一些改變。為此,你可以在資料步中使用賦值語句,其一般形式為:
variable=expression;
其中variable是一個新建的或原有的變數名,expression是任何有效的SAS表示式。當同一個變數名同時出現在等號兩邊時,該變數的原有值被用於在等號右邊估計表示式的值。
例: data lab123.drug1h;
set research.cltrials;
if placebo='yes';
cholchng=chol2-chol1;
glucose=glucose+glucose*.10;
avgchol=mean(chol1,chol2);
run;
注意,賦值語句是少數幾個不以關鍵詞開頭的SAS語句之一。
在表示式中,你可以使用“+、-、*、/、**”等算術運算子號,也可以使用一些SAS函式。
你可以在HELP視窗中找到SAS提供的所有運算子,方法為:
Helpà SASLanguage à SASExpressions à SASOperators
除了這些運算子之外,SAS系統還提供很多函式,下表為一些簡單例子:
類別 |
關鍵詞 |
描述 |
算術函式 |
MIN MAX |
返回引數中的最小值 返回引數中的最大值 |
進位函式 |
ROUND |
根據設定的有效位數取最接近的值 |
簡單統計函式 |
MEAN SUM |
計算引數的算術平均值 計算引數的和 |
字元函式 |
SCAN UPCASE |
從字元表示式中取一個詞 將字元變為大寫 |
你可在HELP視窗中找到所有SAS函式及其描述,具體方法為:
Helpà SASSystem à SASLANGUAGE à SASFunction àFunction Categories
5)選擇變數
在新建立的SAS資料集中,你可能並不希望包含在原有資料集中以及在DATA步中出現的變數,為此,你可以在DATA語句和SET語句中使用DROP=或KEEP=選項。一般形式為:
DATASAS-data-set (DROP=variables);
SET SAS-data-set(DROP=variables);
或 DATA SAS-data-set(KEEP=variables);
SET SAS-data-set(KEEP=variables);
使用這兩個選項的一般情況是:
A.如果你根本不需要某些變數,那麼在SET語句中的DROP=選項中指定它們,這樣,它們就不會被讀取。
B.如果你在計算中需要某些變數,但不希望它們在新資料集中出現,那麼在DATA語句中的DROP=選項中指定它們,這樣,它們就不會被寫入。
C.如果需要被丟掉(DROP)的變數比要保留(KEEP)的變數多的話,用KEEP=選項代替DROP=選項。
三.利用SAS函式轉換資料
1.SAS函式的作用
SAS函式是一些預先寫好的程式,它能幫你快速簡單地完成各種資料處理工作。SAS函式能完成多種多樣的任務,下面是一些SAS函式的分類:
類別 |
例 |
作用 |
Arithmetic(算術) |
ABS(argument) |
返回絕對值 |
Character(字元) |
LEFT(argument) |
字串靠左對齊 |
Data Set(資料集) |
CLOSE(dsid) |
關閉一個SAS資料集 |
Date and Time(日期和時間) |
DATE() |
返回當天的日期值 |
External File(外部檔案) |
DCLOSE(directory-id) |
關閉一個目錄 |
Financial(財務金融) |
DEPSL(period,value,years) |
直線折舊 |
Mathematical(數學) |
LOG(argument) |
自然對數 |
Probability and Density(概率與密度) |
PROBNORM(x) |
標準正態分佈函式 |
Random Number(隨機數) |
RANUNI(seed) |
產生一個平均分佈的隨機數 |
Sample Statistic(樣本統計) |
RANGE(argument……) |
返回樣本範圍 |
Special(特殊) |
LAGn(argument) |
返回滯後n階的值 |
Variable(變數) |
VARTYPE(dsid,var-num) |
返回SAS資料集變數的型別 |
這一節,我們主要討論下列SAS函式:
1)資料變換函式
2)日期資料處理函式
3)字元資料函式
2.SAS函式的用法
SAS函式可在資料步和一些統計過程的程式語句中使用,在任何SAS的表示式中也可以使用SAS函式。例如在賦值語句中使用MEAN函式:
Avgscore=mean(exam1,exam2,exam3);
1)SAS函式的一般形式:
Function-name(argument-1,argument2)
通常是函式名,後面跟若干引數,引數用括號括起。即使有些函式不需要引數,後面仍需跟一對括號:
function-name()
2) 函式引數
函式的引數可以是:
A.變數,如 mean(x1,x2,x3)
B.常量,如 mean(456,502,612,498)
C.表示式,如 mean(37*2,192/5,mean(22,34,56))
如果一個函式有多個引數,引數之間通常用逗號分隔。但是,對有些函式,變量表或陣列變數可用於作為引數,變量表或陣列變數要跟在一個關鍵詞OF後面。例如:
mean(ofx1-x3)
mean(of newarray{*})
注意,mean(of x1-x3) 和mean(x1-x3)的區別。
3)目標變數
目標變數是指要將函式結果賦值於的那個變數,如
avgscore=mean(exam1,exam2,exam3);
AVGSCORE就是目標變數。除非事先設定,目標變數的長度被設為函式規定的預設值。
注意,個別字元函式規定的預設長度是200,使用這些函式時要注意,必要時,事先設定目標變數的長度,以免目標變數在資料集中佔據過多的空間。
3.資料變換
1)字元型變數到數字型的自動轉換
當下列情況發生時,字元型變數自動轉換為數字型變數:
A.賦值於一個數字型變數,例: rate=payrate;
B.在算術運算中使用,例: salary=payrate*hourse;
C.與一個數字型變數進行比較,例: if payrate>=rate;
D.在要求數字型變數的函式中作為引數,例: newrate=sum(payrate,raise);
上述例中,PAYRATE是一個字元型變數,其它都是數字型變數。
注意,這裡的自動轉換是指系統產生一個臨時的數字型變數來完成賦值或運算,字元型變數PAYRATE本身不會被一個數值型變數的值代替。
當自動轉換髮生時,系統會在LOG視窗中給出提示,例如:
NOTE: Character values have been converted tonumeric
Valuse atthe places given by: (Line):(column).
6:11
2)數字型變數到字元型的自動轉換
與字元型變數自動轉換為數字型變數的情況很相似,當下列情況發生時,數字型變數自動轉換為字元型變數:
A.賦值於一個字元型變數,例: sitecode=site;
B.在與要求字元的運算子一起使用,例: sitecode=site||dept;
C.在要求字元型變數的函式中作為引數,例: region=trim(site);
上述例中,SITE是一個數字型變數,其它都是字元型變數。
同樣,與字元型變數自動轉換為數字型變數的情況相似,這裡的自動轉換是指系統產生一個臨時的字元型變數來完成賦值或運算,並且,當自動轉換髮生時,系統會在LOG視窗中給出提示,例如:
NOTE: Numeric values have been converted tocharacter
Valuse atthe places given by: (Line):(column).
11:13
3)字元型變數到數字型的明確轉換
雖然在一些比較簡單的情況下,系統能完成字元型變數和數字型之間的自動轉換,但是如果需要被轉換成數字型變數的字元型變數不能被作為標準的數字讀入,或則,需要被轉換成的字元型變數有格式要求的話,就必須使用SAS函式來進行明確轉換。
用INPUT函式可將字元型變數轉換為數字型變數,其一般形式為:
INPUT(source,informat)
其中,source是被轉換的字元型變數,informat是讀取數字型變數的輸入格式。對於字元型變數到數字型的明確轉換,必須要設定一個輸入格式。
4)數字型變數到字元型的明確轉換
用PUT函式可將數字型變數轉換為字元型變數,其一般形式為:
PUT(source,format)
其中,source是被轉換的數字型變數,format是一個輸出格式。
PUT函式和INPUT函式的形式非常相似,所不同的是,INPUT函式要求輸入格式,而PUT函式要求輸出格式。
4.用函式處理SAS的日期資料
由於在SAS系統中,日期資料是以數字型變數的形式儲存,因此,你可以象使用其它數字型變數一樣,用日期變數資料來進行各種數值運算。同時,SAS系統還提供了一些專門用於處理日期變數資料的函式。
1)MONTH函式
從一個SAS日期資料中取出月份數,一般形式:
MONTH(date)
MONTH函式返回一個數字值,範圍為1到12。
2)YEAR函式
從一個SAS日期資料中取出年份數,一般形式:
YEAR(date)
MONTH函式返回一個數字值表示年份,比如1989。
3)MDY函式
從三個分別代表月、日、年的數字產生一個SAS日期值,一般形式為:
MDY(month,day,year)
其中,month的範圍為1到12;day的範圍為1到31;year可以用2位或4位數字來表示。
注意,如果在MDY函式中給定一個無效日期,那麼,系統賦予目標變數一個遺漏資料。
4)TODAY函式和DATE函式
給出當天的日期值,一般形式為:
TODAY() 或 DATE()
這兩個函式的形式和效果都一樣,可以互相代替。注意,這兩個函式不需要引數。
5.改變字元變數
1)SCAN函式
將一個字元型變數資料分割成詞,並返回其中特定的一個詞,一般形式為:
SCAN(argument,n,delimiters)
其中,argument是一個字元型變數或表示式,n設定要返回第n個詞,delimiters是設定的分隔符。函式根據設定的分隔符將一個字元型變數分割成若干詞,並返回其中第n個詞。
你可以設定一個或多個分隔符,引數變數中連續的分隔符被視為一個,另外,開頭的分隔符不起作用。如果在SCAN函式中不設定分隔符的話,系統使用以下所有分隔符作為預設值:
空格 . < ( + | & ! $ * ) ; ^ - / , %
例如: lname=scan(name,1,',');
上例是以空格和逗號作為分隔符。
注意,SCAN函式對目標變數賦予200的長度。如有必要的話,可事先用LENGTH語句設定目標變數的長度。例:
datahrd.newtemp(drop=name);
set hrd.oldtemp;
length lnamefname mname $ 10;
lname=scan(name,1);
fname=scan(name,2);
mname=scan(name,3);
run;
2)SUBSTR函式
取出字串或替換字元值,一般形式為:
SUBSTR(argument,position,n)
其中,argument是一個字元型變數或表示式,position是開始位置,n設定要取出或替換的字元數。
如果SUBSTR函數出現在賦值語句中等號的右邊,則它從一個字元型變數中取出字串,例:
minitial=substr(mname,1,1);
如果SUBSTR函數出現在賦值語句中等號的左邊,則它在用一個字串替代一個字元型變數中的一部分,例:
substr(region,1,3)='NNW';
3)SCAN函式和SUBSTR函式的比較
SCAN函式和SUBSTR函式都能從一個字元型變數中取出一個子字串,它們的區別在於:
A.SCAN函式取出用分隔符分割的一個詞
B.SUBSTR函式取出特定位置和特定長度的子字串,不需要有分隔符
另外,SUBSTR函式能用於改變字元型變數的值,而SCAN函式不行。
4)TRIM函式
消除字元尾的空格,一般形式為:
TRIM(argument)
引數argument可以是一個字元型變數,如 trim(addr),或是一個其他的字元型函式,如 trim(left(idnum))。TRIM函式在將幾個字元型變數合併是比較有用,例如:
datahrd.newtemp(drop=addr city state zip);
set hrd.temp;
newaddr=trim(addr)||','||trim(city)||', '||zip;
run;
注意,TRIM函式不影響變數儲存的方式,你可以用TRIM函式消除某個字元型變數尾的空格並將它賦予一個新的變數,但是如果新值的長度小於新變數的長度的話,新值的尾部仍然會填補上足夠的空格以適應新變數的長度。
5)INDEX函式
在一個字元型變數中搜索特定的字串,一般形式為:
INDEX(source,excerpt)
Source是一個字元型變數名,excerpt是要搜尋的字串,如果找到,函式返回字串的開始位置,如果找不到,返回0。INDEX函式可用於幫助尋找符合特定要求的觀測,例如:
datahrd.datapool;
set hrd.temp;
ifindex(job,'word processing') > 0;
run;
注意,INDEX函式是區分大小寫的,因此要搜尋的字串必須完全匹配才行。UPCASE函式和LOWCASE函式常常與INDEX函式一起使用以保證大小寫不一致時也能找到目標字串。
6)UPCASE函式和LOWCASE函式
UPCASE函式將字元型變數中所有字元變為大寫,而LOWCASE函式將字元型變數中所有字元變為小寫,一般形式為:
UPCASE(argument) 或 LOWCASE(argument)
例如: index(upcase(job),'WORD PROCESSING')
或 index(lowcase(job),'wordprocessing')
四.利用DO迴圈產生資料
1)建立DO迴圈
上一章我們介紹過DO迴圈和DO/END語句組,請注意區分。使用DO迴圈的的一個主要目的是在進行重複計算時可減少程式的語句,另外,也可以用DO迴圈來產生資料、有條件地執行語句,或讀取資料。有四種DO語句可用於建立DO迴圈:
A.DO
B.DO WHILE
C.DO UNTIL
D.DO OVER
其中,DO OVER僅用於隱含陣列,這裡我們不討論。DO和DO WHILE迴圈在上一章已經介紹過,DO UNTIL與DO WHILE剛好相反,其一般形式為:
DOUNTIL(expression);
More SASstatements;
END;
在迴圈尾對錶達式expression進行估計,如果為真,則迴圈不再繼續。因此,DO UNTIL迴圈至少會執行一次。
注意,DO UNTIL與DO WHILE的一個重要區別是,DO UNTIL在迴圈尾對錶達式expression進行估計,而DO WHILE在迴圈頭對錶達式expression進行估計。
2)利用DO迴圈進行計算
利用DO迴圈可以很方便地進行重複的計算,例如:
dataearn;
value=2000;
do year=1 to20;
interest=value*.075;
value+interest; output;
end;
run;
此程式產生的資料集WORK.EARN只有一條觀測,其變數VALUE的值為本金2000,每年複利7.5%,20年下來的本利和。如果在迴圈內加一條OUTPUT語句,則產生的資料集WORK.EARN將包含20條觀測,它記錄每年的利息INTEREST和本息和VALUE。
3)巢狀的DO迴圈
DO迴圈可以巢狀使用,使用時要注意:
A.對不同的DO語句要使用不同的指標變數
B.每個DO迴圈用一個END語句結束
例如:
dataearn;
value=2000;
do year=1 to20;
do month=1to 12;
interest=value*.075/12;
value+interest;
output;
end;
end;
run;
這樣產生的資料集WORK.EARN將包含240條觀測,它記錄按7.5%的名義年利率,每個月複利一次,每個月的利息INTEREST和本息和VALUE。
五.利用陣列來處理變數
1)陣列的概念
SAS陣列是一些SAS變數的臨時組合,一個數組僅僅在DATA步過程中存在。在SAS語言中支援隱含的和明確的兩種陣列,其中隱含陣列是為了與以前版本相容而支援的,下面我們僅討論明確定義的陣列。
當你需要對多個變數進行同樣的計算時,你將發現使用陣列會有很大的幫助。例如,你要將一個數據集中記錄的每週七天的溫度由華氏轉換為攝氏,比較下面兩個程式:
data report; datareport;
set master.temps; set master.temps;
mon=5*(mon-32)/9; ----> array wkday(7) mon tue wed thr fri satsun;
tue=5*(tue-32)/9; do i=1to 7;
wed=5*(wed-32)/9; wkday(i)=5*(wkday(i)-32)/9;
thr=5*(thr-32)/9; end;
fri=5*(fri-32)/9; run;
sat=5*(sat-32)/9;
sun=5*(sun-32)/9;
run;
顯然,右邊的程式既簡單,又不易出錯。
2)定義一個數組
利用ARRAY語句可以明確地定義一個數組,其一般形式為:
ARRAYarray-name{dimension} elements;
其中,array-name是陣列名,它必須是一個有效的SAS名字,同時,它不應與同一個DATA步中的變數名相同,另外,還應當避免使用SAS函式名來給陣列命名,否則,該函式將不能使用。
dimension設定陣列的度數(也可稱為維數,為了避免與下面的二維陣列的定義混淆,我們把它成為度數),它表明陣列包含的變數數目。度數用括號括起,大、中、小括號均可。你可以用一個數字給定一個度數,或則,用一個星號(*)代替,當你用星號時,系統通過計數你給的元素數目來確定陣列的度數。
elements是陣列中的元素,也就是構成陣列的那些變數的名字。你可以將這些變數名一一列出,也可以用下列方法指定一系列變數:
VAR1-VARn 可用數字劃定範圍的一系列變數
_NUMERIC_ 所有數字型變數
_CHARACTER_ 所有字元型變數
_ALL_ 所有變數
注意,一個數組中的所有元素必須全部都是數字型的,或者,全部都是字元型的。
3)指定陣列中的元素
當你定義一個數組時,陣列中的每個元素,根據它們出現的順序都給定一個序號,呼叫這些元素時,用陣列名後跟用括號括起的相應的序號即可。序號必須在陣列的度數範圍以內。通常,由於陣列用於對不同變數的重複操作,往往用迴圈語句的指標變數來陣列中元素的序號。
例: array qua(4) jan apr jul oct;
do i=1 to 4;
yeargoal=qua(i)*1.2;
end;
4)DIM函式
DIM函式可用於獲得陣列的度數,一般形式為:
DIM(array-name)
它返回陣列中元素的個數,可以利用DIM函式來控制迴圈語句的迴圈次數,例:
arraywt(6) weight1-weight6;
do i=1 to dim(wt);
wt(i)=wt(i)*2.2046;
end;
這樣,即使你改變陣列的度數,也不需要修改迴圈語句了。
5)用ARRAY語句建立變數
你可以在ARRAY語句中建立新的變數,當你在ARRAY語句中建立新的變數時,你可以不用設定陣列元素,系統自動在陣列名後加一個相應的數字作為新建立的變數名,例如:
arraydiff(5);
遇到這樣一個語句時,系統自動建立DIFF1、DIFF2、DIFF3、DIFF4和DIFF5這樣五個新變數。當然,如果你不喜歡這樣命名的話,也可以自己給定,如:
arraydiff(5) df1 df2 df3 df4 df5;
如果你希望新建立的變數是字元型的,可以用$符號來標明,例:
arrayfname(5) $;
在ARRAY語句中建立的字元型變數的預設長度為8,你也可以直接設定它的長度,例:
arrayfname(5) $ 24;
6)給陣列賦初值
有時候,你可能希望在定義陣列的同時,給陣列中的元素確定初值,你可以在ARRAY語句中完成這一工作,做法如下:
A.將初值放在元素列表後
B.對每一個數組元素設定一個相應的初值
C.用逗號或空格分隔這些初值
D.用括號括起這些初值
E.如果是字元型變數,把每個初值放在一對單引號中。
例如: array goal{4} g1 g2 g3 g4 (9000 9300 96009900);
array colors{3} color1-color3 ('red','white','blue');
7)建立臨時的陣列元素
如果你建立的陣列僅僅是用於計算過程中,並不想把這些資料儲存到SAS資料集中的話,你在定義陣列的時候,不需要建立新的變數,只要在ARRAY語句中用_TEMPORARY_來作為陣列元素,建立一些臨時的陣列元素供使用就可以了。例如:
arraygoal{4} _temporary_ (9000 9300 9600 9900);
8)多維陣列
為了使用或計算方便,有時候你可能需要用到二維甚至多維的陣列。下面我們以二維陣列為例介紹其使用方法。
為了定義一個二維陣列,在ARRAY語句中,陣列名後必須跟兩個度數,例如:
array new(3,4) x1-x12;
如果我們把二維陣列理解成一個表格的話,第一個度數通常稱為行數,第二個度數則稱為列數,上例定義的陣列可看作一個3x4的表格。陣列元素的排列按先第一行,排滿再排第二行的次序進行。也就是說:
new(1,1)=x1 new(1,2)=x2 new(1,3)=x3 new(1,4)=x4
new(2,1)=x5 new(2,2)=x6 new(3,3)=x7 new(2,4)=x8
new(3,1)=x9 new(3,2)=x10 new(3,3)=x11 new(3,4)=x12
同樣,在使用中為了指定一個二維陣列中的元素,要在陣列名後跟兩個序號,分別對應行號和列號。
多維陣列的定義和使用可參照二維陣列方法類推。
六. 巨集變數
1)巨集變數的概念
巨集變數可以讓你方便地替換程式中的文字。SAS巨集變數實際上就是用一個名字代替一個字串,當在程式中經常出現相同的字串時,你可以定義一個巨集變數,這樣不但可以簡化程式,需要修改時也非常方便。
SAS巨集變數的值是一個字串,它獨立於SAS的DATA步,DATA步結束以後它仍然保持它的值,一直到你改變它。
除了在資料行中之外,你可以在SAS程式的任何地方定義和引用SAS巨集變數。因此,如果你在DATA步中用CARDS輸入資料,那麼在CARDS下面的資料行中不能定義和引用SAS巨集變數。其它地方都可以。
SAS巨集變數分為兩類:
A.自動巨集變數
B.使用者定義巨集變數
顧名思義,自動巨集變數由又SAS系統提供,而使用者定義巨集變數是由使用者自行定義的。
2)自動巨集變數
一旦你啟動SAS系統,自動巨集變數就會被建立,它們提供如下資訊:
A.SAS開始執行的日期和時間
B.執行的SAS軟體的版本號
C.最新建立的SAS資料集的名字
D.執行SAS的作業系統的名稱縮寫
下面是一些常見的SAS自動巨集變數及它們提供的資訊
巨集變數名 變數提供的資訊 例
SYSDATE Date SAS job executed or session began 18MAY99
SYSDAY Weekday SAS job executed or sessionbegan Tuesday
SYSTIME Time SAS job executed or session began 15:32
SYSSCP Operating system abbreviation WIN
SYSVER SAS software release 6.12
SYSLAST Name of most recently created data set HRD.TEMP91
其它的SAS自動巨集變數可從HELP視窗中查尋,方法為:
Help à SAS System à SASLanguage à SASMacro Facility àAutomatic Macro Variables
SAS自動巨集變數都以SYS開頭,因此當用戶自行定義巨集變數時,建議最好不要以SYS開頭,以作為區分。
3)呼叫巨集變數
為呼叫巨集變數,將巨集變數名跟在一個&符號後即可,例如:
&SYSDATE
當你需要用到巨集變數所提供的資訊時,你可以在程式中的任何地方呼叫巨集變數,例如:
footnote"Report Run on &sysday , &sysdate";
遇到巨集變數,SAS系統首先把程式中的巨集變數用相應的字串代替,然後再進行編譯,因此,上述FOOTNOTE語句被SAS系統理解成:
footnoot"Report Run on Tuesday , 19MAY99";
注意,如果在引號內的字串中呼叫巨集變數,必須使用雙引號,這樣,巨集變數才會被解釋,若使用單引號,巨集變數不會被解釋。
4)使用者定義巨集變數
除了直接呼叫系統提供的自動巨集變數外,使用者也可自行定義巨集變數,一種方法是利用%LET語句,一般形式為:
%LETname=value;
例如: %let region=northwest;
注意,巨集變數region的值是northwest,定義時不能用引號將巨集變數的值引起來,否則,如果用: %let region='northwest';
巨集變數region的值就變成'northwest',而不是northwest。
第二點要注意,巨集變數的值是一個字串,
例如: %let level=768;
這裡,巨集變數的值768不作為數值對待,而是由3個字元組成的字串。同樣,對
%letrate=700+700*.05;
系統不會去計算等號右邊的值,而是直接把它當作由11個字元組成的字串。
一般來說,%LET語句放在程式的開頭,例如:
%letyear=1991;
data hrd.newtemp;
set hrd.temp;
ifyear(enddate)=&year;
proc printdata=hrd.newtemp;
title"temporary Employees for &year";
run;
5)SYMBOLGEN 系統選項
系統選項SYMBOLGEN用於規定當巨集變數被解釋時是否在LOG視窗中給出提示,它的一般形式為:
SYMBOLGEN 或 NOSYMBOLGEN
其預設設定是NOSYMBOLGEN。你可以在OPTIONS視窗中或用OPTIONS語句改變它,例如:
optionssymbolgen;
這樣,當一個巨集變數被解釋時,LOG視窗中會給出提示,如:
SYMBOLGEN:Macro variable YEAR resolves to 1991
這樣,你可以通過檢視LOG視窗,確認你的巨集變數是否被正確地解釋。
如果系統遇到一個巨集變數,但是不能解釋時,會在LOG視窗中給出警告,如:
WARNING:Apparent symbolic reference YEAR not resolved.
程式可以繼續進行,但通常會發生錯誤。發生巨集變數不能解釋的可能原因有:
A.呼叫巨集變數時拼寫錯誤
B.呼叫巨集變數之前沒有進行定義
6)將巨集變數與前後綴合並使用
在巨集變數的使用中,有時候你會碰到複雜一些的情況,就是將巨集變數的值與前後綴合並使用。下面我們看幾個例子。
例一: %let yr=91;
datahrd.temp&yr;
系統會將DATA語句解釋為: data hrd.temp91;
因此,將巨集變數的值與前綴合並使用時,按巨集變數的一般用法即可。
例二: %let period=end;
ifyear(&period.date)=1991;
系統會將IF語句解釋為:if year(enddate)=1991;
例三: %let libref=hrd;
data&libref..temp91;
系統會將DATA語句解釋為:data hrd.temp91;
從例二和例三我們看到,將巨集變數的值與字尾合併使用時,要在巨集變數名的後面加一個點(.),而如果字尾剛好是以點(.)開頭的話,巨集變數名的後面就會跟著兩個點。
7)CALL SYMPUT子程式
用%LET語句可以定義你需要的大多數巨集變數,但如果你需要用在DATA步的執行過程中產生的一者變數值來定義一個巨集變數的話,就會用到SYMPUT子程式,其一般形式為:
CALLSYMPUT(name,value);
其中,CALL是一個關鍵詞,表示呼叫一個子程式,SYMPUT是子程式名,name是要定義的巨集變數名,它可以是在引號中的一個字串,也可以是一個數據集的變數,或者資料步中的一個表示式。value是要賦予巨集變數的值,它同樣可以是一個數據集的變數,或者資料步中的一個表示式。
例如: callsymput('cost',fee);
這時,巨集變數COST將被賦予在當前觀測中變數FEE的值。
注意,上例中,巨集變數名在引號中。如果變數FEE是數字型變數的話,在賦值過程中將自動轉換為字元型。
使用SYMPUT子程式使還有兩點要注意:
A.不能呼叫在同一個資料步中由CALLSYMPUT子程式定義的巨集變數
B.不能在一個緊跟資料步的全域性語句中呼叫在這個資料步中由CALL SYMPUT子程式定義的巨集變數
因為,在這兩種情況下,資料步尚未被執行,也就是說,巨集變數尚未被定義,系統無法對巨集變數進行解釋。
七. 將多個SAS資料集合成一個
有時候,需要將兩個或多個SAS資料集併成一個,合成的方式有兩種:
A.拼接
B.合併
如果把一個SAS資料集看作一個表格的話,每行代表一條觀測,每列代表一個變數。那麼拼接的意思是將兩個或多個數據集的內容縱向合併,行數相加;而合併的意思是將兩個或多個數據集的內容橫向合併,列數相加。
1)拼接SAS資料集
如果兩個資料集具有完全相同的結構,他們的拼接非常簡單,直接在DATA步中使用SET語句即可。
例一:兩個資料集NA1和NA2:
|
NA1 |
|
|
|
NA2 |
|
||
OBS |
NAME |
SEX |
JOBCODE |
|
OBS |
NAME |
SEX |
JOBCODE |
1 |
ZHANG |
M |
NA1 |
|
1 |
DING |
F |
NA2 |
2 |
KONG |
F |
NA1 |
|
2 |
LIU |
M |
NA2 |
3 |
CHEN |
M |
NA1 |
|
|
|
|
|
用:data newhire;
set na1 na2;
run;
可得新資料集NEWHIRE:
|
NEWHIRE |
|
|
OBS |
NAME |
SEX |
JOBCODE |
1 |
ZHANG |
M |
NA1 |
2 |
KONG |
F |
NA1 |
4 |
CHEN |
M |
NA1 |
5 |
DING |
F |
NA2 |
6 |
LIU |
M |
NA2 |
如果兩個資料集具有不同的變數,如:
例二:
|
|
NA1 |
|
|
|
|
NA2 |
|
OBS |
NAME |
SEX |
JOBCODE |
|
OBS |
NAME |
SEX |
JCODE |
1 |
ZHANG |
M |
NA1 |
|
1 |
DING |
F |
NA2 |
2 |
KONG |
F |
NA1 |
|
2 |
LIU |
M |
NA2 |
3 |
CHEN |
M |
NA1 |
|
|
|
|
|
採用與上述完全相同的程式的話,系統會在相應位置加入遺漏值,得到:
|
NEWHIRE |
|
|
|
OBS |
NAME |
SEX |
JOBCODE |
JCODE |
1 |
ZHANG |
M |
NA1 |
|
2 |
KONG |
F |
NA1 |
|
4 |
CHEN |
M |
NA1 |
|
5 |
DING |
F |
|
NA2 |
6 |
LIU |
M |
|
NA2 |
2)RENAME=選項
如果兩個資料集中同樣的變數使用了不同的變數名的話,如上述例二的兩個資料集,可使用RENAME=選項進行拼接,使用程式為:
datanewhire;
set na1na2(rename=(jcode=jobcode));
run;
可得到一例一中完全一樣的結果。
3)合併SAS資料集
合併SAS資料集要在DATA步中用MERGE語句,其一般形式為:
DATASAS-data-set;
MERGE SAS-DATA-SETS;
BY by-variable;
RUN;
用MERGE語句可以合併多個數據集,每個輸入資料集必須事先按by-variable排序。
例三:兩個資料集NA1和NA2:
|
NA1 |
|
|
|
NA2 |
||
OBS |
NAME |
SEX |
IDNUM |
|
OBS |
IDNUM |
SALARY |
1 |
ZHANG |
M |
1234 |
|
1 |
1234 |
2000 |
2 |
KONG |
F |
2345 |
|
2 |
3456 |
5000 |
3 |
CHEN |
M |
3456 |
|
3 |
2345 |
4000 |
用: proc sort data=na1; by idnum;
proc sort data=na2; by idnum;
data combine;
merge na1 na2;
by idnum;
run;
可得:資料集COMBINE:
|
COMBINE |
|
||
OBS |
NAME |
SEX |
IDNUM |
SALARY |
1 |
ZHANG |
M |
1234 |
2000 |
2 |
KONG |
F |
2345 |
4000 |
3 |
CHEN |
M |
3456 |
5000 |
如果輸入資料集的by-variable不能完全匹配,則輸出資料集相應位置用遺漏資料表示,
例四:兩個資料集NA1和NA2:
|
NA1 |
|
|
|
NA2 |
||
OBS |
NAME |
SEX |
IDNUM |
|
OBS |
IDNUM |
SALARY |
1 |
ZHANG |
M |
1234 |
|
1 |
1234 |
2000 |
2 |
KONG |
F |
2345 |
|
2 |
3456 |
5000 |
3 |
CHEN |
M |
3456 |
|
3 |
4567 |