SAS プログラムの可視化 - SAS プログラムステップフローチャート生成プログラムの紹介 - 福田裕章 1 ( 1 MSD 株式会社 ) Visualization of SAS programs Hiroaki Fukuda MSD K.K.
要旨 : データステップ及び SGPLOT プロシジャにおける POLYGON/TEXT ステートメントを利用した SAS プログラムステップフローチャートを生成する SAS プログラムを紹介する キーワード :SGPLOT, フローチャート, 可視化 2
背景 一般的なSASプログラムデータ加工 Proc Step データ加工 Proc Step... Proc Lua Data Step 様々なデータハンドリング技術 Proc DS2 Proc SQL フローの可視化が望ましい Hash Object 主流は基本的な Data Step や SQL プロシジャ ハンドリングのために数多のステップが発生 プログラムの把握に一苦労 フローチャート化 SAS プログラムを SAS プログラムで読み込み処理することで プログラムのステップフローチャートを作成する 3
SAS プログラムの判定 SAS プログラムによるプログラムステップ判定 SAS システムによる認識判定 例 : データステップの開始 data で始まっている data の直前が */ や ; で終了している data に続けて空白 + データセット名可能文字列が記載 などなど data, proc, set, merge などのステートメントに対する処理 コメントアウトやクオーテーションの処理 他にも様々な条件や記載方法 ( 改行等 ) の考慮 柔軟なテキスト操作やデータハンドリングが必要 4
プログラムの概要 SAS プログラムの読み込み コメント クオーテーションの処理 各種ステートメントの処理 Data Statement Proc Statement Set Statement Merge Statement SQL の処理 フローの分岐処理 Grouping 処理 = X 座標の決定 出力対象とする Text の選択 Y 座標の決定 アウトプット (Box/Arrow) 用の Dataset 作成 フローチャートの描画 Hash Object を利用 コード処理 分岐処理 ( 座標処理 ) アウトプット処理 Perl Regular Expression を利用 SGPLOT プロシジャを利用 5
テキスト操作の柔軟性 Perl Regular Expression Perl 正規表現の一部を SAS では関数として使用することが可能 パターンマッチにより 複雑な文字処理が可能 コメントアウトの処理 ( 一部 ) * rec2: プログラムコード格納変数 ; *** 先頭行や前行の最後が ; */ で終了している場合 ; rec2 = prxchange('s/(% *.*?; / *.*? * / (^ (?<=[^ w_ ))) *? *.*?;)//', -1, rec2); *** 改行により複数行にまたがっている場合 (/* */); if index(rec2, "/*") then do; asts1fn = 1; cont1fn = 1; rec2 = prxchange('s/ / *.*?//', 1, rec2); end; if index(rec2, "*/") then aste1fn = 1; if cont1fn = 1 then do; if aste1fn ^= 1 then rec2 = ""; else if aste1fn = 1 then do; rec2 = prxchange('s/(^.*? * /)//', 1, rec2); cont1fn = 0; end; end; <prxchange 関数 > (perl-regular-expression, times, source) * 引数の 1 番目が Perl 正規表現で特定の文字列パターンを置換 6
テキスト操作の柔軟性 Perl Regular Expression データステップの処理 ( 一部 : 条件分岐の提示のみ ) *** 以下のパターンに場合分けしてフラグを設定 ; ** 1.data statement が一行内で完結している場合 ; prxmatch('m/;( *)data( +)([ w_])+(.*);/i', rec2) ** 2. 前行の最後が ; */ で終了している場合; prxmatch('m/(; * /)$/', trim(pre_line2)) * 2-1. data で終了している場合( 継続 ); prxmatch('m/^data( *)$/i', trim(rec2)) * 2-2. data が存在する場合( 継続 ); prxmatch('m/^data( *)/i', rec2) * 2-3. 一行内で完結している場合 ; prxmatch('m/^data( +)([ w_])+(.*);/i', rec2) ** 3. 先頭行の場合 ; * 3-1. data で終了している場合( 継続 ); prxmatch('m/^data( *)$/i', trim(rec2)) * 3-2. data +データセット名等で終了している場合 ( 継続 ); prxmatch('m/^data( +)([ w_])+(.*)/i', rec2) * 3-3. 一行内で完結している場合 ; prxmatch('m/^data( +)([ w_])+(.*);/i', rec2) ** 4. その他の場合 ;... <prxmatch 関数 > (perl-regular-expression, source) * 引数の 1 番目が Perl 正規表現で 特定の文字列パターンに該当するかを判定 各パターンを考慮することで データステップの開始かどうかを判定 7
データハンドリングの柔軟性 Hash Object Y 座標の決定方向 X 座標の決定方向 1 2 3 (5) (4) (3) (2) A B C D O (9) (10) (7) Q P 4 (11) (8) X Y X 座標の決定 :1~4 最終ステップを含むグループを支点として決定 フローの上流から分岐を決定 Input/Output の関係から どの分岐先に属するか判定 ( 下プログラム ) Y 座標の決定 :(1)~(11) 下流 ( 最終ステップ ) から上流へ決定 分岐がある場合に複数の Input が同座標になるように決定 (1) E *** X 座標 (group) の決定 ; dcl hash itxtlst(); itxtlst.definekey('itext'); itxtlst.definedata('group'); itxtlst.definedone(); rc1 = itxtlst.check(key: text); ** Object itxtlistに出力テキスト (text) が存在するか確認 ; if rc1 = 0 then rc2 = itxtlst.find(key: text); ** itxtlistに存在すれば groupを取得 ; if group ^=. and (istepseq <= 2) then igroup = group; if igroup > &i. then rc3 = itxtlst.add(key: itext, data: igroup); ** Inputの情報をHashに格納 ; 8
フローチャートの作成 SAS9.4 から SGPLOT プロシジャに POLYGON/TEXT ステートメントが追加された ods graphics / imagemap=on; ** TIP オプション使用に必須 ; proc sgplot data=output noborder noautolegend; ** POLYGON ステートメントによるボックスの描画 ; polygon id=boxid x=box_x y=box_y; ** TEXT ステートメントによるテキストの描画 ; text x=text_x y=text_y text=text / Text を囲う枠線を定義するデータセット Box 由来の変数 : 頂点の座標を定義 textattrs=(size=5) splitchar='.' splitpolicy=splitalways tip = (code); ** SERIES ステートメントによる矢印の描画 ; 矢印を定義するデータセット Arrow 由来の変数 : 始点 終点の座標を定義 series x=arrow_x y=arrow_y / group=arrowid lineattrs=(color=black) arrowheadpos=end arrowheadscale=0.2; ** 軸の設定 ; xaxis display=none min=&xmin. max=&xmax. offsetmin=0 offsetmax=0; yaxis display=none min=&ymin. max=&ymax. offsetmin=0 offsetmax=0; run; 9
結果 1 単純なプログラムの場合 ** Create Data A; data A; set sashelp.class; run; proc sort data = A; by name age; run; ** Create Data B by SQL procedure; proc sql; create table B as select X.*, Y.pop from X inner join (select * from sashelp.demographics) as Y on X.COUNTRY = Y.ISONAME; quit; proc sort data = B out = B; by name age; run; ** Create Data C from A and B; data C; merge A (in = in1) B (in = in2); by name age; if in1 = in2; run; proc print data = C noobs; run; データ C 生成のコードを表示 TIP オプションにより指定した変数の値を表示できる 各ステップのコードを表示するように設定 10
結果 2 実際の解析データセット作成プログラムに適用した場合 例 :AE の解析データセット作成プログラム プロシジャの場合 枠の形状が になるように調整 まとめ 簡単な解析データセット作成プログラムならば フローチャートの作成が可能であった ステップが増大すると 作図の都合上 図形が小さくなるので 分割などを考慮する必要がある マクロ処理やMerge 処理が十分ではないので こうしたステップへの対応が今後の課題である 11
参考 SAS 9.4 コンポーネントオブジェクト : リファレンス第 2 版 http://www.sas.com/offices/asiapacific/japan/service/help/pdf/v94/lec ompobjref.pdf SAS 9.4 関数と CALL ルーチン : リファレンス第 4 版 http://www.sas.com/offices/asiapacific/japan/tools/download.html?url =http://support.sas.com/documentation/cdl_alternate/ja/lefunctionsre f/67960/pdf/default/lefunctionsref.pdf Steven First (2016) Innovative Performance Improvements Through Automated Flowcharts In SAS SAS Global Forum 2016. 12