いただいたご質問への回答:stopステートメント abortステートメントの話

問い合わせ用のフォームからご質問いただいたのですが、返信用のメールアドレスに誤りがあるようで 返事ができませんでした。
記事としてご回答します。

質問の要旨は
=================================================================================
setで新しいデータセットを作る際の処理に
setするデータセット中のある変数に数字の「5」が入っていたら、それ以降の行を読み込むのをやめてエラーをだす方法はありますか?


或いは「5」が入っていたら、強制的にSASを終了させたりもできますでしょうか?=================================================================================

一体、どのようなシチュエーションで必要となった処理なのか、なかなかに興味があります。
うまく意図を汲めているかわかりませんが、以下を考えてみました。

まず

data Q1;
 do X=1,6,8,3,5,4,2,9;
  output;
 end;
run;

のようなデータセットあったとします。












そうしたら

data  A1;
 set Q1;
 if X=5 then do;
  put 'ERROR: やばいです。5がありますよ';
  stop;
 end;
run;

とすれば











とログに出てデータセットの中身は








stopステートメントは、その時点でステップを打ち切ります。
あとはSAS忘備録でも紹介されていた(http://sas-boubi.blogspot.jp/2013/12/blog-post_24.html)
ログにオリジナルエラーメッセージを出す方法を使いました。

あるいは

data A2;
 set Q1;
 if X=5 then abort;
run;

としても












abortや%abortはあまり使ったことないのですが、データセットの中身は同様の結果になります。
ログのエラーメッセージはわかりにくですが...。

さらに強制的にSASそのものを閉じさせたい場合は

/*実行注意!!開いているSASが全部閉じちゃいます*/
 data A3;
  set Q1;
  if X=5 then abort abend;
 run;

 とすればOKのはずです



「SAS® 認定プロフェッショナルのための Base Programming for SAS® 9 完全ガイド」のサンプルデータは公開されてます

以前、書籍案内で「SAS® 認定プロフェッショナルのための Base Programming for SAS® 9 完全ガイド」を紹介しましたが、
何人の方からか、本の中で紹介されているコードを実際実行したいが、使用するデータセットがないので実行できずにいて悔しいといったメッセージをいただきました。

この本は米国SASが出している書籍「SAS Certification Prep Guide: Base Programming for SAS 9」の翻訳版で、基本プログラムもデータも同じなので、米国SAS社のHPから入手できます

http://support.sas.com/publishing/cert/index.html

の「Sample Data」をクリックすると
















長いコードがばっとでてきますので




























全部選択してコピーして、SASのエディタにペーストして実行すれば
SASUSERライブラリに、書籍中にでてくる多分全てのサンプルデータが作成されます。

Advancedの方は無いようですが、基本、米国SASが出している書籍には、その書籍を紹介しているSASのページから、サンプルプログラムやデータを落とせることが多いので便利です。


ぶっちゃけた話、中身が気になるけど、買うほどじゃないなぁって本はサンプルプログラム落として
ざーっとみるだけで充分勉強になります。





目に見えない改行コードが邪魔をしてくる話

今、








こういう、どうってことないデータセットがあったとします。
Xは文字型です。

そして、

data A1;
 set Q1;
 Y=input(X,8.);
run;

というなんてことない処理(Xを数値化してYに割り当てる)を実行します。


結果は








え?

見た目は同じなのに2オブザベーション目だけ欠損値です。

ログにも、確かに欠損値が生成されたNoteはでていますが、






引数が無効と言われても、、。といった感じです。

これ、知らないと一生解決できないんじゃないか系のトラブルです。
以前紹介した「背筋が凍る、厄介でおっかない小数点誤差の話」
http://sas-tumesas.blogspot.jp/2014/03/blog-post_14.html
に似てますね。



実は冒頭のデータセットは

data Q1;
length X $10.;
 X='1';output;
 X=cats('0A'X,'1');output;
run;

というコードで生成したものです。

ん?2個目のXで、1にくっつけている'0A'Xってなに?

これ、実は改行コードの一部(ラインフィールド)を指定する意味をもった記述なんです。
通常、こいつと'0D'x(キャリッジリターン)を合わせて、改行をさせます。

こういう意味をもった記号があって(タブ('09'x)とか)、そいつらが往々にして
僕らの大切な時間と精神力を奪っていきます。

対策は簡単で

data A2;
 set Q1;
 Y=input(compress(X,'0A'X || '0D'X),8.);
run;

取り除いてからinputです。

例えば、エクセルからデータを読み込んでデータセットを作る場合なんかによくこの問題が
浮上します。

見栄えをよくするために、結構セル内改行つかったりしていることが多いんですよね。






横方向に重複を取り除く。配列内の変数から重複している値を消す方法

しばらく更新できないか、頻度が落ちると思います。すみません。

最近、迷った処理について

以下のようなデータがあったとします。

data Q1;
ID='001';TERM_1='頭痛';TERM_2='腹痛';TERM_3='頭痛';TERM_4='頭痛';output;
ID='002';TERM_1='下痢';TERM_2='腹痛';TERM_3='下痢';TERM_4='';output;
ID='003';TERM_1='腰痛';TERM_2='';TERM_3='';TERM_4='';output;
ID='004';TERM_1='';TERM_2='骨折';TERM_3='';TERM_4='骨折';output;
run;









ここから、








のようなデータセットを作れと言われたとします。

要は横方向に重複を除いてから連結しろってことで、
変数の数は可変、発生する重複の個数は可変で、どことどこが重複するかも
不明だとします
(必ず連続して2個重複とかなら、配列で要素番号-1を捉える条件式で対応できますね)


いいアイデアがなかったので、もう一端transposeで縦にデータ起こしてから、sortにnodupつけて
重複殺してから、再度、transposeして、と思ったのですが、それもちょっとイマイチだなと思って
以下の方法でやってみました。

data A1;
set Q1;
array AR{*} $ TERM_:;
 do i=1 to dim(AR);
  if AR{i}^='' and whichc(AR{i},of AR{*})<i then AR{i}='';
 end;
 ALLTERM=catx('、',of TERM_:);
run;






となって、IDとALLTERMだけkeepすれば、最初の作るべきデータセット同じになります。

青字の部分がミソで、要するに、自分の値で、自分自身を含む配列を検索して、最初に
見つかった位置番号が自分の要素番号より小さければ、自分の値は既に前の変数で
出現しているので、自分は要らない子なので消えようってことを順番に全変数分やって
生き残った値がユニークな値ってことです。

横方向に重複を取り除くのって、ぱっと思いつかないですね。
他に方法があれば教えてください。
配列は苦手なので、もっといい方法がある気がしてます。

call sortcルーチンにnodupオプションみたいなのがあれば一発解決な気がしますが、、。
追加されないかな






データセットオプションの意図的な空指定

どうってことないことかもしれませんが。

data Q1;
 X=1;Y=2;Z=3;
run;

のデータセットに

data A1(drop= rename=());
 set Q1;
run;

を実行すると、問題なく実行されます。

(drop= rename=())の部分は完全に意味のない空指定として無視されます。

それがどうした?といった感じなんですが、マクロ化する時なんかに
この性質を知っていると書きやすいです。


%macro ma(dr,rn);
 data A1(drop=&dr rename=(&rn));
  set Q1;
 run;
%mend;

とのようなマクロを作った時、
何も操作を加えず、データセットQ1をA1として作成したい場合は

%ma(,)

でOKです。僕はずっと、こけると思ってました。

それで例えば

%ma(X Y,%str(Z=A))

で実行すれば

変数X Yが落ちて、ZがAにリネームされます。


ただし、注意点として

data A2(where=());
 set Q1;
run;

は駄目です、エラーになります。これ、通るようにならないかなぁ。





WEBページのデータ(HTML)を直接SASデータセットにする方法

WEBページのデータ(HTML)を直接SASデータセットにする方法です。

例えば、例えばの話で、実際やったことはない.....?ですが

仕事中にここ1週間の将棋の棋戦の結果を知りたいなって時に、

http://www.shogi.or.jp/kisen/week/kekka.html


















みたいなページを長々と見てたら、てめぇ仕事してないなって即バレなわけです。


なので filenameステートメントでURLをファイル指定して
infileステートメントでとりあえずそのまま読み込みます。


filename KISEN url 'http://www.shogi.or.jp/kisen/week/kekka.html';
       
data A1;
   infile KISEN ;
   input COL $2000. @@;
run;


すると


















のようにWEBページを構成しているHTMLがそのままデータセットになってます。

あとは必要な部分の性質がわかっているなら

data A2;
 set A1;
 where COL contains ('○');
run;

(基本、勝敗がつくと考えて)




















これで、行われた対局と、その結果をぱっと知れます。
正規表現とか駆使すれば、余計なタグを取り除いて綺麗にできます。