2013年6月23日

【SAS 小技巧】以文字格式讀取CSV資料檔中的欄位(變項)

 

在實務工作將資料中所有的欄位(變項)先以文字格式(character format)匯入,在做後續的分析是很實務的作法。為何會有這種作法?主要是SAS以PROC IMPORT匯入CSV檔案時,會預先猜測欄位的格式,在"自動"給予文字或數字格式,如果不幸某個欄位是以混合格式(mixed format)鍵入,SAS很有可能會採用數字格式匯入該欄位,而導致欄位中非數字的資料變成遺漏值(missing value)。

這篇小文章中我打算介紹三種方法來處理這樣的方法,如果你的時間不夠,請直接跳到方法三。

方法1: PROC IMPORT中使用GUESSINGROWS

使用GUESSINGROWS可以讓SAS在猜欄位格式時,多讀一點欄位後再猜測,預設為20列,最多可以設到2147483647列。

如果以【程式1】的PROC IMPORT程式匯入練習用檔案時,可看到欄位V2的第23筆資料為遺漏值。

image

【程式1】

PROC IMPORT OUT= WORK.data1
            DATAFILE= "d:\TEMP\bigdata.csv"
            DBMS=CSV REPLACE;
     GETNAMES=YES;
     DATAROW=2;
RUN;


在【程式1】中加入GURSSINGROWS並設定適當列數後,可順利將欄位V2以文字格式匯入【程式2】。為何要說適當列數,因為當設定的列數過多時,例如設為最大值,遇到大型的CSV檔案會花較長時間執行,寫程式的時候必須要斟酌考慮的。

【程式2】

PROC IMPORT OUT= WORK.data2
            DATAFILE= "d:\TEMP\bigdata.csv"
            DBMS=CSV REPLACE;
     GETNAMES=YES;
     DATAROW=2;
     GUESSINGROWS=1000 ;
RUN;


方法2: 利用PROC IMPORT的LOG資料

這是一個偷吃步吧,當執行完PROC IMPORT後,至LOG視窗中,可以注意到有一段SAS幫大家寫好的匯檔程式,如下圖:

image

然後只要把從 data WORK.DATA2 一直到 run; (也就是程式行號50到68),中間的語法複製到程式編輯視窗,在把一些與巨集相關的語法刪除後(第51和67號),最重要將所有informat、format、input做適當的修改後,就可以順利把所有欄位都讀成文字格式了。

所謂適當修改就是把informat和format後面的格式改成  $數字. (有點),然後把input的欄位名稱後面補上 $ 。修改後程式於【程式3】

【程式3】

data WORK.DATA2    ;
infile 'd:\TEMP\bigdata.csv' delimiter = ',' MISSOVER DSD lrecl=32767 firstobs=2 ;
          informat v1 $20. ;
          informat v2 $20. ;
          informat v3 $20. ;
          informat v4 $20. ;
          format v1 $20. ;
          format v2 $12. ;
          format v3 $20. ;
          format v4 $20. ;
       input
                   v1 $
                   v2 $
                   v3 $
                   v4 $
     ;
run;

此部分說明,也可參考 [SAS] 完整匯入Excel格式檔案 的介紹。


方法3: SAS MACRO匯入CSV資料

必須先說明,這個一段主程式不是我所寫的,主程式的來源為 http://stackoverflow.com/questions/14614369/import-all-columns-from-csv-as-character 這篇的解答。

這是一隻程式的功能就是將方法二所需要的步驟,利用MACRO自動撰寫匯入程式,因此非常的好用,有這個巨集後也不用在人工一個一個將欄位修改成文字格式,而原程式沒有考量欄位資料可能會多於8個字元,因此我稍作修改,增加可設定欄位長度。

【程式4】

%macro readcsv(dsn,fn,vl);
/* MACRO TO READ ALL COLUMNS OF A CSV AS CHARACTER */
/* PARAMETERS:                                     */
    /*   DSN - THE NAME OF THE SAS DATA SET TO CREATE  */
    /*   FN  - THE EXTERNAL FILE TO READ (QUOTED)      */
    /*   VL  -  THE VARIABLES LENGTH      */
/* EXAMPLE:                                        */
    /*    %READCSVE (WANT, 'C:\TEMP\TEMPFILE.CSV', 10);       */ %let test_length=500;
data _null_;
  infile &fn LRECL=32767;
  input;
  i = 1;
  length headers inputstr lengthstr_test lengthstr $32767;
  headers = compress(_infile_,"""'");
  newvar = scan(headers,1,',');
  do until (newvar = ' ');
     inputstr = trim(inputstr) || ' ' || trim(newvar) || " $";
     lengthstr= trim(lengthstr) || ' ' || trim(newvar) || " $&vl..";
     i + 1;
     newvar = scan(headers,i,',');
     end;
  call symput('inputstr',inputstr);
  call symput('lengthstr',lengthstr);
  stop;
run;
%put inputstr &inputstr;
%put lengthstr &lengthstr;
data &dsn;
  infile &fn firstobs=2 dsd dlm=',' missover dsd lrecl=32767 firstobs=2;
  length &lengthstr.;
  input &inputstr.;
run;
%mend readcsv;

用法非常簡單,%readcsv( 輸出資料名稱, '資料路徑和名稱組合' , 欄位長度 ),如果要讀入範例的檔案,巨集的寫法為下;

%readcsv (data3, 'd:\TEMP\bigdata.csv', 50);

需要留意的事情是,因為欄位長度設定是所有欄位均適用,如果設定太長,資料筆數又多,匯入的資料檔會變成相當巨大,執行上也會很慢。

當然還是有人工解決辦法,先把長度設為適當數字,然後在執行巨集前先執行下面的系統指令

OPTION MPRINT;

在執行巨集後,到LOG視窗中,應該會看到一段匯入的程式,我想聰明的你應該知道要如何利用這段程式了。


練習用資料和本文章使用程式語法:  http://goo.gl/zo60Q

沒有留言:

張貼留言