2016年10月19日水曜日

INFILEステートメントの DSD MISSOVER の挙動




「INFILEで外部ファイルを読み込むときに指定する ”DSD MISSOVER” ってどういう役割?」
って質問をよくもらいます。

具体例で各オプションの役割を見ていきましょう。



DSDの役割


外部ファイルからカンマ(,)等の区切り記号毎に値を区切って読み込む際、挙動を細かく設定するオプションです。


例1
読み込むCSVファイル … C:\test\sample1.csv
1,,2


*** DSDあり ;
data OUT1;
  length A B C 8.;
  infile "C:\test\sample1.csv" dlm="," dsd missover ;
  input A B C;
run;
  A  
  B  
 C 
  1   .   2   

*** DSDなし ;
data OUT1;
  length A B C 8.;
  infile "C:\test\sample1.csv" dlm="," missover ;
  input A B C;
run;
  A  
  B  
 C 
  1   2  .   

  • 上記テキストファイルで「1,,2」 というように区切り記号が連続する部分をDSDオプションにより欠損値として扱うよう設定できます。
  • またこの例では分からないですが、DSDを指定することによって、区切り記号のデフォルトがカンマ(,)に変わります(デフォルトは半角スペース)。区切り記号は「DLM=オプション」で変更可能です。


例2
読み込むCSVファイル … C:\test\sample2.csv
1,2,"x, y and z"


*** DSDあり ;
data OUT2;
  length A B 8. C $10.;
  infile "C:\test\sample2.csv" dlm="," dsd missover ;
  input A B C;
run;
  A  
  B  
 C 
  1   2  x, y and z 

*** DSDなし ;
data OUT2;
  length A B 8. C $10.;
  infile "C:\test\sample2.csv" dlm="," missover ;
  input A B C;
run;
  A  
  B  
 C 
  1   2  "x   

DSDの挙動として、
テキストファイルが「"x, y and z"」というようにクォーテーションで囲まれていると、そのクォーテーションを取り除いた上で中の文字全体を区切り記号もろとも1つの変数に読み込むことが出来ます。



MISSOVERの役割


読み込むCSVファイル : C:\test\sample3.csv
1,2
3,4,5


*** MISSOVERあり ;
data OUT3;
  length A B C 8.;
  infile  "C:\test\sample3.csv" dlm="," dsd missover ;
  input A B C;
run;
  A  
  B  
 C 
  1   2  .   
  3   4  5  

*** MISSOVERなし ;
data OUT3;
  length A B C 8.;
  infile  "C:\test\sample3.csv" dlm="," dsd;
  input A B C;
run;
  A  
  B  
 C 
  1   2  3   


input A B C;」 というように変数を3つ割り当てていますが、
テキストファイルの1行目は 「1,2」 となっているので変数Cを割り当てるデータがありません。
(変数Cを欠損値にしたいのであれば 「1,2,」 というように区切り記号を最後にもつける)

なので、SASは足りない部分を次の行から取ってこようとしちゃいます。
MISSOVERは足りない部分を「欠損値で埋める」という処理をしてくれます。



ただし!

MISSOVERより「TRUNCOVER」というオプションを使用すべき場合があるのでご注意ください
(以下、海外のPaper参照。挙動が分かりやすいです)




一応、軽く説明。

読み込むテキストファイル : C:\test\sample4.txt
a xxx
b yy
c z

*** オプション指定なし ;
data OUT4;
  length A B $10.;
  infile  "C:\test\sample4.txt";
  input A 1-2 B 3-5;
run;
 A  
 B  
 a  xxx 
 b c z

*** MISSOVER ;
data OUT4;
  length A B $10.;
  infile  "C:\test\sample4.txt" missover ;
  input A 1-2 B 3-5;
run;
 A  
 B  
 a  xxx 
 b 
 c 

*** TRUNCOVER ;
data OUT4;
  length A B $10.;
  infile  "C:\test\sample4.txt" truncover ;
  input A 1-2 B 3-5;
run;
 A  
 B  
 a  xxx 
 b yy
 c z


今回は「input A 1-2 B 3-5;」みたいに、カラム(バイト)指定して読み込んでいますが、「TRUNCOVER」以外は臨んだ結果になっていません。

原因として、INPUTステートメントで「B 3-5」として3~5バイト目を読み込んで変数Bに格納するよう指定していますが、以下の通りテキストファイルの2行目と3行目は5バイト目がありません。

a xxx
b yy
c z

  • 読み込むバイト数が足りない場合、そのデータの読み込みがスキップされて、上で示した「オプション指定なし」の結果のようにデータがズレた感じで読み込まれちゃいます。
  • 「MISSOVER」を指定すると、データのズレはなくなりますが、バイト数が足りない部分は欠損値になっています。
  • 「TRUNCOVER」を指定すると、データのズレもなく、バイト数が足りない部分も読み込んでくれています。

ちなみに、以下のように後ろを半角スペースで埋めていれば、バイト数が足りないとは判定されません。

a xxx
b yy 
c z  


このように、INFILE・INPUTの指定方法(と、もしかしたら環境)によって挙動が様々なので、都度挙動の確認はした方がよいです。
ちなみに今回のようなデータをCARDSステートメントで読み込む場合はまた挙動が変わります。

なんてややこしい仕様だ!


0 件のコメント:

コメントを投稿