SAS 對數據的拼接與串接


SAS 對數據的拼接與串接

使用SAS對數據進行串接、合並、更新與修改。

1. 數據集的縱向串接

數據集的縱向串接指的是,將兩個或者多個數據集首尾相連,形成 一個新的數據集。

對數據集的縱向串接可以通過以下兩種方法實現:

  1. ·使用SAS DATA步的SET語句。
  2. ·使用SAS過程步的APPEND過程。

1.1 使用SET語句實現縱向串接 

1.基本形式 

使用SET語句實現縱向串接的基本形式如下: 

DATA  新數據集;
SET  數據集1  數據集2  <數據集3  數據集4  …>;
RUN;

其中:

  • ·SET語句中的數據集1、數據集2都為輸入數據集。
  • ·串接后的數據存儲在DATA語句的新數據集中。
  • ·SET語句可以同時讀入多個數據集,新數據集將包含各輸入數據集 中的所有變量。

對數據集Work.New_Emloyee和Work.Old_Emplyee進行串 接。

以下代碼創建了數據集:

data  work.New_Employee;
input  Emp_ID  $  Emp_Name  $  @@;
datalines;
ET001   Jimmy  ED003  Emy  EC002   Alfred  EQ004  Kim
;
run;
data  work.Old_Employee;
input  Emp_ID  $  Emp_Name  $  @@;
datalines;
EQ122  Molly  ET121   Dillon  ET123   Helen  ED124  John
;
run
 

數據集Work.New_Emloyee和Work.Old_Emplyee含有相同的變量Emp_ID和Emp_Name。串接兩個數據集的示例代碼如下:

data  work.Employee;
set  work.Old_Employee  work.New_employee  ;
run;
proc  print  data=work.Old_Employee;
title  'Old  Employee';
run;
proc  print  data=work.New_Employee;
title  'New  Employee';
run;
proc  print  data=work.Employee;
title  'All  Employee';
run;

從輸出內容中可以觀察到新數據集work.Employee包含了2個變量和8條觀測,work.Old_Employee的觀測直接加在了work.New_Employee的 后面,名稱相同的字段放在同一變量下。

如果Work.New_Employee和Work.Old_Emplyee中含有的變量不全一 致,將這兩個數據集進行串接時,情況會是如何呢?

以下代碼在 Work.New_Emloyee和Work.Old_Emplyee中分別用IF語句創建了新變量 Dept和Gender。

data  work.New_Employee_Dept;
set  work.New_Employee;
if substr(Emp_ID,2,1)="T"  then  Dept="TSG";
else  if substr(Emp_ID,2,1)="Q"  then  Dept="QSG"; else  if substr(Emp_ID,2,1)="D"  then  Dept="DSG"; else  if substr(Emp_ID,2,1)="C"  then  Dept="CSG";
run;
data  work.Old_Employee_Gen;
set  work.Old_Employee;
if mod(substr(Emp_ID,length((trim(Emp_ID))),1),2)=0  then  Gender="F";
else  Gender="M";
run;

對數據集Work.New_Emloyee_Dept和Work.Old_Emplyee_Gen進行串接。 示例代碼如下:

data  work.Employee_Update;
set  work.Old_Employee_Gen  work.New_employee_Dept;
run;
proc  print  data=work.Employee_Update;
title  'All  Employee  Update';
run;

新數據集work.Employee_Update和work.Employee一樣含有8條觀 測,但是work.Employee_Update含有4個變量,依次為Emp_ID、 Emp_Name、Gender和Dept。由於work.Old_Employee_Gen中不含有 Dept,因此串接后前4條觀測的Dept都為缺失值,同樣Gender在 work.New_Employee_Dept中不存在,串接后的后4條觀測其Gender都為 缺失值。

1.2  使用BY語句進行穿插串接

在例4.2中,如果要讓串接后的新數據集中的8條觀測按照Emp_ID的 升序排列,該如何操作呢?這時需要引入穿插串接的概念。穿插串接就是使得新數據集的觀測按照一定順序排列的串接方法。

基本形式如下:

DATA  新數據集;
SET  數據集1  數據集2  <數據集3    數據集4 …   >;
BY 變量1   <變量2  變量3  變量4   …   >;
RUN;

BY語句在處理多個數據集時經常使用,為了更好地理解本章后面 的內容,這里需要引入BY變量、BY變量組、BY變量值和BY組合的概 念。

  • ·BY語句中的變量稱為BY變量,一個BY語句中可以有多個BY變量。
  • ·當BY語句中有多個變量時,稱這些變量為BY變量組。
  • ·BY變量值指的是BY變量的取值。
  • ·BY組合指的是具有相同BY變量值的觀測的集合。當有多個BY變量時,BY組合就是使得所有BY變量的取值完全相同的觀測的集合。

為了便於理解,在本章后面的闡述中,BY變量既代表一個BY變 量,也可以是多個BY變量。

在使用BY語句時,所有輸入數據集都必須是按BY變量排過序,或 者有基於BY變量建立的索引(在以后的所有代碼中,使用BY語句都有 這樣的要求)。串接完畢后,新數據集中的觀測也將按照BY變量排 序。 

對數據集Work.New_Emloyee_Dept和Work.Old_Emplyee_Gen進行穿插串接。

由於work.New_Employee_Dept和work.Old_Employee_Gen都沒有按 照Emp_ID排序,在對這兩個數據集進行穿插串接時,首先必須對其按 Emp_ID排序。

proc  sort  data=work.New_Employee_Dept;
by   Emp_ID;
run;
proc  sort  data=work.Old_Employee_Gen;
by   Emp_ID;
run;
data  work.Employee_Int;
set  work.Old_Employee_Gen work.New_Employee_Dept;
by   Emp_ID;
run;
proc  print  data=work.Employee_Int;
title  'All  Employee  Interleaving  by   ID';
run;

1.3.使用LENGTH語句

當輸入數據集中同名變量的長度不一樣時,新數據集中該變量的長度等於SET語句中第一個數據集中對應變量的長度。在對多個數據集進 行串接時,最好先檢查字符型變量的長度,避免在讀取變量值時造成截 斷。如有需要,可以在使用SET語句之前使用LENGTH語句來定義變量 的長度。

使用LENGTH語句定義變量長度的基本形式如下:

LENGTH  變量1    <  $  >長度  <變量2    <  $  >長度  …>;

在定義字符型變量的長度時,需在長度前面加上$符號。

使用LENGTH語句將數據集work.Employee中Emp_ID的長度定義為15。 示例代碼如下:

data  work.Employee;
length  Emp_ID  $15;
set  work.New_Employee  work.Old_employee;
by Emp_ID;
run;

1.4  使用選項RENAME=

在上面的例子中,輸入數據集中相同含義的字段正好同名,但是在很多情況下,由於數據來自於不同的部門系統和時期,輸入數據集中相 同含義的變量往往不具有相同的變量名。例如,在一個數據集中表示員 工ID的變量名叫ID,在另一個數據集中表示員工ID的變量名叫 Emp_ID,在進行數據拼接的時候,如果不做另外的處理,這兩個變量 將會被SAS認為是兩個不同的字段,並分別存儲在兩個不同的變量下。 這時可以使用RENAME=選項將兩個數據集中的變量名改成一致的名 稱,避免出現前面描述的問題。

使用RENAME=選項的基本形式如下:

數據集(RENAME=  (原變量名1  =  新變量名1 <原變量名2  =  新變量名2  …   >));

2  使用APPEND過程實現縱向串接

使用APPEND過程進行數據集串接的基本形式如下:

PROC  APPEND  BASE=主數據集 <DATA=追加數據集>  <FORCE>;

其中:

  • ·主數據集表示需要增加觀測的數據集。該主數據集可以是已經存 在的數據集,也可以是不存在的數據集。當主數據集不存在時,在執行完APPEND過程后,將生成主數據集,並將追加數據集的觀測復制到主數據集中。
  • ·追加數據集中包含了需要被添加到主數據集中的觀測。這個語句可以是默認的,此時,SAS會將當前數據集的觀測添加到主數據集的后 面。當前數據集指的是SAS系統最近一次生成的數據集。通常情況下, 為了保證程序的可讀性,不建議默認。
  • ·FORCE選項會強制將追加數據集中的觀測添加到主數據集中。后面將會介紹需要使用FORCE選項的3種情況及其結果。

使用APPEND過程進行串接時,SAS不會處理主數據集中的觀測, 而是直接將追加數據集的觀測添加到主數據集最后一條觀測的后面,且 變量僅包含主數據集中的變量。

  運用APPEND過程將work.New_Employee_Dept和 work.Old_employee_Gen兩個數據集進行縱向串接,並將串接后的數據 集保存在work.Old_employee_Gen中(前面在介紹SET語句的時候,已經 介紹並操作過這兩個數據集)。

  兩個數據集的基本情況如圖所示。 兩個數據集所含的變量不全一致,需要使用FORCE語句來進行串接,代碼如下:

proc  append base=work.Old_Employee_Gen  data=work.New_Employee_Dept  FORCE;
run;

串接后的數據集work.Old_Employee_Gen如圖所示。

從上面的例子可以觀察到,串接后work.Old_Employee_Gen中僅包含原來含有的變量,觀測數為兩個數據集中的觀測之和。這里使用了 FORCE選項,如果去掉FORCE選項,串接將失敗,這是因為追加數據 集work.New_employee_dept中含有主數據集沒有的變量。

使用APPEND過程時特別需要注意FORCE選項的使用,下面介紹需要使用FORCE選項的3種情況,以及使用FORCE選項后的結果。

·第一種情況,如果追加的數據集中存在不包含在主數據集中的變量,使用FORCE選項將會使得串接成功,但僅存在於追加數據集中的變量不會被添加到主數據集中。

·第二種情況,如果同名變量在主數據集和追加數據集中的類型不一樣,那么需要使用FORCE選項,但是追加進主數據集的觀測對應的這個變量的值為缺失。

·第三種情況,如果同名變量在追加數據集中的長度大於主數據集中的長度,那么需要使用FORCE選項,在執行過程中,追加數據集中的變量值可能會被截斷。

當主數據集中包含追加數據集中不含有的變量時,串接成功,同時 系統會在日志中生成警告,並且追加數據集中不含有的變量之值都為缺 失。另外,當兩個數據集中同名變量的屬性不一致時,將沿用主數據集 中變量的屬性。

在企業交易系統數據的維護過程中可以使用APPEND過程,例如主 數據集可以表示歷年的交易記錄,追加數據集可以表示每年新增的交易 記錄,使用APPEND過程可以將每年新增的銷售記錄方便快速地串接到 歷年的銷售記錄中。

注意 在使用APPEND過程時,一定要注意觀察日志信息,避免產生數據缺失、截斷等異常結果。

1. SET語句與APPEND過程的比較

對兩個數據集進行縱向串接時,如果兩個數據集中的變量名稱和屬性都相同,使用SET語句和APPEND過程,可以得到完全一樣的結果。 但是使用APPEND過程的效率比使用SET語句高,尤其是當主數據集的觀測量很大時,這是因為APPEND過程不對主數據集的觀測進行操作, 而是直接把追加數據集的觀測加到主數據集的后面。

當輸入數據集的個數、所包含的變量或者變量屬性不一致時,兩種 方法有較大差別,如表4.1所示。

2表4.1 SET語句和APPEND過程比較

2 數據集的橫向合並

數據集的橫向合並,指的是將兩個或多個數據集根據某種原則橫向 合並起來,形成新的數據集。SAS提供了MERGE語句來實現兩個或多 個數據集的橫向合並。數據的橫向合並主要分為以下兩種情況:

  1.  ·不使用BY語句合並,也稱為一對一合並(左圖)。
  2. ·使用BY語句合並,也稱為匹配合並(右圖)。

1.  不適用by語句實例代碼

代碼如下:
DATA  WORK.COMBINED;
MERGE  WORK.DATA1  WORK.DATA2; 
RUN;

2.  使用by語句實例代碼

DATA  WORK.COMBINED;
MERGE  WORK.DATA1  WORK.DATA2; 
BY  Year;
RUN;

2.1 不使用BY語句實現橫向合並

不使用BY語句進行數據集橫向合並的基本形式如下:

DATA  新數據集;
MERGE  數據集1   數據集2  <數據集3   數據集4 …   >;
RUN;

不使用BY語句進行數據集橫向合並時,對輸入數據集的排序沒有要求。

某部門的主管決定在年終的時候對本部門的員工進行考 核,數據集work.staff中包含了員工的基本信息,而另一個數據集 work.schedule中包含了考核時間和地點。現在需要給每位員工分配考核 時間和地點。

以下代碼創建了數據集。

data  work.staff;
infile  datalines  dsd;
length  emp_name  $20   title  $15; 
input  emp_name  $  title  $  ; 
datalines;
Jacob Adams,Analyst
Emily  Anderson,Analyst
Michael  Arnold,Senior  Analyst
Hannah  Baker,Manager
Joshua Carter,Senior  Analyst
;
run;
data  work.time;
input  time  date9. room  $11-24;
format  time  date9.;
datalines;
01Dec2013  Meeting  Room  1
02Dec2013  Meeting  Room  2
03Dec2013  Meeting  Room  1
03Dec2013  Meeting  Room  2
04Dec2013  Meeting  Room  3
04Dec2013  Meeting  Room  1
;
run;

其中,Emp_name表示員工姓名,title表示員工的職位,time表示考核時間,room表示和時間對應的會議室。現在將時間和會議室分配給各 員工,示例代碼如下:

data  work.schedule;
merge  staff  time;
run;
proc  print  data=  work.schedule;
title  "Schedule  for  Performance  Management";
run;

2.2 使用BY語句實現橫向合並

使用BY語句進行數據集橫向合並的基本形式如下:

DATA  新數據集;
MERGE  數據集1 數據集2     <數據集3    數據集4     …   >;
BY 變量名1     <變量名2    變量名3     …   >;
RUN;

和之前介紹SET語句時提及的一樣,當使用BY語句時,輸入數據集必須按BY變量排序。

SAS在處理匹配合並的DATA步程序時,主要分以下兩個階段:

  • ·編譯階段,SAS在辨識出MERGE語句后,將按照其中數據集的排列順序,依次讀入所有數據集中變量的描述部分,包括DATA步中新創建變量的描述部分,並將所有變量置於PDV中。若不同的數據集中有同名的變量,則要求它們的數據類型必須相同,長度以第一次出現的變量為准。
  • ·執行階段,各輸入數據集中的觀測按BY變量進行匹配,在DATA 步的每次循環中依次讀入BY組合的每條觀測。如果遇到同名的變量,后讀入的變量值將覆蓋先讀入的變量值。由數據集中讀入的變量值,會自動地保留到BY變量值在所有輸入數據集中都改變為止。由DATA步新 創建的變量,其變量值在每次循環中都不能在PDV中自動保留,也就是說,在處理下一條數據之前它將被置為缺失值。

1.BY變量值在所有數據集中唯一

BY變量值在所有數據集中都是唯一的,即在任一輸入數據集中, 沒有兩條或兩條以上的觀測具有相同的BY變量值,這是最簡單的一種 情景。 

據集ex.staff_personel中包含了員工的基本信息,如Emp_ID、姓名、部門,另一個數據集ex.sales_current_month包含了員工本月的業績信息,如Emp_ID、產品種類和銷售額,但是不含有員工姓名。現在欲制作一張報表展現員工本月業績,並在報表中包含員工姓名 和部門數據。

首先得對ex.staff_personel和ex.sales_current_month按照Emp_ID進行排序,代碼如下:

proc sort data=ex.staff_personel  out=work.staff_personel;
by Emp_ID;
run;
proc  sort  data=ex.sales_current_month  out=work.sales_current_month;
by   Emp_ID;
run;

以下代碼實現了合並操作:

data  work.Staff_sales;
merge  work.staff_personel  work.sales_current_month;
by Emp_ID;
run;
proc  print  data=work.Staff_sales  noobs;
title'Staff  Sales';
run;

2.BY變量值在某一數據集中存在重復

BY變量值在某一輸入數據集中存在重復值,即在其中一個輸入數據集中,含有兩條或兩條以上的觀測具有相同的BY變量值,也稱為一對多合並。在匹配過程中會遵循如下原則:由輸入數據集讀入的變量 值,會保留在PDV中,直到被下一個讀入的觀測值覆蓋或該BY組合處 理完畢被重置為缺失值為止。接下來通過一個簡單的例子來具體講解這一原則。

數據集ex.sales_three_month中包含了最近3個月 的績效信息,每個員工每個月都有一條記錄,現在欲制作一個報告顯示 員工最近3個月的績效信息,並顯示員工的姓名和部門。

這里Emp_ID變量值在輸入數據集中不再是唯一的。以下代碼可以 實現員工信息和最近3個月績效信息的匹配:

proc  sort  data=ex.staff_personel  out=work.staff_personel;
by   Emp_id;
run;
proc  sort  data=ex.sales_three_month  out=work.sales_three_month;
by   Emp_id;
run;
data  work.staff_report;
merge  work.staff_personel  work.sales_three_month;
by     Emp_id;
run;
proc  print  data=work.staff_personel  noobs;
title  "Staff  Information";
run;
proc  print  data=work.sales_three_month  noobs;
title  "Sales  For  Three  Months";
run;
proc  print  data=work.staff_report  noobs;
title  "Staff  Report";
run;

3.BY變量值在多個數據集中存在重復

雖然在匹配合並時,一般情況下BY變量值至多在某一個數據集中有重復,但並不代表匹配合並只能處理這一種情況,它同樣可以處理兩個或兩個以上輸入數據集中的BY變量值重復的情況,也就是實現多對多合並。SAS的匹配原則和一對多合並時一樣,並且新數據集中每一個 BY變量值重復的次數和輸入數據集中重復次數最多的一樣。

運用MERGE語句進行多對多合並在實際應用中並不常見,但是理 解了SAS的匹配原則在實際應用中有助於開發人員進行程序調試和質量 控制。這里用一個簡單的例子幫助讀者理解。

 

data work.schedule;
merge work.staff work.time;
run;
proc print data=work.schedule;
run;

data work.test1;
input x y;
datalines;
1 2 
1 3
2 2
2 4
;
run;
data work.test2;
input x z;
datalines;
1 4 
1 9
2 3
2 9
3 4
;
run;
proc sort data= work.test1 out=work.merge1;
by x;
run;
proc sort data=work.test2 out=work.merge2;
by x;
run;
proc print data=work.merge1;
run;
proc print data=work.merge2;
run;
data work.merge_all;
merge work.merge1 work.merge2;
by x;
run;
proc print data=work.merge_all;
run;

3 使用數據集選項IN=操作觀測

在上例中,work.staff_personel數據集中有一部分員工沒有業績信息,如果不想將這些員工的信息包含在新生成的數據集中,就需要確定數據集work.staff_personel與work.sales_current_month是否分別輸出了它 們的觀測值到輸出數據集中。使用數據集選項IN=可以幫助實現這一功能。

數據集選項IN=的基本形式如下:

數據集(IN= 變量)

數據集選項IN=可以運用在SET、MERGE、MODIFY、UPDATE語 句中的任何數據集后面。變量是數值型臨時變量,不同的數據集應定義 不同的臨時變量名稱,臨時變量可以在DATA步中使用,但是不會在數 據集中輸出。在某一數據集后面使用(IN=變量)時,如果PDV中對應 的變量值是來自於這一數據集的觀測,臨時變量將被賦值為1,否則臨 時變量的值為0。特別是,當和BY語句一起使用時,可以通過判斷PDV 中BY變量的值是否來自於這一數據集來確定臨時變量的值。

以下程序對例4.8的數據集進行匹配合並時使用了數據集選項IN=。

由於選項IN=指定的只是臨時變量,為了在輸出數據集中能看到變量的

值,因此在程序中又將這些臨時變量的值賦給了新變量INA和INB。從 輸出結果可以看出,在合並以后的數據集中,來自work.staff_personel的 觀測的INA為1,來自sales_current_month的觀測的INB為1。

data  work.Staff_sales;
merge  work.staff_personel (IN=a)
work.sales_current_month (IN=b);
by Emp_ID;
ina=a;
inb=b;
run;
proc  print  data=work.Staff_sales  noobs;
title  'Staff  Sales';
run;

 

如果只想將既存在於work.staff_personel又存在於 work.sales_current_month中的員工記錄寫入新數據集中,可以通過IF語 句實現。

data  Staff_sales;
merge  staff_personel (IN=a)
sales_current_month (IN=b);
by Emp_ID;
if a and b;
run;

其中“if a and b;”是“if a and b then output;”的一種省略形式。

4. 數據集的更新 

 數據集的更新,指的是用一個數據集中的數據來替換另一個數據集 中的數據。SAS提供了UPDATE語句來實現數據集的更新

UPDATE語句如下:

DATA  WORK.DATA1;
UPDATE  WORK.DATA1  WORK.DATA2; 
BY Year;
RUN;

在運用UPDATE語句進行數據集更新時,通常稱DATA1為主數據集,DATA2為更新數據集。在上述示例中,主數據集和更新數據集通 過BY變量Year聯系起來,更新數據集中的非缺失的變量值替換了主數 據集中的變量值。對於更新數據集中存在缺失值的情況,在UPDATE語 句中可以運用選項UPDATEMODE=來控制是否用缺失值替換主數據集 中的變量值,系統默認UPDATEMODE=MISSINGCHECK,也就是不替 換;如果設置UPDATEMODE=NOMISSINGCHECK,則不管更新數據 集中的變量值是否是缺失值,都將替換。

使用UPDATE語句進行數據集更新的基本形式如下:

DATA  新數據集;
UPDATE  主數據集 更新數據集 <UPDATEMODE = MISSINGCHECK|NOMISSINGCHECK>; 
BY  變量1 <變量2  變量3 …>;
RUN;

更新后數據集的名稱可以是新的數據集名稱,不需要和主數據集同 名。新數據集中包含主數據集和更新數據集中的所有變量。

主數據集和更新數據集都必須按照BY變量排序。通常要求BY變量值在主數據集中必須是唯一的,且不需要進行更新,例如BY變量可以 是員工號或交易號。運用UPDATE語句時,如果SAS發現主數據集中BY 變量值有重復,SAS會在日志中輸出警告,此時雖然可更新成功,但是所有的更新只會作用在主數據集中BY組合的第一條觀測上。

某公司的市場部門將所有的客戶信息都存儲在數據集

work.Customer中,但是每年都需要對這些客戶信息進行及時更新,更新信息存儲在數據集work.UpdateInfo中。

以下代碼創建了數據集work.Customer和work.UpdateInfo。 work.Customer和work.UpdateInfo中包含了客戶編號、姓名、地址、聯系 方式等數據。

data  work.Customer;
input  Customer_ID  $1-4 Name  $  6-19  Address  $  21-37  City  $  39-51  State  $  53-54;
datalines;
C001   Jacob Adams          111   Clancey  Court  Chapel  Hill       NC 
C002   Emily  Anderson  1009 Cherry  St.       York                        PA 
C003   Michael  Arnold  4  Shepherd  St.          Vancouver            BC 
C004   Hannah  Baker       Box  108                           Milagro                 NM
;
run;
proc  print  data=work.Customer  noobs;
title  "Customer  - Master  Data";
run;
data  work.UpdateInfo;
infile  datalines  missover;
input  Customer_ID  $1-4 Name  $  6-19  Address  $  21-37  City  $  39-51  State  $  53-54
;
datalines;
C001    14   Bridge  St.    San  Francisco  CA 
C002   Emily  Cooker 42   Rue  Marston
C002    52   Rue  Marston   Paris
C005   Jimmy  Cruze Box  100    Cary    NC
;
run;
proc  print  data=work.UpdateInfo  noobs;
title  "Update  Information  - Yearly  Transaction  Data";
run;

Customer_ID是客戶的注冊號,對於客戶來說,這個注冊號是唯一的。由於work.Customer和work.UpdateInfo都已經按照 Customer_ID排過序,因此在更新前不需要重新排序。接下來用 UPDATE語句對數據集work.Customer進行更新。示例代碼如下:

data  work.Customer_update;
update  work.Customer  work.UpdateInfo;
by   Customer_ID;
run;
proc  print  data=work.Customer  noobs;
title  "Customer- Master  Data  Update";
run;

在上例中,主數據集中的BY變量是唯一的,更新數據集中的BY變 量值存在重復值,我們可以有如下發現:

  • ·當更新數據集中BY變量值存在重復值時,BY組合中的后一條觀測 會覆蓋前一條觀測。例如Customer_ID為C002的更新信息分別記錄在 work.UpdateInfo的兩條觀測中,更新后的數據集中Customer_ID為C002 的觀測是唯一的,並且Address為work.UpdateInfo中后一條觀測的值。
  • ·當更新數據集中的某一條觀測在主數據集沒有對應的觀測時,SAS 會直接將這條觀測作為更新的基礎,然后結合更新數據集中剩余的觀測 繼續處理該觀測。如上例中Customer_ID為C005的觀測在主數據集中不 存在,SAS將其作為了更新的基礎,由於更新數據集中不含有其他 Customer_ID為C005的觀測,所以該條觀測被直接加入新數據集中。

UPDATE語句和MERGE語句都可以對兩個數據集進行匹配合並,但是存在比較大的區別,如下:

  • ·UPDATE語句只能操作兩個數據集;MERGE語句可以對兩個或兩 個以上數據集進行操作。
  • ·使用UPDATE語句時必須使用BY語句;MERGE語句在不使用BY語句的時候也可以按觀測號進行一對一合並。
  • ·在處理缺失值時,UPDATE語句可以控制是否用缺失值對主數據 集進行替換;MERGE語句中后一數據集中的缺失值一定會覆蓋前一數 據集中的值。
  • ·當BY變量值在后一數據集或者更新數據集中不唯一時,UPDATE 語句和MERGE語句的處理方式不一樣,詳見上一章節中MERGE語句的 多種情形和本節前面部分的介紹。 
data  work.Customer;
input  Customer_ID  $1-4 Name  $  6-19  Address  $  21-37  City  $  39-51  State  $  53-54;
datalines;
C001 Jacob Adams    111 Clancey Court Chapel Hill   NC 
C002 Emily Anderson 1009 Cherry St.   York          PA 
C003 Michael Arnold 4 Shepherd St.    Vancouver     BC 
C004 Hannah Baker   Box 108           Milagro       NM
;
run;
proc  print  data=work.Customer  noobs;
title  "Customer  - Master  Data";
run;
data  work.UpdateInfo;
infile  datalines  missover;
input  Customer_ID  $1-4 Name  $6-19  Address  $21-37  City  $39-51  State  $53-54
;
datalines;  
C001                 14 Bridge St. San Francisco    CA 
C002 Emily Cooker    42 Rue  Marston
C002                 52 Rue  Marston   Paris
C005 Jimmy Cruze     Box 100           Cary         NC
;
run;
proc  print  data=work.UpdateInfo  noobs;
title  "Update  Information-Yearly  Transaction  Data";
run;

data  work.Customer_update;
update  work.Customer  work.UpdateInfo;
by   Customer_ID;
run;
proc  print  data=work.Customer  noobs;
title  "Customer- Master  Data  Update";
run;

5. 數據集的更改

SAS提供了MODIFY語句進一步擴充了DATA步的功能,它可以在 原數據集上直接進行替代、刪除或添加觀測的操作。

5.1 單個數據集的更改

運用MODIFY語句進行單個數據集更改的基本形式如下:

DATA  原數據集;
MODIFY  原數據集;
RUN;

運用MODIFY語句,可以更改原數據集中任何變量的值,但是由於 該語句不能夠更改原數據集的描述部分,因此不能在原數據集中添加或 者刪除變量。以下通過一個銷售管理系統的例子來講解MODIFY語句的 運用。

數據集work.inventory中包含產品、庫存和價格的信息,以下代碼創 建了數據集work.inventory。

data  work.inventory;
input  Product_ID  $  Instock  Price;
datalines;
P001R   12  125.00
P003T   34  40.00
P301M   23  500.00
PC02M   12  100.00;
proc  print  data=work.inventory  noobs;
title  "Warehouse  Inventory";
run;

數據集work.inventory內容如圖4.19所示。 例4.11:由於物價上漲導致成本上升,公司決定將每種產品的銷售價格提高15%。 示例代碼如下:

data  work.inventory;
modify  work.Inventory;
price=price*1.15;
run;
proc  print  data=work.inventory  noobs;
title  'Price  reflects  15%  increase';
run;

4.4.2 兩個數據集的更改

使用MODIFY語句可以實現通過一個數據集對另一個數據集中的數 據進行更改,基本形式如下:

DATA  主數據集;
MODIFY  主數據集 修改數據集;
BY 變量1   <變量2 變量3   …>;
RUN;

其中,主數據集表示需要更改的數據集,修改數據集中包含了用於更改的數據,此時必須使用BY語句。在使用MODIFY時,主數據集和 修改數據集中的BY變量不需要事先排序或索引,但是按BY變量排序或 索引可以提高運行效率,特別是在觀測量很大的情況下。

在使用MODIFY更改數據集時,需要注意以下兩點:

  • ·當主數據集中的BY變量值有重復值時,只有每個BY變量值的第一條觀測會被更改;當修改數據集中的BY變量值有重復值時,系統會依次讀入修改數據集中的每一條觀測,並應用到主數據集,且后讀入的觀 測會覆蓋前一次讀入的觀測;當主數據集和修改數據集中的BY變量值都有重復值時,系統會依次操作修改數據集中BY組合中的每一條觀測,並且應用到主數據集中對應BY組合的第一條觀測中。
  • ·如果在修改數據集中存在缺失值,系統默認不用缺失值更改主數據集中的數據。如果需要用缺失值更改主數據集,可以仿照在UPDATE 語句中使用選項UPDATEMODE=實現操作。

實際上,在主數據集或修改數據集中BY變量值有重復值時,MODIFY語句的處理邏輯和UPDATE語句一樣。

例4.12:接着例4.11繼續操作,數據集work.inventory2中保存了公司 產品在海外倉庫的庫存信息,現在公司財務欲根據work.inventory和 work.inventory2中的數據計算公司各產品的總庫存,並制作報告。

以下代碼創建數據集work.inventory2。

data work.inventory2;
input  Product_ID  $  Outstock  ;
datalines; P001R   12
P001R   30
P001R   25
P003T  34
P301M  23
;
proc  print  data=work.inventory  noobs;
title  "Warehouse  Inventory  Inhouse";
run;
proc  print  data=work.inventory2  noobs;
title  'Warehouse  Inventory  Overseas';
run;

兩個數據集work.inventory和work.inventory2的內容如圖4.21所示。 需要注意的是,在work.inventory2中,產品P001R有三條觀測。 計算各產品總庫存的程序如下:

data  work.inventory;
modify  work.inventory  work.inventory2;
by  product_id; instock=instock+Outstock;
run;
proc  print  data=work.inventory  noobs;
title  'Total  Inventory';
run;

程序中加入“instock=instock+Outstock;”用來計算instock並輸出到數據集work.inventory中,產品P001R的instock的值等於原work.inventory 數據集中P001R的instock值加上work.inventory2中P001R的3條觀測的 instock值。

以上例子中,修改數據集中的所有觀測在主數據集中都可以找到對 應的觀測,當修改數據集中含有一些新觀測時,可以使用OUTPUT語句 將新觀測添加到主數據集中,具體使用方法請查詢SAS幫助文檔。

6.  數據集處理的一點補充

1 使用數據集選項END=

很多情況下,在進行數據操作時需要知道SAS在什么時候處理輸入 數據集的最后一條觀測,這時可以使用SAS提供的數據集選項END=來 幫助辨識。使用數據集選項END=的基本形式如下:

SET  數據集1 <數據集2   數據集3…   >END=變量;

在使用SET、MERGE、MODIFY、UPDATE語句時,都可以使用該 選項。這里語句中的變量是數值型的臨時變量,當DATA步在操作數據 集的最后一條觀測時,該變量的取值為1,否則為0。臨時變量可以在 DATA步中使用,但是不會在數據集中輸出。需要特別注意的是,在使 用SET、MERGE、MODIFY、UPDATE語句進行多個數據集處理時,只有當DATA步處理所有輸入數據集的最后一條觀測時,該變量的取值才 會由0變成1。 

數據集work.Sales中記錄了公司每位員工的全年的銷售額, 現在欲計算全年公司的總銷售額,並輸出到報表中。

以下代碼創建了work.Sales數據集,Emp_ID表示員工編號,Dept表示員工所屬部門,Sales表示銷售額。

data  work.sales;
input  Emp_ID  $  Dept  $  Sales  Gender$;
datalines; 
ET001   TSG  100   M 
ED001  DSG  200   F 
ED001  DSG  135   M 
EQ001  QSG  234   F 
ET001   TSG  125   F 
ET002   TSG  98   M 
EQ002  QSG  100   M 
EQ003  QSG  98   M 
ED002  DSG  124   M 
ET003   TSG  123   F
;
run;
proc  print  data=work.sales;
title  'Sales';
run;

現在運用END=選項計算公司全年的總銷售額。 

data  work.total_sales;
set  work.sales  END=last;
total_sales+sales;
if last  then  output;
keep total_sales;
run;
proc  print  data=work.total_sales  noobs;
title  'Total  Sales  in  Million';run;

 

上面這段代碼中有以下幾個要點:

  • ·END=last定義了臨時變量last,當SAS在處理最后一條觀測時,last的取值將變為1。
  • ·“total_sales+sales;”計算公司的全年銷售 額。“total_sales+sales;”的作用和“retain total_sales 0; total_sales=total_sales+sales;”一樣。
  • ·IF語句和OUTPUT語句判斷了最后一條觀測,並將該觀測輸出到數據集中。
  • ·KEEP語句僅將需要輸出的total_sales變量保留在數據集中。 上面計算全年銷售額的代碼和下面的代碼等價。
data  work.total_sales;
set  work.sales  END=last; retain  total_sales  0; total_sales=total_sales+sales; if last  then  output;
keep total_sales;

5.2 使用自動變量FIRST.與LAST.

DATA步中若使用了BY語句,SAS要求讀入的數據集必須按BY 變量排序(MODIFY語句除外),同時,SAS在程序執行過程中會自動 生成兩個數值型臨時變量:FIRST.變量和LAST.變量,它們分別用來辨 識BY組合的第一條觀測和最后一條觀測。當只有一個BY變量時,很容 易理解它的取值。

·當DATA步正在處理該BY變量值的第一條觀測時,FIRST.變量為1,否則為0。

·當DATA步正在處理該BY變量值的最后一條觀測時,LAST.變量為1,否則為0。

當有多個BY變量時,系統會自動生成多對FIRST.變量和LAST.變 量。例如,SAS在執行如下代碼時,會自動生成臨時變量FIRST.x和 LAST.x,以及FIRST.y和LAST.y。

data  work.test; input  x  y  $  @@; datalines;
1  A  1  A  1  B  2  B  2  C
;
run;
data  work.try;
set  work.test;
by   x  y;
firstx=first.x; lastx=last.x;
firsty=first.y; lasty=last.y;
run;

SAS處理第一條x=1的觀測時,first.x=1;當SAS處理最后一條 x=1的觀測時,last.x=1;當SAS處理第一條x=1並且y=“A”的觀測時, first.y=1;當SAS處理最后一條x=1並且y=“A”的觀測時,last.y=1。 

據集work.Sales中包含了每位員工的銷售額和員工所屬部

門及性別數據,現在公司欲統計各部門男員工和女員工的總銷售額,並 制成報表。

首先將work.Sales數據集按Dept和Gender進行排序,然后再運用選 項FIRST.與LAST.計算各部門男女員工的總銷售額。

proc  sort  data=work.sales;
by   Dept  Gender;
run;
data  work.sales_dept;
set  work.sales; by Dept  Gender; retain  sales_by_dept;
if first.Gender  then  sales_by_dept=0;
sales_by_dept=sales_by_dept+sales;
if last.Gender;
keep Dept  Gender  sales_by_dept;
run;
proc  print  data=work.sales_dept  noobs;
title  'Sales  by   Department  by   Gender';
run;

“if last.gender;”是“if last.gender then output;”的省略寫法。這里使用了RETAIN語句,使得在DATA步的循環中sales_by_dept的值可以保留 在PDV中。BY語句創建的這兩個臨時變量不僅可在SET語句讀入單個數據集時 使用,在進行多個數據集的拼接時也常使用。

 

5.3 使用SET語句中的選項POINT=和NOBS=

DATA步使用SET語句讀入數據集時,可使用選項POINT=指明要 讀入的觀測序號。使用選項POINT=的基本語法如下:

SET 數據集POINT=指針變量;

其中指針變量用來指明要讀入特定序號的觀測,必須在SET語句執 行前對它賦值。在有SET語句的DATA步程序中,系統將反復執行 DATA步的語句,直到遇到數據中的文件結束標志。但是在使用選項 POINT=時,系統會直接讀入指針指向的記錄,這就很可能導致系統不 會遇到文件結束標志,容易陷入死循環。因而在按指針讀入數據的程序 中,經常會用到STOP語句。

如果要取得數據集中觀測的個數,可以使用SET語句中的選項

NOBS=,語法如下:

NOBS=變量;

其中,變量同樣是臨時變量,在DATA步的編譯階段賦值。

4.15:現有一個數據集work.Whole,欲從其中隨機抽取1/3的觀測

用來建立模型。

示例代碼如下:

data  work.sample;

do   i=1  to  total  by   3;

set  work.whole  point=i  nobs=total;

output;

end;

stop;

run;

運行這個代碼,系統將從數據集work.sample中依次抽出第1條觀 測、第4條觀測…,並存儲到數據集work.sample,直到系統處理完數據 集中的全部觀測。

5.4 使用多個SET語句

SAS中實現同一個操作,往往可以有多種方法。作為補充,這里 將介紹如何運用SET語句進行數據集橫向合並。使用SET進行橫向合並 的一個好處是,在合並之前不需要將輸入數據集進行排序。

下是使用多個SET語句的一個簡單例子。

data  work.data1; 
input  x  y  @@; 
datalines;
1  2  2  3  3  4
;
run;
data  work.data2; 
input  x  z @@; 
datalines;
1  3  3  5  4  2  5  4
;
run;
data work.combined; 
set work.data1; 
set  work.data2;
run;
proc  print  data=work.Combined;
title  'Using  Two  Set  in  Data  Step';
run;

數據集work.data1和數據集work.data2的內容如所示。 合並后的數據集work.combined如圖所示。

 

 

 

在使用多個SET語句時,PDV中的變量是讀入數據集的並集。首 先,DATA步從第一個SET語句中讀入第一條觀測,並復制到PDV中; 然后從第二個SET語句中讀入第一條觀測,並復制到PDV中。當輸入數 據集中有同名變量時,后讀入的數據集的變量值覆蓋前一個數據集中同 名變量的值。新數據集中的觀測數是所有輸入數據集中的觀測數的最小 值,因為當DATA步遇到第一個文件結束標志時,DATA步就結束執 行。

5.5 使用HASH對象處理多個數據集

前面部分已經介紹了運用SET語句和MERGE語句進行數據集之間的拼接,這里將通過實例介紹如何運用HASH對象實現這類操作。相較於SET語句和MERGE語句,使用HASH對象有兩個優點,第一,它對數據集的排序沒有要求;第二,由於HASH對象是放入內存中的數據集,因此在內存允許的情況下,運用HASH對象進行數據集之間 的關聯時其效率更高。

一般在觀測數很多的數據集與觀測數較少的數據集進行匹配時,運用HASH對象將較小的數據集加載到內存中,可以非常快速地完成匹 配。

接下來首先介紹在DATA步中如何定義HASH對象。

1.定義HASH對象

使用HASH對象時,首先要定義HASH對象,基本形式如下:

DECLARE object HASH對象名(<主題1:  內容1  <,  主題2:  內容2,  …>>); 
HASH對象名.DEFINEKEY(<主題1:  內容1  <,  主題2:  內容2,  …>>);
HASH對象名.DEFINEDATA(<主題1:  內容1  <,  主題2:  內容2,  …>>); 
HASH對象名.DEFINEDONE();

這里第一行定義了HASH對象名稱,object可以是HASH或HITER,HASH對象名由編程者定義。

第二行和第三行分別通過HASH對象名.method的語法定義了HASH對象的KEY變量和DATA變量,這些變量都是DATA步中的變量。 第四行表明HASH對象定義結束。

現在有一個數據集work.Sales,其中包含了員工編號 Emp_ID、員工部門Dept、銷量Sales、產品編號Product_id,另一個數據 集work.Product中包含了Product_id、Product_name和Description 3個變 量,現在欲將Product_name和Description加到數據集Sales中。

以下代碼生成Sales和Product中的部分數據。

data  work.sales;
input  Emp_ID  $  Dept  $  Sales  Product_ID  $;
datalines;
ET001   TSG  100   P001
ED001  DSG  120   P001
ET001   TSG  50   P002
EC001   CSG  230   P004
EQ001  QSG  150   P003
ET001   TSG  210   P004
ET002   TSG  40   P002
ET003   TSG  150   P003
;
run;
data  work.product;
infile  datalines  dsd;
length  Product_ID  $4   Product_Name  Description  $35; input  Product_ID  $  Product_Name  $  Description  $; 
datalines; P001,ManufacturingIndustry Solutions,ManufacturingIndustry Solutions V2 P002,Logistics Solutions,Logistics Solutions V1 P003,Financial Service Solutions,Financial Service Solutions V3 P004,Insurance Solutions,Insurance Solutions V2 ; run;

以下是通過HASH對象實現匹配的完整代碼。

data  work.sales_description(drop=ErrorDesc) work.exception;
length  Product_ID  $8   Product_Name  Description  $35;
if _N_=1  then do;
/*Define  hash objective*/
Declare hash product_desc(dataset:"work.product"); 
product_desc.definekey('Product_ID'); 
product_desc.definedata('Product_Name','Description'); 
product_desc.definedone();
call  missing(Product_ID,Product_Name,Description);
end;
set  work.sales;
/*Retrieve  matching  data*/
rc=product_desc.find();
if rc =  0  then
output  sales_description;
else
do;
ErrorDesc="No  Product  Description";
output  exception;
end;
drop  rc;
run;

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM