2017年7月27日木曜日

My Favorite SAS Functions (9) CALL MISSING



第9回目は、関数じゃなくてコールルーチンになりますが、CALL MISSINGを紹介。
指定した変数をすべて欠損値にする機能を持っています。


こちらもやっぱり過去記事で紹介済みです。
指定した変数をすべて欠損値にする【CALL MISSING】



さて、CALL MISSINGの使用前・使用後を見てみましょう。




以下のようなデータセットがあったとします。

data DT1;
   X1 = 123;
   X2 = 456;
   X3 = "abc";
run;
  X1  
  X2  
  X3   
 123 456  abc

ここで、変数 X1, X2, X3 を欠損値にしたいします。

普通に書くと以下のような感じですね。

Before
data DT2;
   set DT1;
   X1=.;
   X2=.;
   X3="";
run;
  X1  
  X2  
  X3  
   .   .  

数値変数だったら「数値変数=.;」
文字変数だったら「文字変数="";」
みたいな感じで書き方分けなきゃいけないし、面倒ですよね。

CALL MISSINGを使えば、もっと楽になります。

After
data DT2;
   set DT1;
   call missing(X1, X2, X3);
run;
  X1  
  X2  
  X3  
   .   .  


ちょこっとした場面で頻繁に活躍してくれるので、すごく便利ですよ!



2017年7月25日火曜日

そのマクロ変数、ローカル?グローバル?②%LET編




%LETでマクロ変数を定義した時に、ローカル・グローバルどちらになるのか説明します。
まずは以下がSAS内部の判定方法なのでご覧ください。

























上の図を整理すると、、マクロ変数を定義する場所によって以下の動作をします。

マクロの外
・「グローバル」になる

マクロの中
・まず、同名のマクロ変数が既に定義されていないかチェックする。
・チェックする順は、「ローカル」→「グローバル」の順
・既に存在する場合は、上書きする。
・「ローカル」にも「グローバル」にも無い場合は、「ローカル」に新規作成。



では具体例でみていきましょう。
まず今回の解説で使うマクロ変数を予めリセットしときます。

%symdel MAC1 MAC2 MAC3 / nowarn;





動作確認


① マクロ外で定義したマクロ変数が、「グローバル」になる例。

%let MAC1 = abcd;
%put _user_;

ログ
GLOBAL MAC1 abcd



② マクロ内で定義したマクロ変数が、「ローカル」になる例。

%macro TEST(  MAC2 );
       %let MAC2 = 1234;
       %put _user_;
%mend;

%TEST( abcd );

ログ
TEST MAC2 1234

1つ補足ですが、マクロの引数として定義したマクロ変数は、必ず「ローカル」になります。
つまり、「%macro TEST(  MAC2 )」でローカルマクロ変数「MAC2」を定義しています。

次に「%let MAC2 = 1234」で、上記で既に定義した同名のローカルマクロ変数を上書きしています。



③ マクロ内で定義したマクロ変数が「グローバル」になる例

%let MAC1 = abcd;

%macro TEST;
   %let MAC1 = 1234;
   %put _user_;
%mend;

%TEST;

ログ
GLOBAL MAC1 1234

同名のグローバルマクロ変数が既に存在するので上書きします。



④ マクロ内で定義したマクロ変数が、「ローカル」になる例。

%macro TEST;
       %let MAC3 = abcd;
       %put _user_;
%mend;

%TEST;

ログ
TEST MAC3 abcd

同名のマクロ変数がローカルにもグローバルにもないので、ローカルマクロ変数が作成されます。




次回はCALL SYMPUTによるローカル・グローバルの判定方法を紹介します。


2017年7月21日金曜日

My Favorite SAS Functions (8) IFN / IFC関数



第8回目は、IFN / IFC関数。
IFステートメントの関数バージョンみたいなやつです。

これも大変便利なのでヘビーに使う関数のひとつですね。



構文

   IFN (  条件式  , 条件式が真(TRUE)の場合の戻り値 ,  条件式が偽(FALSE)の場合の戻り値 )


戻り値を数値で返したい場合はIFN関数を使い、文字値で返したい場合はIFC関数を使います。


以下記事ですでに紹介済みなので、まずはそちらをご覧ください。
IFN / IFC関数と謎の第4引数



では、IF関数を使わない場合と、使う場合とでプログラムを比較してみます。





例えば、以下のようなデータセットがあったとします。

data DT1;
   X1="YES"; output;
   X1="NO"; output;
run;

 X1 
   YES  
   NO 


ここで
・X1="YES" だったら「1」
・X1="YES" 以外だったら「0」
みたいな条件分岐で値を設定したいとします。

通常はIFステートメントを使いますよね。

Before
data DT2;
   set DT1;
   if X1 = "YES" then Y=1;
   else  Y=0;
run;
 X1
 X2
  YES      1  
  NO     0  


IFN関数を使えばもっとスッキリとした文になります。

After
data DT2;
   set DT1;
   Y = ifn(X1="YES",1,0);
run;
 X1 
 X2
  YES      1  
  NO     0



2017年7月18日火曜日

そのマクロ変数、ローカル?グローバル?①基本概念




マクロ変数には、以下2種類あるのをご存知でしょうか?

  ローカルマクロ変数

 定義したマクロ内でしか参照できないマクロ変数

  グローバルマクロ変数  
  
 どの場所からでも参照できるマクロ変数




では具体例を見ていきます。
(ただし、どうしてこれがローカルになるの?グローバルになるの?っていうのは別記事で紹介予定なので、今は気にしないでください。)




ローカルマクロ変数の例


以下マクロ「TEST」の中で、ローカルマクロ変数「X」を定義しています。

%macro  TEST;
     %let  X = abcd;
%mend;

%TEST;


ここで以下赤字の%putステートメントを用いて、
マクロ「TEST」の中で、マクロ変数 X の値を展開してみます。

%macro  TEST;
     %let  X = abcd;
     %put  &X;
%mend;

%TEST;

ログ
abcd


問題なくマクロ変数 X の値が展開できている事が分かります。
では次に、マクロの外で展開しようとすると、、

%macro  TEST;
     %let  X = abcd;
%mend;

%TEST;
%put  &X;

ログ
WARNING: 記号参照Xを展開していません。

怒りのWARNINGが出てしまいます。
マクロ内で定義したローカルマクロ変数は、マクロの実行中にしか存在しないので、マクロ外からの展開は出来ません。




グローバルマクロ変数の例


以下では、グローバルマクロ変数「Y」を定義しています。
どこからでも展開することができます。

%let  Y = xyz;
%put  &Y;

%macro  TEST;
     %put  Y;
%mend;
%TEST;

ログ
xyz
xyz




マクロ変数の表示。


マクロ変数がローカルとグローバルどちらで格納されているのか判断がつかない場合の対処法。

以下 「%put _user_;」で調べる事が出来ます。

%let  Y = xyz;

%macro  TEST;
     %let  X = abcd;
     %put  _user_;
%mend;
%TEST;

ログ
 TEST X abcd
 GLOBAL Y xyz

実際のログには余計なマクロ変数の値が出ますが、上の例ではそれらを除いて分かり易くしてます。
ログの結果から以下が分かります。

・マクロ「TEST」のローカルマクロ変数「X」 には "abcd" という値が格納されている
・グローバルマクロ変数「Y」には "xyz" という値が格納されている


_USER_ 以外にも以下の指定が可能です。

_AUTOMATIC_ … 自動マクロ変数を表示する
_GLOBAL_       … グローバルマクロ変数を表示する(自動マクロ変数は含まず)
_LOCAL_          ... ローカルマクロ変数を表示する
_ALL_               … 全てのマクロ変数を表示する(自動マクロ変数を含む)
_USER_            … ユーザー定義のマクロ変数を表示する。

2017年7月13日木曜日

欠損値の判定とテクニック【IS NULL】【IS MISSING】【MISSING関数】




WHEREステートメントに、「変数が欠損値」という条件を入れたい場合、以下のように書く方が多いと思います。

・数値変数の場合
  where X = .;

・文字変数の場合
  where X = ””;





別の書き方として、以下のように書くことも出来ます。
  where X is null;        /* is null */
  where X is missing;  /* is missing */
  where missing(X);    /* missing関数 */


変数が欠損値”以外”の場合はnotをつけます。
  where X is not null;        /* is null */
  where X is not missing;  /* is missing */
  where not missing(X);    /* missing関数 */


・この3つの書き方は変数が数値型だろうが文字型だろうが、関係なく通るので便利です。
・ただし、「is null」と「is missing」は、WHEREステートメントでした使えない書き方です。

IF文とかで使いたい場合は、missing関数が使えます。
  if missing(X) then Y=1;




この書き方が役に立つ例として、以下のようなマクロを組む場合です。
%macro TEST( DS, VAR );

   data DT1;
      set &DS;
      where &VAR is null;
   run;

%mend;

上記のマクロ、なんてことはないマクロですが、「is null」という書き方を使わないと、プログラム書くのがすごい面倒です。

というのも、マクロ変数 VAR に指定した変数が、
・数値変数の場合は 「where &VAR =.;」
・文字変数の場合は 「where &VAR ="";」
というように、指定された変数の型によって、実行するWHEREステートメントを分岐するように書かなきゃいけないからです。


状況によって使い分けると便利です。

2017年7月12日水曜日

My Favorite SAS Functions (7) CMISS関数



第7回目は、CMISS関数。
指定した変数のうち、欠損値の数を返してくれます。
おススメポイントが、数値変数・文字変数どちらも指定可能という点です。


基本的な使用例は以下記事で紹介済みなので、そちらをご覧ください。
欠損値のチェックを簡単に行う。



では、CMISSを使わない場合と、使う場合とでプログラムを比較してみましょう。





例えば、以下のようなデータセットがあったとします。

data DT1;
   X1=1;
   X2=.;
   X3="aaa";
run;

 X1 
 X2 
X3
   1    .  aaa 


この変数 X1~X3 のうち、いずれかが欠損値の場合、変数Yにフラグ「1」を立てたいとします。
まずはCMISSを使わない場合。

Before
data DT2;
   set DT1;
   if X1=. or X2=. or X3="" then Y=1;
run;
 X1 
 X2 
X3
 Y 
   1    .  aaa   1  


そしてCMISSを使う場合。

After
data DT2;
   set DT1;
   if cmiss(X1,X2,X3)>0 then Y=1;
run;
 X1 
 X2 
X3
 Y 
   1    .  aaa   1  


今回の例だとCMISSを使った成果が見えづらいですが、変数の数が多いと非常にスッキリとした文になります。


CMISSは便利なのに知名度が低いので、すごい勿体ない。

2017年7月4日火曜日

【PROC COPY】データセットを他のライブラリに一括コピー



構文


   PROC COPY
       IN                =   コピー対象のライブラリ
       OUT            =   出力先のライブラリ
       MEMTYPE  =   (コピー対象のデータのタイプ) ;

       SELECT     コピー対象のデータ ;
       EXCLUDE  コピー対象外のデータ ;

   RUN;


・SELECT・EXCLUDEステートメント を省略するとライブラリ内の全データがコピー対象になる

・出力先に同名のデータが存在する場合は、上書きされる。

・MEMTYPE = には以下などが指定可(一部)

       DATA          …    データセット
       CATALOG   …   カタログ
       VIEW          …    データビュー





では例を見ていきましょう。
まずは適当にコピーするデータセットを準備。

data DT1 DT2 DT3;
  A=1;
run;



例① WORK の全データセットを MYLIB にコピー
libname MYLIB "C:\TEST";

proc copy in=WORK out=MYLIB memtype=(data);
run;


例② WORK の DT1,DT2 を MYLIBにコピー
proc copy in=WORK out=MYLIB memtype=(data);
  select DT1 DT2;
run;


例③ WORKの DT3 以外の全データセット を MYLIBにコピー
proc copy in=WORK out=MYLIB memtype=(data);
  exclude DT3;
run;