詰めSAS1回目_全変数全obsで最大の値をとる

詰めSASの1回目のテーマは、データセット中の最大の値を1変数1obsのデータセットに格納する最善手を考えたいと思います。1手?詰めです。

まず、問いの内容は

data Q1;
input X Y Z;
cards;
1 4 3
2 9 8
7 6 5
;
run;







のデータセットから最大の値、この場合、Yの2obs目の9という値を
変数Mのみの新しいデータセットに格納するという目的です。

目的局面図は





です。


以下、解法です。

【解法1】
data A1;
 set Q1 end=eof;
 retain M;
 if max(X,Y,Z)>M then M=max(X,Y,Z);
 if eof;
 keep M;
run;

最大の値をだす場合に、第一感で思い浮かぶのはproc univariateやmeans等の
利用かもしれませんが、その場合は変数ごとの最大をだした後にデータステップで
その中からの最大をだすことになり2ステップになってしまうと思います。

なので、データステップ1回でやっつけたいのですが、SASのmax関数は横(行)方向の最大値
をとる関数なので、そこで出した値を次のobsに持ち込まないといけません。
なのでretainを使って、持ち越し、endオプションで最終obsだけ残します。

【解法2】
proc sql noprint;
 create table A2 as
  select max(M) as M
   from 
  (select X as M from Q1
    union
   select Y as M from Q1
    union
   select Z as M from Q1)
;
quit;

SQL内でmax関数は1変数内を縦にみて最大値を返すので、じゃあ全部の変数を縦に
つないでからかけてやればいいんじゃないかと思って書いてみると
思ったより頭悪い感じのコードになりました。また、サブクエリを使うと、あまり一手といえなくなって
しまいますが。これならサブクエリ内でX、Y、Zで最大をとってからCASE文で比較して最大を
とる方がスマートだったかも。

【解法3】
data A3;
 obs1=1;
 obs2=2;
 obs3=3;
  set Q1(rename=(X=X1 Y=Y1 Z=Z1)) point=obs1;
  set Q1(rename=(X=X2 Y=Y2 Z=Z2)) point=obs2;
  set Q1(rename=(X=X3 Y=Y3 Z=Z3)) point=obs3;
   M=max(of X1--Z3);
  keep M;
  output;
 stop;
 run;

これは悪ふざけです。横に最大を返すなら、全部横にしてから、かければ
それで決着という方向で書きました。

1回目はここまで。


====================================================
後日、コメントをいただいて追記
====================================================
SQLでの記述について、突っ込みをいれていただきました。
以下のコードで詰みですね!スマート!!
思いつきもしませんでした!

標準SQLのmax関数は引数が1つなのですが、複数の引数を指定した場合
SASはSQLプロシジャ内でもSASのMAX関数と認識するそうです。
奥が深い、、

proc sql;
create table A4 as
select max(max(X,Y,Z)) as M
from Q1;
quit;






9 件のコメント:

  1. こんにちは。

    またまた過去記事からすみません。
    ↓以下の解法はどうでしょうか?
    実はSQLでも横方向のMAXを求められたりします。
    ご存知でしたらすみません。

    proc sql;
    create table A4 as
    select max(max(X,Y,Z)) as M
    from Q1;
    quit;

    返信削除
    返信
    1. ふと思ったんですが、標準SQLでのMAX関数の引数って1だと思うんですね。
      てことは、max(max(X,Y,Z)) のmax(X,Y,Z)の部分はSAS関数のmaxを利用しているってことなんでしょうか??
      SAS関数とSQLで重複している関数の場合、入れ子にすると、下層の関数はSAS関数での働きをして、最上層はSQL関数として解釈されたりするんでしょうか??

      削除
    2. おそらく、MAX関数で引数を複数指定するとSASのMAX関数と解釈するんだと思います。

      以下のプログラムを実行すると、普通に動きますし。

      data TEST;
      input A B C;
      cards;
      1 1 1
      2 2 2
      3 3 3
      ;
      run;

      proc sql;
      select sum(A,B,C) as D
      from TEST;
      quit;

      SASって本当にいいとこ取りしてますよね。

      削除
    3. あぁ、そうか、そういうことか~。動くのか、確認し忘れました。
      いいとこ取りですね、闇鍋状態でもあると思いますが。

      いっつも有難うございます

      削除
  2. や、やられました。詰まされました。
    完全にご存じなかったです。
    なんか書いてて、違和感あったんですよね、、。

    第1回目から見落としてました~。

    精進します。

    でも、ほんといつも読んでいただいてて、有難うございます。





    返信削除
  3. ちなみに、このブログに感化されてわたしもSASブログ作っちゃいました。
    さっそくネタ切れ&年末年始の激務で更新が出来なくなりそうですが。。

    1年に数回、たまーに更新できたらって感じなので、気が向いた時に見に来てください。
    真似した感じになってすみません。。

    http://sas-boubi.blogspot.jp/

    返信削除
  4. [解法1] とほとんど変わりません。
    max関数の中でも_numeric_が使えました。

    data A1(keep=M);
    set Q1 end=EOF;
    retain M;
    M=max(of M _numeric_);
    if EOF;
    run;

    返信削除
  5. すみません。 上で、
    M=max(of M _numeric_); は
    M=max(of _numeric_); でOkでした。

    返信削除
    返信
    1. 有難うございます!
      そうですね、この場合of指定の方が綺麗ですね。
      全ての変数が数値型であることが分かっていれば
      M=max(of _ALL_);でもOKですね。
      或いはM=max(of X--M);も可ですね。

      削除