ラベル NOBS= の投稿を表示しています。 すべての投稿を表示
ラベル NOBS= の投稿を表示しています。 すべての投稿を表示

2016年8月2日火曜日

0オブザベーションの時、1行追加して「該当データなし」みたいな値を入れる方法



サンプルデータ

data DT1;
   length A $30.;
   delete;
run;

           A          



やりたい事

上記のようにデータセットが0オブザベーションだったら、「該当データなし」みたいな値を入れた行を追加したい。

A
  該当データなし 



解決案

(プログラム中の「NOBS=オプション」は正しく動かない状況もあるので、下の各リンク記事も要確認!)

data OUT1;
   length A $30.;
   if _OBS=0 then do;
        A = "該当データなし";
        output;
   end;

   set DT1 nobs=_OBS;
   output;
run;

A
  該当データなし 

0オブザベーション以外の時は「該当データなし」の行は追加されません。


解説

以下リンク記事を読んでいただくと8割がた上記処理の理解につながると思います。

 ・ NOBS=オプションの性質 【オブザベーション数の取得】
 ・ 暗黙のOUTPUTステートメント

補足すると、SETするデータセットが0OBSの場合、SETステートメントの後にどんな処理を入れても作成されるデータセットも0OBSとなってしまいます。(データステップの性質上)

なので、0OBSにされる前に、先に青字のプログラムで「該当データなし」の行をOUTPUTしてから、最後にSETステートメントを実行するようにしています。 なんかパズルみたいですね。



その他

NOBSの注意事項
行削除の落とし穴


2016年8月1日月曜日

NOBS=オプションの性質 【オブザベーション数の取得】




「NOBS=」はSETステートメントで使えるオプションです。まず構文から見ていきましょう。




構文

SET  データセット  NOBS = 適当な一時変数名 ;

  • SETしたデータセットのオブザベーション数を一時変数に格納
  • 一時変数なので、作成したデータセットには残らない
  • WHERE等の文があっても、抽出前のオブザベーション数しか取得できない
  • SASビューとか、TAPE, XMLのようなシーケンシャルエンジンとか、特殊なデータではオブザベーション数の取得に対応していない場合があるので注意
  • その他、落とし穴もあるので、下部の方に貼った注意点の記事リンクも要確認!




* サンプルデータ ;
data DT1;
   do X=1 to 3;
       output;
   end;
run;

* オブザベーション数の取得 ;
data DT2;
   set DT1 nobs=_OBS;
   OBS = _OBS;
run;

  X   
 OBS  
   1    3
   2    3
   3    3





NOBS=オプションの性質


NOBS=オプションは、データステップ内の他のプログラムが実行される前に働きます。
以下のプログラムをご覧ください。


data _null_;
   put _OBS;
   stop;
   set DT1 nobs=_OBS;
run;

ログ
3


set DT1 nobs=_OBS;」で一時変数_OBSにオブザベーション数を格納しています。
その前の 「put _OBS;」で、_OBSの値をログにputしてから、「stop;」で、データステップをstopしています。


stopしてるので、その下の「set DT1 nobs=_OBS;」は実行されないんですが、NOBS=オプションだけは他のプログラムが実行される前に既に働いています。

つまり、「SETステートメントは実行しないけど、オブザベーション数だけ先に取ってくる」 という事をやってのけています。




NOBS=の注意点

行削除の落とし穴
http://sas-boubi.blogspot.jp/2014/05/blog-post_20.html




NOBS=の性質を利用したテクニック

【訂正追補】SASデータセットのオブザベーション数をマクロ変数に格納する方法_call symput
http://sas-tumesas.blogspot.jp/2013/10/sascall-symput.html(データステップ100万回)


データステップ内で、色々なデータセットのオブザベーション数を取得する
http://sas-boubi.blogspot.jp/2015/06/blog-post_26.html



2016年3月29日火曜日

オブザベーション数を取得してマクロ変数に格納する方法 【まとめ】


ぱっと思いつく限りあげてみました。他に面白い方法があれば教えてほしいです。


*** サンプルデータ ;
data DT1;
  do i=1 to 100;
    output;
  end;
run;


① SQL INTO
proc sql noprint;
  select count(*) into :OBS1 trimmed
  from DT1;
quit;

%put &OBS1;


② NOBS
data _NULL_;
  if 0 then set DT1(drop=_ALL_)  nobs=NOBS;
  call symputx("OBS2", NOBS);
  stop;
run;

%put &OBS2;

参照…http://sas-boubi.blogspot.jp/2015/06/blog-post_26.html(過去記事)
※ 注意事項があるので過去記事参照


③ SQL DICTIONARY
proc sql noprint;
  select NLOBS into :OBS3
  from DICTIONARY.TABLES
  /* ライブラリ名とデータセット名を大文字で指定する */
  where LIBNAME="WORK" and MEMNAME="DT1";
quit;

%put &OBS3;

参照…http://sas-boubi.blogspot.jp/2015/08/dictionary.html(過去記事)


④ OPEN, ATTRN関数
data _NULL_;
  DSID = open("DT1");
  OBS  = attrn(DSID, "NLOBSF");
  call symputx("OBS4",OBS);
run;

%put &OBS4;

まず、OPEN関数でデータセットを開く(戻り値としてデータセット識別子というIDが返される)
次に、ATTRN( データセット識別子, "NLOBSF" ) でオブザベーション数を取得しています。


⑤ HASH
data _NULL_;
  if 0 then set DT1;
  dcl hash hs(dataset :"DT1", multidata:"y");
  hs.definekey("i");
  hs.definedone();
  call symputx("OBS5", hs.num_items);
  stop;
run;

%put &OBS5;

参照…http://sas-tumesas.blogspot.jp/2014/07/clearnumitemsdeleteremove.html(データステップ100万回)

ポイント
multidata:"y" で重複キーも保持するようにしています(ハッシュオブジェクトはデフォルトだと、キーが重複するレコードに対して、最初のレコードしか保持しないので)


⑥ SYSNOBS
参照…http://sas-boubi.blogspot.jp/2014/01/blog-post_8902.html(過去記事)


⑦ SQLOBS
参照…http://sas-boubi.blogspot.jp/2014/09/blog-post_8.html(過去記事)

2015年6月26日金曜日

データステップ内で、色々なデータセットのオブザベーション数を取得する


(注意!)
今回の方法で正しくobs数を取得できないケースもあるので、記事の最後に貼っているリンク記事も参照下さい。



まずは適当なサンプルデータを用意。

* サンプルデータ ;
data DT1;
   do i=1 to 10;
      output;
   end;
run;

data DT2;
   do i=1 to 20;
      output;
   end;
run;

data DT3;
   A="aa";  output;
   A="bb";  output;
   A="cc";  output;
run;

DT1 は10obs、DT2 は20obsを持つデータセットです。



ここで、DT3を読み込むときに、DT1とDT2のobs数も取得したいとします。

* 各データセットのOBS数を取得 ;
data OUT1;

   set DT3;

   if 0 then set DT1(drop=_ALL_)  nobs= _OBS1;
   if 0 then set DT2(drop=_ALL_)  nobs= _OBS2;

   DT1_OBS = _OBS1;
   DT2_OBS = _OBS2;

run;

  A  
 DT1_OBS 
 DT2_OBS 
  aa 
  10  
  20 
  bb
  10  
  20 
  cc
  10  
  20 


解説

プログラム青字部分がポイントです。
if 0 then」 の 「0」 は 「false」 の意味になり、then以降の 「set DT1(drop=_ALL_) ・・・」 の部分は実行されません。
。。のはずですが、たとえ実行されなくてもデータセット名の指定があると、コンパイル時にそのデータセットの定義情報だけが読み込まれます。

この性質を利用し、
・まず 「if 0 then set DT1」 でDT1の定義情報だけを読み込みます。
・変数定義も読み込まれてしまうので 「DT1(drop=_ALL_)」 で読み込まれる全変数をdropする。
・「nobs = 適当な一時変数名」で、定義情報に格納されたobs数を一時変数に格納。
といった流れです。


※ 以下記事の通り、特殊な処理をしてる場合は、正しくobs数を取得できないのでご注意ください。
行削除の落とし穴


2014年5月20日火曜日

行削除の落とし穴




📝 本題に入る前に。。

行削除を行うステートメントは環境によって挙動が異なるため、今回の記事で示した結果と、各環境の実行結果が異なる場合があります。



行(オブザベーション)を削除する方法はいくつかありますが、その方法によっては注意が必要です。


サンプルデータ
data DT1 DT2 DT3;
   do A=10 to 30 by 10;
       output;
   end;
run;

データセットDT1~DT3

 A 
  1  10 
  2  20 
  3  30 



まずは色々な方法で行を削除してみる。
* ①DELETEステートメント ;
data DT1;
   set DT1;
   if A=10 then delete;
run;

* ②MODIFY,REMOVEステートメント ;
data DT2;
   modify DT2;
   if A=10 then remove;
run;

* ③SQLのDELETE ;
proc sql;
   delete from DT3 where A=10;
quit;


データセット
DT1

 A 
  1 20 
  2 30
DT2

 A 
  2 20 
  3 30
DT3

 A 
  2 20 
  3 30


出来たデータセットを開いてみると上記のような感じです。いっけん同じに見えるけど、注目してほしいのはデータセットの左側に表示される行番号。
DT2とDT3は「2」から始まってますね。

1行目が削除されても行番号が削除前と変わっていないのです。
このように使用できる行番号が歯抜け状態になってしまうことでちょっとした問題を起こす場合があります。




問題を起こすケース


行削除後の行数取得。
data _null_;
   set DT2 nobs=NOBS;
   put "行数= " NOBS;
   stop;
run;

ログ
行数= 3

NOBS=を使って行数を取得しログに出力しています。
本来は「行数= 2」となるはずですよね。


POINT=を使った行の読み込み。
data DT4;
   do X=1 to NOBS;
      set DT2 nobs=NOBS point=X;
      output;
   end;
   stop;
run;

データセットDT4

 A 
  1 . 
  2 20 
  3 30 

POINT=で読み込む行番号を変数Xの値によって指定してます。
結果を見ると、1行目が欠測値になってズレちゃってますね。



対策

もしSQLのDELETEやREMOVEステートメントで行を削除してたら、、、以下のようにSETし直せばOK。

data DT2;
   set DT2;
run;


data _null_;
   set DT2 nobs=NOBS;
   put "行数= " NOBS;
   stop;
run;

ログ
行数= 2