2017年5月26日金曜日

My Favorite SAS Functions (5) COALESCE / COALESCEC関数


第5回目は、COALESCE / COALESCEC関数。
お気に入り関数トップ3のうちのひとつです(あと2つは WHICHN、CHOOSEN)

この関数は「引数のうち最初にNULL以外で登場する値を返す」という機能を持っています。


基本的な構文や機能は以下記事で紹介済みなので、そちらをご覧ください。
http://sas-boubi.blogspot.jp/2016/04/coalesce.html

データステップ100万回でも特集されてます。
http://sas-tumesas.blogspot.jp/2013/09/sas3null.html





上の過去記事でさんざん例を紹介済みな感じですが、あらためて。
以下X1~X3の中から最初にNULL以外で登場する値を返したいとします。

  X1  
  X2  
  X3  
   

  aa  bb  aa  



以下、COALESCEC関数を使わない場合(Before)と、使う場合(After)。

Before
  length Y $2.;
         if X1^="" then Y=X1;
  else if X2^="" then Y=X2;
  else if X3^="" then Y=X3;

After
  length Y $2.;
  Y = coalescec( X1,X2,X3 );


いいですね~このスッキリ感がたまらないですね。

ちなみにCOALESCE関数あるあるだと思うんですが、読み方が最初よく分からなくて、綴りをいちいち調べてた時期がありました。

コアレスと読むそうです。
上にリンク貼ったSASYAMAさんの記事でもコールエッセって読んでたってお話しがありますね。
私はコアレスシって読んでました。

2017年5月23日火曜日

REPORTプロシジャ入門10:数値変数の落とし穴



前提知識として、まず以下リンク記事をご覧ください。
REPORTプロシジャ入門4:集計【ANALYSIS】




では、落とし穴の例を見ていきましょう。


落とし穴の例

まず、データセットSASHELP.CLASS の NAME, AGE をREPORTプロシジャで出力してみます。

* 例① ;
proc report data=SASHELP.CLASS nowd;
   column NAME AGE;
   define NAME / "名前";
   define AGE  / "年齢";
run;



まぁ、これは特におかしなところはないですね。
では以下のように年齢だけ出力してみるとどうでしょうか?

* 例② ;
proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / "年齢";
run;


「あれ?1行しか出力されていないうえ、年齢「253」てなんだよ!」って感じですよね。



解説

実は、REPORTプロシジャに指定した ”数値変数” は、以下青字のように「analysis sum」オプションをSASが裏で勝手につけて実行しています。

proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / analysis sum "年齢";
run;

つまり、AGEを合計して「253」という出力になってしまったわけですね。


以下のように「display」オプションを明示的につければ、この勝手な挙動を制御できます。
proc report data=SASHELP.CLASS nowd;
   column AGE;
   define AGE  / display "年齢";
run;




ちなみに最初の例①の場合は、SASが裏で以下青字のように判断して実行します。

proc report data=SASHELP.CLASS nowd;
   column NAME AGE;
   define NAME / display "名前";
   define AGE    / analysis sum "年齢";
run;

文字変数の場合は特にこちらで明示しない場合「display」が勝手につくわけです。

つまり挙動として、数値変数 AGE だけだと合計してしまうけど、文字変数 NAME を「display」オプションでそのまま表示するようにしているから、AGE も合計されなくて済んでるっていう仕組みです。



9.特定セルの書式設定【CALL DEFINE】
10:数値変数の落とし穴

2017年5月20日土曜日

My Favorite SAS Functions (4) CHOOSEN / CHOOSEC関数


第4回目は、CHOOSEN / CHOOSEC関数。
これもいい関数ですよ!



構文


    CHOOSEN( Y , X1 , X2 , X3 , … )


・Y番目のXの値を返す。
・第2引数以降に数値型の変数または値を指定する場合はCHOOSEN関数を用いる。
・第2引数以降に文字型の変数または値を指定する場合はCHOOSEC関数を用いる。





以下のように、X1~X3のうち、Y番目の値を取得したいとします。。

  X1  
  X2  
  X3  
  Y  
  XVAL  
  aa    bb  cc  2     bb


以下、CHOOSEC関数を使わない場合(Before)と、使う場合(After)。

Before
  length XVAL $2.;
  if Y = 1 then XVAL=X1;
  if Y = 2 then XVAL=X2;
  if Y = 3 then XVAL=X3;


After
  length XVAL $2.;
  XVAL = choosec( Y ,X1,X2,X3 );



こんな感じでスッキリとした文になるんでよく使います。今日も使いました。


他の便利な使い方を過去記事でも紹介してるので是非見てくださいね。
http://sas-boubi.blogspot.jp/2014/03/12_25.html

2017年5月15日月曜日

My Favorite SAS Functions (3) WHICHN / WHICHC関数


第3回目は、一番お気に入りの WHICHN / WHICHC関数です。
お気に入りすぎて、WHICHN関数使ってる夢みたことあります。



構文


    WHICHN( Y , X1 , X2 , X3 … )


・Yと同じ値がXの何番目に初登場するか返す。
・同じ値が無い場合は、0を返す。
・引数に数値型の変数または値を指定する場合はWHICHN関数を用いる。
・引数に文字型の変数または値を指定する場合はWHICHC関数を用いる。





以下のように、Y の値が X1~X3 の何個目と同じか知りたいとします。

  Y  
  X1  
  X2  
  X3  
  XNUM  
  bb    aa  bb  cc     2


以下、WHICHC関数を使わない場合(Before)と、使う場合(After)。

Before
  if Y = X1 then XNUM=1;
  if Y = X2 then XNUM=2;
  if Y = X3 then XNUM=3;


After
  XNUM = whichc( Y ,X1,X2,X3 );



この関数のお気に入りポイントは応用範囲がすごく広いところです。
過去記事でもとりあげまくってるので、是非読んでみてください。

http://sas-boubi.blogspot.jp/2017/04/blog-post.html

2017年5月11日木曜日

My Favorite SAS Functions (2) CATX関数


第2回目は、CATX関数。
この関数は「文字列同士を区切り記号付きで連結する」という機能を持っています。

基本的な構文や機能は以下記事で紹介済みなので、そちらをご覧ください。
http://sas-boubi.blogspot.jp/2015/11/catxcatq.html


もうほんと、この関数の登場は、待ってましたという感じで、ある処理において大変使い勝手が良いです。






例えば、以下X1~X4までの変数値を連結してYのような文字列を作りたいとします。

  X1  
  X2  
  X3  
  X4  
   
  aa      bb  cc  aa,bb,cc 


今までは、以下Beforeのようなメンドクサイ書き方をする必要ありました。あー面倒だなーって言いながら書いてました。
それがAfterのようにCATX関数を使えば超スッキリと短い文で書けてしまいます。

Before
  length Y $20.;
  array AR(*) X1-X4;
  do i=1 to dim(AR);
     if AR(i)^="" then do;
        if Y = "" then Y=AR(i);
        else Y = trim(left(Y)) || "," || trim(left(AR(i)));
     end;
  end;


After
  length Y $20.;
  Y = catx( "," ,X1,X2,X3,X4 );


今でこそ当たり前につかってますが、知ったときは感動しましたよ。

他にも以下記事のように他の事にも使えそうなので、アイディアあったらぜひ教えてください。
複数の変数から、欠損値以外の値を左にシフトしたい。

2017年5月9日火曜日

My Favorite SAS Functions (1) CATS関数


SASユーザー総会のポスター展示でタイトルのようなのを出そうかなと思ってます。

内容としては、個人的にお気に入りかつ使いこなすと便利な関数を紹介する感じにしたいと思います。
まずは一番ヘビーに使うCATS関数から。



構文


    CATS( 変数1, 変数2, … )


指定した変数または値を結合する。
(変数または値の両脇の半角スペースは取り除いたうえで結合されます。)





今まで文字を結合する時は、以下Beforeのような書き方が定着しています。
それがCATS関数を使えば超スッキリと短い文で書けてしまいます。

Before
  length Y $20.;
  Y = trim(left(X1)) || trim(left(X2)) || trim(left(X3));


After
  length Y $20.;
  Y = cats(X1,X2,X3);





また、CATS関数にはもう1個便利な機能があります。SASYAMAさんが過去に紹介されてる以下を読んでください。
http://sas-tumesas.blogspot.jp/2015/06/cat.html

CATS関数に指定した変数が数値型の場合、BESTフォーマットを当てて文字値にしてくれるという機能を利用した小技ですね。
整数値を文字変換したい場合に使えます。

なので例えば「N=10」みたいな感じでN数を表す文字列を作りたい場合、以下Beforeのように書いていたところをAfterのように書けてしまいます。

Before
  length Y $20.;
  Y = "N=" || left(put(X,best.));


After
  length Y $20.;
  Y = cats("N=", X);


2017年5月7日日曜日

文字列の検索いろいろ:INDEX関数編



文字列の検索に使えるINDEX系の関数を紹介。



INDEX、INDEXC、INDEXW関数

シングルバイト(半角の英数など)の文字を対象とする場合、上記3つの関数を状況によって使い分ける。


例を見てみましょう。

data DT1;
     A  = "abc,def,ghi" ;
     B  = index( A , "bc" );
     C  = indexc( A , "ae" );
     D  = indexw( A , "def" , "," );
run;
  A  
  B  
  C  
   
  abc,def,ghi    2  1  5

解説
INDEX( A , "bc")
第2引数の "bc" という文字列が変数Aの何バイト目に見つかったかを返す。
(見つからなかった場合は0を返す。)

INDEXC( A , "ae" )
第2引数の "ae"を一字ずつ分解し、"a"または"e"という文字が変数Aの何バイト目に見つかったかを返す。
(見つからなかった場合は0を返す。)

INDEXW( A , "def" , ",")
第3引数にカンマ「","」を指定しているので、変数Aはカンマ区切りで単語が格納されていると解釈されます。
つまり変数Aの「abc,def,ghi」は「abc」「def」「ghi」という3つの単語があると解釈される。
そしてこの3つの単語のうち、第2引数の「def」と完全一致する単語が5バイト目に見つかったことを表しています。

注意点
日本語などの文字を含む場合は、以下記事の通りうまく動作しないのでご注意ください。
関数の落とし穴:5C問題


KINDEX、KINDEXC関数

マルチバイト(日本語などの全角文字など)を含む文字を対象とする場合、頭に”K”がつく上記2つの関数を使います。

data DT2;
  A = "あいうえお";
  B = kindex(A,"うえ");
  C = kindexc(A,"あお");
run;
  A  
  B  
  C  
  あいうえお    3  1

解説
KINDEX( A , "うえ")
第2引数の "うえ" という文字列が変数Aの何文字目に見つかったかを返す。
(見つからなかった場合は0を返す。)

KINDEXC( A , "あお" )
第2引数の "あお"を一字ずつ分解し、"あ"または"お"という文字が変数Aの何文字目に見つかったかを返す。
(見つからなかった場合は0を返す。)


重要なポイント
頭に"K"の付く関数とそうでない関数の違いとして、、
INDEX系関数は何バイト目に見つかったかを返すのに対し、
KINDEX系関数は何文字目に見つかったかを返します。


覚え方
種類いっぱいあって覚えらんないですよね。一応私の覚え方ですが、

・INDEXC の ”C” は Character(一字)のC?
・INDEXWの ”W” は Word (単語)のW?

検索方法を表しているんでしょうかね。
CとWの略は私がそう思ってるだけで実際のとこは分かりません。