2019年12月14日土曜日

[KCHARLIST関数] 「アルファベット」や「数字」などの特定の文字列を返す





SAS9.4M5から追加になった「KCHARLIST関数」がいい感じです。


例1

data test;
   length x $500.;
   x = kcharlist("U");
run;



KCHARLIST関数で指定した「"U"」は「大文字のアルファベット」を意味しています。
ご覧の通り、戻り値として大文字のアルファベットが返されました。



このように特定の種類の文字をリストとして取得することができます。
「"U"」の他に以下なども指定可能です(一部抜粋)

  • "A"  =  大文字と小文字のアルファベット
  • "L"  =  小文字のアルファベット
  • "U"  =  大文字のアルファベット
  • ”D”  =  数字
  • ”F”  =  SAS名(変数名やデータセット名など)で有効な開始文字
...などなど



2019年12月6日金曜日

[SGプロシジャ] スタイル属性の組み合わせ方法を設定する





SAS9.4で追加になった「ODS GRAPHICS の ATTRPRIORITY=オプション」をご紹介します。


この「ATTRPRIORITY=オプション」は、SGプロシジャでの「スタイル属性の組み合わせ方法」を設定することができます。
ていわれても意味不明かもしれないんで、とりあえず例を見てみましょうか。





「ATTRPRIORITY=オプション」の例


ATTRPRIORITY=COLOR

ods graphics / attrpriority=color;

proc sgplot data=sashelp.class;
    styleattrs datacontrastcolors=(blue orangedatasymbols=(circlefilled starfilled) ;
    scatter x=height y=weight / group=sex markerattrs=(size=12pt);
run;




  • 変数SEXをグループ変数として、シンボルを分けています。
  • 今回は説明しやすくするため、STYLEATTRSステートメントを使って、以下のスタイル属性を明示的に設定しています。
    • シンボルカラーを「BLUE」と「ORANGE」
    • シンボルを「円」と「星」


このスタイル属性に対して「ATTRPRIORITY=COLOR」は以下のイメージでグループごとの「スタイル属性の組み合わせ」を作ります。













1つ目のグループ「BLUE」と「円」の組み合わせ
2つ目のグループ「ORANGE」と「円」の組み合わせ
3つ目のグループ「BLUE」と「星」の組み合わせ
4つ目のグループ「ORANGE」と「星」の組み合わせ

というようにカラーを循環させて組み合わせていきます。





ATTRPRIORITY=NONE

ods graphics / attrpriority=none;

proc sgplot data=sashelp.class;
    styleattrs datacontrastcolors=(blue orangedatasymbols=(circlefilled starfilled) ;
    scatter x=height y=weight / group=sex markerattrs=(size=12pt);
run;



「ATTRPRIORITY=NONE」は以下のようなイメージです。



1つ目のグループ「BLUE」と「円」の組み合わせ
2つ目のグループ「ORANGE」と「星」の組み合わせ

というようにすべてのスタイル属性をグループごとに循環させていきます。





長所と短所



  • 「ATTRPRIORITY=NONE」とした方が見やすいグラフになりやすい

さきほどの「ATTRPRIORITY=COLOR」の例では、グループごとに「色違いの同じシンボル(円)」がPLOTされているのに対して、「ATTRPRIORITY=NONE」の例では、グループごとに「色もシンボルも異なる」PLOTができるので、当然見やすくなるわけです。



  • 「ATTRPRIORITY=COLOR」の方が、組み合わせを多く作れる

記事の最初に示した例では、2つの「シンボル」と2つの「色」をスタイル属性として定義しました。
これに対して「ATTRPRIORITY=COLOR」では4つの組み合わせが作れるのに対して、「ATTRPRIORITY=NONE」では2つしか作れません。


なにが言いたいかというと、たとえば以下の例をご覧ください。

ods graphics / attrpriority=none;

proc sgplot data=sashelp.class;
    styleattrs datasymbols=(circlefilled starfilled) datacontrastcolors=(blue orange);
    scatter x=height y=weight / group=age markerattrs=(size=12pt);
run;



変数AGEをグループ変数として、シンボルを分けていますが、異なるグループにも関わらず、同じシンボルとカラーが割り当てられてしまいました。


これは、スタイル属性が循環して使われるためです。
(たとえばカラー属性だと「BLUE」→「ORANGE」→「BLUE」→「ORANGE」という感じで、設定されている色を使い切ると循環して同じ色が使われる)

この循環は「ATTRPRIORITY=COLOR / NONE」どちらも起こり得ますが、使える組み合わせが少ないと、こういった不具合を起こしていしまいやすいですね。


2019年11月28日木曜日

[SGPLOT] BY値ごとにグラフを作成する際、軸やシンボルなどをグラフ間で揃えたい






これは SGPLOT をよく使用する方なら一度は困るところではないでしょうか?
まずは、以下の失敗例をご覧ください。



失敗例

/* Sample Data */
proc sort data=sashelp.class (obs=5) out=class;
    by age;
run;

/* BY値ごとにグラフを作成 */
ods graphics / height=400 width=400;

proc sgplot data=class;
    scatter x=height y=weight / group=sex markerattrs=(symbol=circlefilled);
    by age;
run;




「BYステートメント」によって、変数「AGE」の値ごとにグラフを作成しています。
また「GROUP=オプション」によって、変数「SEX」の値ごとにシンボルカラーを変えています。



ここで気になるのが、、

  • X軸とY軸の目盛がグラフ間で異なっている。
  • シンボルの色がグラフ間で異なっている(SEX=Fのシンボルが、AGE=13の時は青、AGE=14の時は赤になっている)



そうなんですよ、、BY値ごとにグラフを作成すると、軸やシンボルはグラフ間で統一してくれません。
でも解決方法は簡単!



成功例

proc sgplot data=class uniform=all;
    scatter x=height y=weight / group=sex markerattrs=(symbol=circlefilled);
    by age;
run;




UNIFORM=オプション」を指定するだけ!
このオプションは「BY値ごとに作成したグラフのどこを統一させたいか」を設定します。
設定値には以下があります。



UNIFORM=

 設定値 設定内容 
SCALEX軸を統一 and Y軸を統一
XSCALEX軸を統一
YSCALEY軸を統一
GROUP「GROUP=オプションに指定した変数の値ごとにシンボルや線種などを統一
XSCALEGROUP「XSCALE」と「GROUP」の両方を設定
YSCALEGROUP「YSCALE」と「GROUP」の両方を設定
ALL上記のすべてを統一



2019年11月20日水曜日

外部ファイルの属性情報(更新日時やファイルサイズなど)を取得する方法 (FOPEN関数編)




※今回使用する「FOPEN関数」を使用すると「SASが裏で対象のファイルを開く」点にご注意ください。
開いてる間はSAS以外から編集が出来ないなども起こるかもしれません。




では以下 SAS Ondemand for Academics 上に配置したファイルの属性情報を取得してみます。









filename test 'ファイルのパス/mysas/sakura1.jpg';

data out1;
     /* ファイルを開く */
     fid = fopen( 'test' );

     /* ファイル属性を取得 */
     length name $50. info $1000.;

     do  i = 1 to foptnum( fid );
          name = foptname( fid, i );
          info = finfo( fid, name );
          output;
     end;

     /* ファイルを閉じる */
     rc = fclose( fid );

     keep name info i;
run;


※ 取得される属性情報は、環境や言語設定などによって異なります。
色々な環境で実行する可能性がある場合は、ご注意ください。







解説


FOPEN関数でファイルを開きます。

 FOPEN( "開きたいファイルが割り当てられたファイル参照名" )

戻り値として、開いたファイルの識別番号が返されるので、その番号を変数FIDに入れてます。
この識別番号は、以降の処理で使います。



FOPTNUM関数でファイルの属性数を取得できます。

 FOPTNUM( ファイルの識別番号 )

ここで、得られた属性数だけDOループをまわして、以下の関数で全ての属性値を取得しています。



FOPTNAME関数でファイル属性名を取得できます。("作成日"や"更新日"といった属性名の部分)

 FOPTNAME( ファイルの識別番号 , 属性番号 )



FINFO関数でファイル属性値を取得できます。

 FINFO( ファイルの識別番号 , ファイル属性名 )



FCLOSE関数でファイルを閉じます。

 FCLOSE( ファイルの識別番号 )


2019年11月10日日曜日

ライブラリ内の全データセットから、指定したデータセットだけ残して全て削除する





PROC DATASETS の「SAVEステートメント」でタイトルにある通りのことが出来ます。
あまり知られていない機能なので、覚えておくと便利です。



以下では、WORKのDT1~DT5のうち、DT1だけ残して全部削除しています。

data DT1 DT2 DT3 DT4 DT5;
run;


proc datasets lib=WORK nolist memtype=data;
    save DT1;
quit;



データセットだけでなくビューも含めたい場合は「MEMTYPE=」に「VIEW」を追記すればOK

proc datasets lib=WORK nolist memtype=(data view);
    save DT1;
quit;



2019年11月7日木曜日

SASデータセットを削除するDATASETSプロシジャ






データセットを削除する方法1

PROC  DATASETS  LIB=ライブラリ名   MEMTYPE=DATA  NOLIST;
     DELETE  データセット名1  データセット名2 ・・・ ;
QUIT;

  • 「DELETEステートメント」に削除したいデータセットを列挙します。



proc datasets lib=work memtype=data nolist;
  delete dt1 dt2 dt3;
quit;






データセットを削除する方法2  (注意事項あり)

PROC  DATASETS  LIB=ライブラリ名  MEMTYPE=DATA  KILL  NOLIST;
QUIT;


  • 「KILLオプション」でライブラリ内の「全てのデータセット」を削除します。
  • 「全てのデータセット」なので、たとえば「DELETEステートメント」で削除するデータセットを指定していても意味はなく、ライブラリ内の全データセットを削除します。





ちなみに

データセットだけでなくビューも含めて削除したい場合は「MEMTYPE=」に追記すればOK

proc datasets lib=work memtype=(data view) kill nolist;
quit;




2019年11月1日金曜日

カタログからフォーマットを削除する方法






フォーマットを削除する方法1

PROC CATALOG  CAT=ライブラリ名.カタログ名;
     DELETE  フォーマット名1  フォーマット名2 ・・・ / ET=フォーマットの種類;
RUN;


  • 「DELETEステートメント」に削除したいフォーマットを列挙します。
  • 「ET=オプション」に削除する「フォーマットの種類」を指定します。
  • 「フォーマットの種類」には以下があります。
    • FORMAT   ...  数値フォーマット
    • FORMATC ...  文字フォーマット
    • INFMT       ...  数値インフォーマット
    • INFMTC    ...  文字インフォーマット



/* Sample */
proc format;
   value     a      1      = "aaa" ;
   value     $b   "aaa" = "bbb" ;
   invalue   c     "aaa" = 1 ;
   invalue   $d   "aaa" = "bbb" ;
run;

/* フォーマットの種類ごとに削除 */
proc catalog cat=work.formats;
    delete a / et=format;
    delete b / et=formatc;
    delete c / et=infmt;
    delete d / et=infmtc;
quit;



ちなみに、以下のように書くことも可能です。

proc catalog cat=work.formats;
    delete a (et=format)  b (et=formatc) c (et=infmt) d (et=infmtc);
quit;






フォーマットを削除する方法2  (注意事項あり)

PROC CATALOG  CAT=ライブラリ名.カタログ名  KILL FORCE;
RUN;


  • カタログ内の「全エントリー」を削除します。
  • 「全エントリー」とはフォーマットだけでなくマクロなどのあらゆるエントリーを含みます。
  • 「KILL」オプションは PROC CATALOG 内の他のオプションやステートメントより先に動作します。たとえばDELETEステートメントで削除するフォーマットを指定していても意味はなく、カタログ内の全エントリーを削除してしまいます。



2019年10月26日土曜日

データステップでOSのコマンドを実行する「CALL SYSTEM」




データステップでOSのコマンドを実行する「CALL SYSTEM」をご紹介します。
これあんまり知られてない気がする。



例1 (Windows環境)
options noxwait;

data _null_;
    call system( "start excel" );
run;

  • 上の例では「call system( "start excel" )」でExcelを起動するOSのコマンドを生成してます。
  • OSのコマンド実行時にコマンドプロンプトが開かれてSASの処理が一時停止状態になります。システムオプション「noxwait」を設定すると、コマンド実行後にコマンドプロンプトを自動で閉じてSASの処理を継続させます。

なんといっても、データステップでOSのコマンドが生成できちゃうのが魅力ですね。


2019年10月16日水曜日

マクロの実行を中止する「%RETURNステートメント」




  • %RETURNステートメント」でマクロの実行を中止します。
  • 「%RETURN」が書かれたとこから中止される。
  • 「親マクロ」の中に「子マクロ」を入れたネスト構造のマクロで、「子マクロ」の中のみに%RETURNを指定した場合は「子マクロ」のみ中止される。




私はよく以下のような感じで使ってます。



%macro test( in_ds=, out_ds= );
 
    * 引数チェック ;
    %if %sysfunc( exist( &in_ds ) ) = 0 %then %do;
         %put WARNING: データセット &in_ds が存在しません. マクロTESTを中止します;
         %return;
    %end;

    * 引数チェックをクリアしたあとの処理 ;  
    data &out_ds;
        set &in_ds;
    run;

%mend;
%test( in_ds=work.aaa, out_ds=bbb )


ログ




最初にマクロの引数がちゃんと正しく設定されてるか確認して、正しくない場合、

  • WARNINGとかのメッセージを出して、
  • %RETURNでマクロを中止させる。

みたいな流れです。


2019年10月14日月曜日

「SASデータセット」や「外部ファイル」の存在確認




  • EXIST関数・・・「SASデータセット」の存在確認をする。
  • FILEEXIST関数・・・「外部ファイル」の存在確認をする。
  • 存在する場合「1」、存在しない場合「0」が返される。




data test;
    x = exist( "sashelp.class" );
    y = fileexist( "c:\test/test.xlsx" );
run;



記事の内容うっすい・・

2019年10月6日日曜日

ODS LAYOUT GRIDDED入門: 「ODS REGION」の活用





「ODS REGION」ではオプションを設定することができます。
領域内の幅や高さ、配置場所など、詳細な設定を行うことができます。




構文

ODS REGION  オプション;


オプション
 指定 設定内容 
width =
height =
領域の横幅
領域の高さ
column =
row =
何列目の領域に配置するか
何行目の領域に配置するか
column_span =
row_span =
結合する領域の列数
結合する領域の行数
description = "テキスト"代替テキスト
style = [スタイル]レイアウトのスタイル



ods layout gridded
  columns=2 rows=2 column_gutter=0in row_gutter=0in;

 ods region column=1 row=1;
 proc freq data=sashelp.class;
   tables sex;
 run;

 ods region column=2 row=2;
 proc means data=sashelp.class n mean std;
   var height weight;
 run;

ods layout end;





記事一覧

1. 基本構文
2. ODS REGION


2019年10月3日木曜日

「ODS LAYOUT GRIDDED」の「ADVANCE=オプション」



ODS LAYOUT」は「ODS HTML」「ODS PRINTER(PDF等)」「ODS PowerPoint」での出力のみサポートされてるのでご注意を。



まずは以下記事をご覧ください。
ODS LAYOUT GRIDDED入門



今回は上の記事の「ADVANCE=オプション」を詳しく解説したいと思います。



通常は「ODS REGION」を指定して、次の領域に出力を移動させますが、
「ADVANCE=オプション」で、「次の領域に出力を移動させるルール」を新たに設定できます。



ADVANCE=」の設定値
設定値内容 
bygroupBYグループごとに領域を移動
explicit「ODS REGION」が指定されない限り領域を移動しない(デフォルト)
procプロシジャごとに領域を移動
table表ごとに領域を移動
output出力ごとに領域を移動

(「table」と「output」の違いがよく分からない・・テストしてみたけど同じじゃないの?)




例1
ods layout gridded columns=2 column_widths=(3in 3in) advance=bygroup;

 ods region;
 proc sgplot data=sashelp.cars;
   scatter x=msrp y=enginesize;
   by make;
 run;

ods layout end;



「ADVANCE=BYGROUP」として、BY値ごとにグラフを格子状に配置させています。



例2
ods layout gridded columns=2 column_widths=(3in 3in) advance=table;

 ods region;
 proc univariate data=sashelp.class;
    var height;
 run;

ods layout end;



「ADVANCE=TABLE」として、プロシジャから出力される表をそれぞれ格子状に配置させています。




2019年9月29日日曜日

ODS LAYOUT GRIDDED入門: 基本構文




SAS9.4から追加された「ODS LAYOUT GRIDDED」では格子状に領域を作って、プロシジャの出力を各領域に配置させることが出来ます。

格子状に仕切りを定義するODS LAYOUT GRIDDEDのイメージ


構文

ODS LAYOUT GRIDDED オプション;

     ODS REGION;
     プロシジャ

     ODS REGION;
     プロシジャ

ODS LAYOUT END;


  • ODS HTML」「ODS PRINTER (PDF等)」「ODS PowerPoint」への出力のみサポート。
  • 「ODS REGION」で次の領域に移動します。
  • 「ODS LAYOUT GRIDDED」には以下のオプションが設定可


オプション
 指定 設定内容 
width =
height =
レイアウトの幅
レイアウトの高さ
columns =
rows =
列数
行数
column_gutter =
row_gutter = 
列間のスペースの横幅
行間のスペースの高さ
order_type = row_major | column_major次の領域に進む順を縦方向にするか横方向にするか
column_widths = ( 幅1, 幅2・・・)
row_heights = ( 高さ1, 高さ2・・・)
各列の幅
各行の高さ
x =
y =
レイアウトの横位置
レイアウトの縦位置
advance = bygroup | explicit | proc | table | output(ODS REGION以外で) 次の領域に移動するルール (別記事で解説)
description = "テキスト"代替テキスト
style = [スタイル]レイアウトのスタイル



ods pdf file="c:\test.pdf";

ods layout gridded
  columns=2 rows=2 column_gutter=0in row_gutter=0in;

 ods region;
 proc freq data=sashelp.class;
   tables sex;
 run;

 ods region;
 proc means data=sashelp.class n mean std;
   var height weight;
 run;

 ods region;
 ods graphics / width=3in height=2in;
 proc sgplot data=sashelp.class;
   scatter x=height y=weight / group=sex;
 run;

ods layout end;

ods pdf close;




記事一覧

1. 基本構文

2019年9月23日月曜日

PROC ODSTEXT入門: 書式の設定




以下のテキスト出力ステートメントでは「STYLEオプション」でテキストの書式を設定できます。
  • P
  • ITEM
  • HEADING




構文

P   "テキスト"   /   STYLE = [ 書式 ] ;


書式
 指定 設定内容  例 
 FONTFAMILY   フォント  fontfamily='MS P明朝' 
 FONTSIZE  文字サイズ  fontsize=10pt
 FONTWEIGHT  文字の太さ  fontweight=bold 
 FONTSTYLE 斜体等のスタイル  fontstyle=roman
 COLOR 文字色 color = blue
 BACKGROUNDCOLOR   セル色 backgroundcolor = yellow
 ・・・ など




proc odstext;
   h1 "食欲の秋" / style=[color=yellow fontsize=20pt];
   p   "栗"            / style=[color=brown fontsize=50pt];
   p   "柿"            / style=[color=orange fontsize=20pt];
run;






また、条件によって書式を設定したい場合「CELLSTYLE-ASステートメント」が使えます。


構文

CELLSTYLE  条件1  AS  { 書式1 },
                       条件2  AS  { 書式2 },
                       条件3  AS  { 書式3 },
                        ・・・
;




proc odstext data=sashelp.class;
list;
   cellstyle age=12 as {color=orange},
                  age=13 as {color=red};
   item strip(put(age,best16.)) || ", " || name;
end;
run;



上の例では、
  • 「AGE=12」だったら「文字色をOrange」に
  • 「AGE=13」だったら「文字色をRed」に
  • それ以外は書式指定なし
としています。




記事一覧

1. 基本構文
3. 見出しの設定
4. 書式の設定


2019年9月19日木曜日

PROC ODSTEXT入門: 見出しの設定



(SAS9.4M4からの新機能です)

HTMLとか触ったことある方ならピンときやすいですが、「HEADINGステートメント」で「見出し」を設定できます。



構文
H1 "見出しにするテキスト";


  • 「H1」~「H6」で見出しレベルを設定できます。





proc odstext;
   h1 "食欲の秋";
   p "栗";
   p "柿";
   p "さつまいも";
run;



見出しって大切です。
何が大切かってのはまた今度紹介できたらと思います。




記事一覧

1. 基本構文
3. 見出しの設定


2019年9月11日水曜日

ODS EXCELでセル書式を設定する




PROC REPORTなどで使える「STYLE=オプション」で書式を設定することができますが、ODS EXCELで使うと、EXCELのセル書式を設定できてしまいます。


「STYLE=オプション」の詳細は過去記事をご覧ください。
https://sas-boubi.blogspot.com/2016/02/report8.html



ods excel file='c:\test.xlsx';

proc report data=sashelp.class missing  style( header ) = [ background=blue color=white ];
    column sex name age height weight;
    define   sex / order order=internal;
    compute weight;
        if age.sum > 12 then do;
             call define( "age.sum", "style",  "style = [ color=red ]" );
             call define( "name"     , "style",  "style = [ background=yellow ]" );
        end;
    endcomp;
run;

ods excel close;





2019年9月8日日曜日

SASユーザー総会2019に行ってきました。





9月5、6日に国際医療福祉大学東京赤坂キャンパスで開催された、「SASユーザー総会2019」に行ってきました。

ちなみに、今年はBioS30周年記念講演と合同開催で、いつもより豪華でした。

これからBios30周年記念講演が行われる舞台を写した写真




わたしは以下2演題発表してきました。
  • 「ODS EXCEL入門」プレゼンテーション
  • 「SAS Programming Tips: #BYLINEの活用」ポスターセッション

足を運んで聞いてくださった方、どうもありがとうございます!発表楽しかった~。




あと、毎年恒例のアンケートに答えてもらえる粗品ですが、、

ラゲージスケールと書かれた箱の上に置かれた楕円形の物体を写した写真

luggage scale、荷物はかりですね。。いいセンスだ。




それと、SASでロールプレイングゲームのプログラムを作って、ポスターセッションで発表された方。。いいセンスだ。

プログラムをダウンロードして、レベルMAXになるまで楽しくプレイさせて頂きました。
新作も楽しみにしております。



2019年8月29日木曜日

「ODS HTML」は「PATH=オプション」を指定した方がいい





以下のプログラムの「file=」の部分をご自身の環境にあわせてパスを変えて実行してみてください。

ods html file="c:\mysas\test.html";

proc print data=sashelp.class;
run;

ods html close;




ちゃんと動きましたか??
なんか特定の環境でエラーになっちゃいます。たとえばSAS9.4M5のWindows環境だとエラーになります。


以下のページでも言及されてますね。
https://support.sas.com/kb/61/280.html



環境によってはレジストリの設定で、WORKのフォルダパスが「file=オプション」の先頭につくそうです。

つまり、「file="c:\mysas\test.html"」と設定したら「"WORKのフォルダパス\c:\mysas\test.html"」というパスと認識されちゃうってことですね。




解決法

「path=」にパス、「file=」にファイル名を切り分けることでうまく動きます。

ods html path="c:\mysas" file="test.html";




2019年8月20日火曜日

PROC ODSTEXT入門: リストを入れ子にする




「ITEM ~ ENDステートメント」でリストに対し、、

  • 複数の段落を出力できる
  • 入れ子構造を作れる





1. リスト内に、複数の段落を出力する


構文
ITEM;
    P "テキスト1";
    P "テキスト2";
END;




proc odstext;
   list;
     item "アイス";
     item;
        p "スイカ";
        p "スイカは野菜";
     end;
   end;
run;




2. リストを入れ子にする


構文
ITEM;
    P "項目";
    LIST;
        ITEM "入れ子にする項目1";
        ITEM "入れ子にする項目2";
        ITEM "入れ子にする項目3";
    END;
END;




proc odstext;
  list;
     item "果物";
     item;
        p "野菜";
        list;
           item "きゅうり";
           item "キャベツ";
        end;
     end;
  end;
run;




記事一覧

1. 基本構文
2. リストの入れ子

2019年8月12日月曜日

PROC ODSTEXT入門: 基本構文




Q.  PROC ODSTEXTとは?
A.「ODS HTML」や「ODS RTF」などのODS出力先に「テキストを出力するプロシジャ」です。SAS9.4から追加されました。



では、3つの基本構文を紹介していきます!





1. テキスト出力



構文
PROC ODSTEXT;
    P  "出力するテキスト":
RUN;

  • テキストを出力します
  • 1つのPステートメントで、1つの段落を作ることが出来る




proc odstext;
    p "暑いですねー";
    p "夏といえば、なにを思いうかべる?";
run;





2. テキスト出力(リスト形式)


構文
PROC ODSTEXT;
    LIST:
        ITEM "項目1";
        ITEM "項目2";
        ITEM "項目3";
    END;
RUN;

・リスト形式でテキストを出力します。




proc odstext;
    list;
      item "アイス";
      item "スイカ";
      item "クーラー";
    end;
run;





3. データセットの中身を出力


構文
PROC ODSTEXT DATA=データセット;
     ~ ステートメント ~
RUN;



proc odstext data=sashelp.class;
    p "名前: " || name;

    list;
       item "性別: " || sex;
       item "身長: " || put(height,8.1);
    end;
run;




記事一覧

1. 基本構文

2019年8月5日月曜日

日付値から「月初」や「月末」の日付値を求める方法




需要ありまくりなんで書いときます!





data test;
    x = '05feb2019'd;
 
    firstday = intnx( 'month', x, 0, 'beginning');
    lastday = intnx( 'month', x, 0, 'end');
 
    format x firstday lastday yymmdd10.;
run;




解説


月初を求める

    firstday = intnx( 'month', x, 0, 'beginning');

日付値が格納された「変数x」に対して、その月の開始を返すように設定しています。




月末を求める

    lastday = intnx( 'month', x, 0, 'end');    

日付値が格納された「変数x」に対して、その月の終了を返すように設定しています。



2019年7月30日火曜日

頭に「Q」がつくマクロ関数の用途




  • 「%SUBSTR」 に対して 「%QSUBSTR」
  • %UPCASE」 に対して 「%QUPCASE」


...のように、頭に「Q」がつくマクロ関数をご存知でしょうか?
今回は、このQつきマクロ関数を解説したいと思います。




以下はマクロ変数Xに「Mr&Mrs Smith」という文字を格納しています。

%let x = %nrstr(Mr&Mrs Smith);



ここからが問題。
このマクロ変数Xの「頭6バイトを抽出したい」とします。

%put %substr( &x, 1, 6 );

ログ
 WARNING: MRSのシンボリック参照を解決できません。



WARNINGが出ました。
これはマクロ関数「%SUBSTR」の戻り値が「Mr&Mrs」となるわけですが、「&Mrs」の部分をマクロ変数としてSASが認識してしまい、「そんなマクロ変数ないよ」って言われてます。



ここでQつきマクロ関数の出番!

%put %qsubstr( &x, 1, 6 );

ログ
Mr&Mrs



うまくいきました!
このQつきのやつは「マクロ関数の戻り値に特殊文字を含む場合、その文字をクォート処理」してくれます



まぁ以下のように%nrbquoteとか使ってクォート処理してもいいけど、、

%put %nrbquote( %substr( &x, 1, 6 ) );

ログ
Mr&Mrs


Qつきマクロ関数の用途を理解していれば、こんなめんどくさい書き方しなくてもOKってのが分かりますね!


2019年7月24日水曜日

ARRAYステートメントでのLENGTH指定





配列に定義した新たな変数にLENGTHを割り当てたい場合は、以下のような感じで書きますが、、

data test;
    length a b c $10.;
    array ar(3) a b c;
run;




ARRAYステートメントで直接定義することも可能

data test;
    array ar(3) $10. a b c;
run;



2019年7月19日金曜日

「PROC REPORT」の「COMPUTE」がうまく動かないんだけど




以下の失敗例をご覧ください。

* 失敗例 ;
proc report data=sashelp.class;
    column name age;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;


「AGE=13だったらAGEの文字色を青にする」というのがやりたかったのに、青になってないじゃん、っていう失敗例です。




解説


さて、何がまずかったでしょうか。
まずは以下の前提知識が必要なのでお目通しを。。

REPORTプロシジャ入門4:集計【ANALYSIS】
REPORTプロシジャ入門10:数値変数の落とし穴



上のリンクの入門記事でも解説した通り、

REPORTプロシジャに指定した ”数値項目” は、以下のように「analysis sum」オプションが勝手について実行されます。

proc report data=sashelp.class;
    column name age;
    define name / display;
    define age / analysis sum;
run;



analysis項目だと、COMPUTEの中では以下のように「項目名.統計量」という書き方をする必要があります。

proc report data=sashelp.class;
    column name age;
    compute age;
        if age.sum=13 then call define("age.sum","style","style=[color=blue]");
    endcomp;
run;



もしくは「analysis項目じゃないよ」っていうのをSASに教えるために、DISPLAYオプションを明示的に指定してあげます。

proc report data=sashelp.class;
    column name age;
    define age / display;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;



2019年7月16日火曜日

【PROC COMPARE入門】データセット間の変数値の比較





データセット間の変数値を比較する「PROC COMPARE」をご紹介。




構文 1

PROC COMPARE  BASE=データセット1  COMPARE=データセット2 ;
RUN ;

  • 「データセット1」と「データセット2」を比較します。
  • 上から順に同じ位置にあるオブザベーション同士を比較します。
  • 同じ変数名同士を比較します。


イメージ(黄色部分が比較対象)






構文 2

PROC COMPARE  BASE=データセット1  COMPARE=データセット2 ;
      ID   ID変数1   ID変数2 … ;
RUN ;


  • 「データセット1」と「データセット2」を比較します。
  • ID変数の値が共通するオブザベーション同士を比較します。
  • 同じ変数名同士を比較します。


変数XをIDとしたときのイメージ(黄色部分が比較対象)








* sample data ;
data dt1;
input x y$ z;
cards;
1 aa 10
2 bb 20
4 cc 30
;

data dt2;
input x y$ z;
cards;
1 aa 10
2 bb 20
3 cc 30
4 dd 40
;

* proc compare ; 
proc compare base=dt1 compare=dt2;
    id x;
run;




出力結果

1. 「データセットの要約レポート」


各データセットの「変数の数」「OBSの数」「共通変数の数」「ID変数の数」などが表示されます。



2. 「オブザベーションの要約レポート」「値の比較の要約レポート」


「共通するOBSの数」「共通しないOBSの数」「比較変数のいずれかが等しくないOBSの数」「すべての比較変数が同等なOBSの数」などなどが表示されます。



3. 変数値の比較結果


実際の不一致箇所が表示されます。



出力結果の確認の流れ(最低限)

  • 「データセットの要約レポート」で、狙い通りのOBS/変数が比較対象になってるか確認。
  • 「オブザベーションの要約レポート」で不一致となったOBSがあるか確認
  • 不一致のOBSがある場合は「変数値の比較結果」から実際の不一致箇所を確認



2019年7月9日火曜日

「_NULL_の活用」PROC SORT編




以前「_NULL_」について紹介しました。
https://sas-boubi.blogspot.com/search/label/_NULL_



「_NULL_」のちょっとしたテクニックとして、私は以下のような使い方をすることがあります。

* sample data ;
data test;
input a;
cards;
1
2
2
3
;

* _null_ を使う ;
proc sort data=test nouniquekey out=_null_ uniqueout=out1;
    by a;
run;


NOUNIQUEKEYについては以下の記事をご覧ください。
https://sas-boubi.blogspot.com/2014/03/sort.html




ポイント
  • 今回の例では「out=」に出力されるデータセットが別に要らなかったので「out=_null_」として出力しないようにしてます。
  • (もし「out=」を省略すると、「data=」に指定したデータセットに直接上書きしてしまうので、それの予防措置)



実は以前書いた記事でもこのテクニックを使ってます。
https://sas-boubi.blogspot.com/2019/06/blog-post.html



2019年7月5日金曜日

「ORDER=DATA」「ORDER=FREQ」の落とし穴




以前「ORDER=オプション」を紹介しました。

このオプションの「ORDER=DATA」と「ORDER=FREQ」には注意が必要です。
以下の例が想定通りの結果になるか各自確認してみてください。



「ORDER=DATA」の挙動確認

* サンプルデータ ;
data test;
input x y:$1.;
cards;
1 b
1 a
2 c
2 a
2 b
;

* PROC REPORTで「ORDER=DATA」 ;
proc report data=test;
   define x / order order=data;
   define y / order order=data;
run;

「x=2の時の順番が「c → a → b」から「b → a → c」になってしまった?」と疑問に思った方は要注意!


解説

「ORDER=DATA」は「データセットに格納されてるままの順番」に出力されると思いがちですが、
登場した値の順に並び替える」というのが正確ですね。今回の例では、

  • x=1 の時「b → a」の順に値が登場します。
  • x=2 の時「c → a → b」の順に値が登場していますが、上で既に「b → a」の順で登場しているので、「b → a → c」の順に並び替えられます。



「ORDER=FREQ」の挙動確認

* サンプルデータ ;
data test2;
input x y:$1.;
cards;
1 a
1 a
1 b
2 a
2 b
2 b
2 b
2 c
2 c
;


* PROC SUMMARYで「ORDER=FREQ」 ;
proc summary data=test2 print order=freq;
   class x y;
run;

「全然、度数が多い順に並んでない?」と疑問に思った方は要注意!


解説

まずCLASS編数 x, y について、別々に度数を計算します。

  • x=1 の度数: 3
  • x=2 の度数: 6
    • x の値で度数が多い順は「2 → 1

  • y=a の度数: 3
  • y=b の度数: 4
  • y=c の度数: 2
    • y の値で度数が多い順は「b → a → c

てことで、x =「2 → 1」、y = 「b → a → c」の順番で並び替えられます。



2019年6月27日木曜日

「FMTERR」と「NOFMTERR」の機能と落とし穴




以下のようなログメッセージが出たことありませんか。

  • 「ERROR: 出力形式XXを変数XXにロードできません」
  • 「ERROR: 出力形式XXが見つからないか、またはロードできません。」



これは「存在しないフォーマットがデータセットに割り当てられている場合」に、現れるメッセージです。
このメッセージを制御しているのが「FMTERR」と「NOFMTERR」というシステムオプションです。




「Windows版SAS」では以下のシステムオプションがデフォルト設定となっています。

options fmterr;


「SAS Ondemand for Academics」では以下がデフォルト設定となっています。

options nofmterr;


それぞれがどんな動きか見ていきましょう。




FMTERR


以下は変数SEXに「$aaa」、変数BIRTHに「yymmdd10」というフォーマットを割り当てています。

options fmterr;

data test;
    format sex $aaa. birth yymmdd10.;
    sex = "FEMALE";
    birth = '26jun2019'd;
run;


--- Log ---------------------

しかし「$aaa」というフォーマットを事前に定義していなかったので、、「$aaaなんてフォーマット見つからんよ!!」とブチ切れられて処理がストップしちゃいました。



NOFMTERR


そこで「NOFMTERR」を指定してやると、

options nofmterr;

data test;
    format sex $aaa. birth yymmdd10.;
    sex = "FEMALE";
    birth = '26jun2019'd;
run;


--- Log ---------------------



--- Dataset ----------------


「フォーマット見つからないよ」と優しめに言われるものの、一応フォーマット$aaaが割り当てられて、処理を続けてくれます。

「NOFMTERR」が設定されてる間は、フォーマットが見つからなかった箇所を(通常は) 出力形式「w.」または「$w.」として扱ってくれます。





NOFMTERRの落とし穴


今度は以下のように「$aaa1.」というようにフォーマットに長さも指定した場合は、、

options nofmterr;

data test;
    format sex $aaa1. birth yymmdd10.;
    sex = "FEMALE";
    birth = '26jun2019'd;
run;



あれ、「FEMALE」の文字が「F」になってる。


実はフォーマットの長さの部分だけは見てくれるようです。つまり「$aaa1.」は「$1.」として扱われる。


あと例えば数値変数に対して「bbb8.2」みたいな感じで存在しないフォーマットを割り当てた場合も「8.2」として扱われる。


中途半端だな・・・




2019年6月25日火曜日