動かして覚える infileステートメント filevar オプション ~複数ファイルをヘッダを飛ばして一括で読み込む~ - SAS

複数のファイルを dataステップ1回で読み込もうとしたとき、それぞれのファイルに読み込ませたくないヘッダーがあると、firstobs オプションを使ってもヘッダを飛ばせず上手く読み込まれません。しかし、filevar オプションを使ってみたところ、上手く全てのヘッダを飛ばして読み込ませることができたので、その方法と filevar オプションについてご紹介します。

(※ filevar オプションではなく、eov オプションを用いた解決方法が、データステップ100万回 SAS新手一生 の記事「filenameで複数ファイルを一括指定して、読み込む場合に各ファイル1行目がラベル行だと、難しいことになるがeovをうまく使えば解決できる話」にて、ご紹介されていますので、こちらもご参考ください。)

(※ filevar オプションによる解決方法は、コーディングミスによる無限ループの危険性があるから、ヘッダを飛ばすだけなら、eov オプションの方が良いかもしれません。)


サンプルに用意した入力ファイルは、以下のようなファイルです。

  • 格納場所  : /folders/myfolders/filevar/
  • 文字コード : Shift-JIS
  • 改行コード : CRLF
  • 区切り文字 : , (カンマ)

なにも考えずに読み込むと、以下みたいに、ヘッダが残ってしまいます。

filename IN "/folders/myfolders/filevar/test?.txt" ;

data TEST ;
  infile IN dlm=',' dsd missover lrecl=1048576 encoding="sjis" termstr=CRLF ;
  input V1 : $CHAR10.
        V2 : 8.
        V3 : $CHAR60.
        ;
run ;

filename のファイル名に指定している ? は1文字にマッチするワイルドカードです。

encoding オプション
入力ファイルの文字コードを指定する。
termstr オプション
入力ファイルの改行コードを指定する。

infile ステートメントに、firstobs=2 を付けても、最初のオブザベーションだけがスキップされ、2ファイル目以降のヘッダは残ってしまいます。



filevar オプションを使ってみよう。

data TEST ;
  drop I ;
  length F_NAME $100. ;
  do I=1 to 3 ;
    /* 入力ファイル名変更 */
    F_NAME = cats("/folders/myfolders/filevar/test", put(I, 1.), ".txt") ;

    infile dummy filevar=F_NAME dlm=',' dsd missover lrecl=1048576
           encoding="sjis" termstr=CRLF firstobs=2 end=EOF ;

    /* ファイルの最後の行まで読み込む */
    do until(EOF) ;
      input V1 : $CHAR10.
            V2 : 8.
            V3 : $CHAR60.
            ;
      output ;
    end ;
  end ;
  stop ; /* 無限ループ防止 */
run ;
cats 関数
複数の文字列を前後のブランクを除去して連結する。

最初のループでは、cats関数で文字列が連結されて、/folders/myfolders/filevar/test1.txt が 変数 F_NAME に格納されます。格納された値が、読み込まれるファイルとなります。

filevar オプションは、infile ステートメントの中で、filevar = 変数名 という感じで指定します。指定された変数の値が変更されると、読み込まれるファイルが変更になります。サンプルでは、変数 F_NAME を指定しています。

infile に、firstobs=2 を付けることで、各ファイルの1行目、ヘッダーを飛ばして、読み込まれるようにしています。1回1回の infile ステートメントにて、1ファイルずつファイルが指定されるので、firstobs=2 がうまい具合に機能します。

test1.txt が infile ステートメントの後の input ステートメントで読み込まれるわけですが、サンプルでは、do until(EOF) で input ステートメントを囲っています。なぜ囲っているのかというと、以下のように do until(EOF) を使わず input だけを書くと、ファイルが1オブザベーションしか読み込まれないからです。

    infile dummy filevar=F_NAME dlm=',' dsd missover lrecl=1048576
           encoding="sjis" termstr=CRLF firstobs=2 end=EOF ;
    /* ダメな例 : この書き方だと1オブザベーションしか読み込まれないよ! */
    input V1 : $CHAR10.
          V2 : 8.
          V3 : $CHAR60.
          ;
    output ;

end オプションと do until を使うことで、ファイルの終端まで読み込まれるようにしています。

run ; の直前で stop ステートメントを実行しているのは、無限ループを防ぐためです。stop しないと、悲しいことになるので、ご注意ください(ついさっきやった経験者より)。

filevar オプション を用いて、複数ファイルをヘッダを飛ばして一括で読み込むことができました!

filevar オプションの特徴は、dataステップ内で、読み込むファイル名を動的に変更することができる点ですね。連番のファイル名だけでなく、ファイル名に年月日が付いているものだったり、もう少し複雑なファイル名にも対応できます。読み込むファイルを増やしたり減らしたりもできそうです。



ワイルドカードを使ってしまうと、ヘッダをうまく飛ばせなくなる!

    /* 入力ファイル名変更 */
    F_NAME = cats("/folders/myfolders/filevar/test*.txt") ;

ヘッダをうまく飛ばす方法ですが、入力ファイルにワイルドカード * ? が使われていて、複数ファイルがマッチしてしまうと、うまく飛ばせなくなります。あくまで、1ファイル1ファイルずつ読み込もうとするからうまくいく方法なので、ご利用の際はご注意ください。



入力ファイルの一覧が別のデータセットに格納されている場合

入力ファイルの一覧が別のデータセットに格納されていても、少しの変更で対応できます。

data IN_FILE_PATH ;
  PATH = "/folders/myfolders/filevar/test1.txt" ; output ;
  PATH = "/folders/myfolders/filevar/test2.txt" ; output ;
  PATH = "/folders/myfolders/filevar/test3.txt" ; output ;
run ;

data TEST ;
  drop I PATH ;
  do I=1 to TOTAL ;
    set IN_FILE_PATH nobs=TOTAL ;

    infile dummy filevar=PATH dlm=',' dsd missover lrecl=1048576
           encoding="sjis" termstr=CRLF firstobs=2 end=EOF ;

    /* ファイルの最後の行まで読み込む */
    do until(EOF) ;
      input V1 : $CHAR10.
            V2 : 8.
            V3 : $CHAR60.
            ;
      output ;
    end ;
  end ;
  stop ; /* 無限ループ防止 */
run ;

入力ファイル名は、データセット IN_FILE_PATH の変数 PATH に格納されています。

do ループの終わりの数字を データセット IN_FILE_PATH のオブザベーション数に変更しています。これで、入力ファイルの数がいくつであっても対応できます。

filevar オプションは、filevar=PATH に変更しています。データセット IN_FILE_PATH 1オブザベーション読み込まれるたびに、変数 PATH の値が変更になり、読み込む入力ファイルが変更されるようにしています。



参考サイト

  1. 複数の外部ファイルにデータを書き出す方法 | SAS社 FAQ
  2. filenameで複数ファイルを一括指定して、読み込む場合に各ファイル1行目がラベル行だと、難しいことになるがeovをうまく使えば解決できる話 | データステップ100万回 SAS新手一生

コメント

このブログの人気の投稿

日付フォーマットでない文字項目をSAS日付に変換するときにログ出力されるメッセージを抑制したい - SAS

データセット(.sas7bdatファイル)の文字コードを取得したい - SAS

Linuxコマンド: date で◯か月前 / ◯か月後を取得するときの注意