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

proc corrのアウトプットで、相関係数の値やp値の値に基づいて色を変える方法

最近交流させていただいております方から、「膨大な数の変数の相関をみる場合があるのですが、相関係数の値が一定以上、P値の値が一定以下の際に、そこがわかるようにアウトプットに色づけしたい」といった趣旨の質問がありました。

プロシジャのアウトプットをダイレクトにいじるのは、あんまやったことないから無理です~!って逃げるところでしたが、ちょっと頑張ってみました。

確かにproc corrかけると、対象変数の相関行列がでてくるんですが、変数多いと、目が滑って見落としちゃうことあります。

まず

data Q1;
 A=2;B=1;C=2;D=3;E=9;F=9;output;
 A=4;B=2;C=3;D=8;E=2;F=22;output;
 A=6;B=1;C=3;D=2;E=13;F=9;output;
 A=8;B=4;C=6;D=3;E=23;F=1;output;
 A=10;B=5;C=7;D=5;E=8;F=8;output;
run;

適当にデータを作ります。

で、

ods trace on;
proc corr data=Q1;
run;
ods trace off;

とすると










































と、いっぱい出てきます。

今回、いじくりたいのは3つめの相関行列の表です。

ods traceつけて実行したので、ログには各アウトプットの情報がでています。
そこから相関行列に該当するものを探します。
(ods tarce onについて詳しくは




みっけ! そこで、テンプレートの箇所をみます。
このテンプレートこそが、解析結果をアウトプットするためのデザイン情報、スタイルシートみたいなもんなんですね。

そこで、テンプレートを特定したら、次にそのテンプレートの中身を展開して確認します

proc template;
 source Base.Corr.StackedMatrix;
run;

templateプロシジャでsourceの後に、確認したい先ほどのテンプレート名を指定して実行
ログに以下のようなものがでてきます。






















ふむふむ、成程。さっぱりわからん。読めるか、こんなもん。
まあ、GraphTemplateLangage(GTL)やってる方なら知っているかもしれませんが、これはグラフじゃない方ののテンプレートランゲージなんですね。

これをカスタマイズするのか~。まあ頑張って読んでみます。
大切なのは、どこの記述が、アウトプットのどこに紐づいているかを見極めることです。

じっくり見てると、なんとな~く
column (RowName RowLabel) (Matrix) * (Matrix2) * (Matrix3) * (Matrix4);
の箇所が、全体の構造に関係してる気がしませんか?勘で。

さっきのアウトプットと見比べてみると、column(RowName RowLabel)はどうも、縦にA B C D E  F、横にA B C D E Fとなっている、アウトプットの一番外側の部分ではないか?と当たりがつきます(強引)。そうすると、次に(Matrix)とあるものは、もしかして相関係数の行列に対応しているのでは?と推測されます(強引)、じゃあ次の(Matrix2)はP値か!
じゃあ(Matrix3)と(Matrix4)はなんなんだ? あ、そうか、corrプロシジャにはたくさんオプションが付けられる!その指定によっては出現する階層じゃないのか!(もはや、こじつけ)

ということがわかります。まあ、詳しくはods関係をじっくり勉強してください。

そして、もう一つさっきのTemplateプロシジャの出力で重要ななのが、NOTEの部分で、このcorrプロシジャの相関行列をだすテンプレートはSASHELPのTMPLISTって中に格納されているよって部分です。このことを心に留めていてください。


さて、実際にこっからテンプレート改造手術を開始する前に下準備

proc format;
 /*相関係数の色*/
   value rf low--0.7='RED'
            -0.7<--0.4='BLUE'
            -0.4<--0.2 ='GREEN'
            -0.2-<0.2='WHITE'
            0.2-<0.4='GREEN'
            0.4-<0.7='BLUE'
            0.7-<1='RED'
            1='WHITE';
  /*P値の色*/
   value pf low-0.01='RED'
            0.01<-0.05='BLUE'
            0.05<-high='BLACK';
run;

まあそのまんまですね、相関係数の値によって変わるフォーマット、P値によって変わるフォーマットを先んじて作っておきます。

そしたら

proc template;
   edit Base.Corr.StackedMatrix;
      column (RowName RowLabel) (Matrix) * (Matrix2);
      edit matrix;
         cellstyle _val_ as {backgroundcolor=rf.};
       end;
        edit matrix2;
          style={foreground=pf.};
       end;
      end;
run;

これで手術完了です。
 edit Base.Corr.StackedMatrix;は、カスタマイズする元のテンプレート名を指定
column (RowName RowLabel) (Matrix) * (Matrix2);
は、今回はここまでの定義以上は必要ないので、こうしてます
edit matrix;からend;までが、相関係数の部分をいじりますよって意味です。
cellstyle _val_ as {backgroundcolor=rf.}; これはセルの値に基づいて、セルのスタイルを変更してください、背景色はrfフォーマットで定義しますって意味です。
edit matrix2;からも同様で、今度はセル全体ではなく、値の書式のみを変更する書き方です。

そして実行すると、このテンプレートはWORK.templateというところに保存されます。え?SASHELPじゃないの?って思うかもしれませんが、SASHELPのテンプレートをうっかり変な風に変えちゃったら、今後のcorrプロシジャのアウトプット全部変になって大変でしょう?
だからWORKに複製が作られて、そこが改造されるようになってるんです。


ods path work.template(update) sashelp.tmplmst;
ods html file='/folders/myfolders/sample.html';
proc corr data=Q1;
 ods select PearsonCorr;
run;
ods html close;

です。あ、ちなみにfile=の記述は、なぜかUniversityではこれでhtmlつくらないと、僕の環境でうまくいかなかったのでつけてるだけで、本来いらないです。
リスト出力以外ならods pdf;でもods rtf;でもods htmlでもなんでもいいです。

ods path work.template(update) sashelp.tmplmst;
これは、WORKにある、カスタマイズしたテンプレートがあるかを先に見ろよ、あったらそっち使えよ!って命令です。

結果は






















です。相関係数の絶対値が0.7以上ならセルが赤、0.4以上なら青、0.2以上は緑になります。
P値は5%以下なら青字、さらに1%以下なら赤字になります。

カスタマイズしたテンプレートを消す場合
proc template; 
   delete base.corr.stackedmatrix;
run;

でOKです。

詰めSAS6回目_由来するデータセットの情報で処理をする

以下の2つのデータセットを、変数名を共通のものにリネームしつつ縦結合し、なおかつ結合後のデータセットで、もともとどちらのデータセットにあったオブザベーションか判別できるように情報を付与せよといった問題になります。

data Q_1;
 A=1;B=2;output;
 A=3;B=4;output;
run;



data Q_2;
 C=5;D=6;output;
 C=7;D=8;output;
run;






上記の2つのデータセットから、下のデータセットを作ります。








なお、1ステップで行うのが最短で、新規データセットを作成する問題なので
appendプロシジャの採用は今回はおそらく悪手です。


【解法1】
data A_1;
 set Q_1(in=in1 rename=(A=X B=Y))
      Q_2(in=in2 rename=(C=X D=Y))
;
 if in1 then BASE='Q_1';
 if in2 then BASE='Q_2';
run;

inデータセットオプションはmergeステートメントと使って、外部結合(片方のオブザベーションを全て残す)ような処理の際によく使われますが、本来、そういった限定的な使用法ではなく、データセットの帰属にフラグをたてれる優秀なオプションなのでより柔軟に使用されるべきだと思います。


【解法2】
proc sql noprint;
 create table A_2 as
  select A as X,B as Y,'Q_1' as BASE
   from Q_1
    union all
  select C,D,'Q_2' as BASE
   from Q_2;
quit;

この方法で面白いのは、変数名をX,Yに変える処理をQ_1に対してしか行っていないのに後段の
Q_2の変数C、DもX,Yになって縦結合される点です。
これは unionにcorrをつけていないことに起因します。corrをつけると縦結合する際に変数名が同じ物同士をつないでくれますが、つけれなれば、どんな変数名であっても1つ目の変数は1つめの変数と結合されます。定義情報は一番最初のテーブルのものが強制されます。通常はそんなおっかない性質は扱いづらいので unionにはallとcorrをつけます。allを抜くと勝手に重複データを消してきます。
SASのSetステートメントの挙動と同じなのはunion corrで繋いだ場合ということになります。




=================================
おまけ in=は優秀
=================================
たとえば以下のようなデータセットがあったとします。

data GROUPDATA;
 input GROUP $10. SEX $;
 cards;
グループA 男性
グループA 男性
グループA 男性
グループA 女性
グループA 男性
グループA 女性
グループA 男性
グループA 男性
グループA 男性
グループA 女性
グループA 男性
グループB 男性
グループB 女性
グループB 女性
グループB 男性
グループB 女性
グループB 男性
グループB 女性
グループB 男性
グループB 女性
;
run;
























ここでAグループ、Bグループ、全体で見たときの男女の人数をカウントせよという問題があった
とします。










そういった時setステートメントで同じデータセットを縦につないで
一旦オブザベーション数が2倍になってデータが重複したデータセットをつくるコードを書きます。
ただし2つめのデータセットにデータセットオプションでin=を指定し、後にifでin=でたてた変数が
1の場合にグループ情報をダミー変数に置き換えます。
あとはグループ集計すればいいのです。
言葉で説明しにくいので実際にやってみてください、SASっぽいなぁと思わせる処理です。

data GROUPDATA_1;
 set GROUPDATA
      GROUPDATA(in=in1);
   if in1=1 then GROUP='全体';
 run;

proc freq data=GROUPDATA_1 noprint;
  tables GROUP*SEX/out=OUTPUT(drop=percent);
run;