2013年12月20日金曜日

PUT関数 vs VVALUE関数


以下のように、「PUT関数」を使って文字変換することってよくありますよね。

*** サンプルデータ *******************;
data DT1;
  format   V1 yymmdd10. ;
  V1 = '01jan2000'd; output;
  V1 = '05feb2001'd; output;
  V1 = .; output;
run;

*** PUT関数を使って文字化 ***********;
data DT2;
  length V1 8.  V2 $20.;
  set DT1;
  V2 = put(V1,yymmdd10.) ;
run;


これは「VVALUE関数」でもっと簡単に書けます。

 V2 = VVALUE(V1) ;

「VVALUE関数」は「変数に割り当てられているFORMAT」を使って文字変換してくれる関数です。


注意点


PUT関数と挙動が似ています。
例えば、PUT関数で数値の欠損値を以下のようにFORMAT変換すると、、

 length V3 $20.;
 V3 = put( . , yymmdd10.);

→ 変換後の値は「         .」という感じで先頭に余計な空白が入ります。


また、フォーマットによっては、、

 length V4 $20.;
 V4 = put( 10, best12. );

→ 変換後の値は「          10」という感じでこちらも先頭に余計な空白が入る場合があります。


VVALUE関数も同様に先頭に空白が入る場合があるのでご注意下さい



2013年12月16日月曜日

全角文字を半角に変換する。




全角から半角へ、半角から全角へと変換する「KPROPCASE関数」についてまとめてみました。



構文

KPROPCASE( 対象変数名,  ' 変換パターン指定 ' )

変換パターン 指定方法
① 全角カタカナ ⇒ 半角カタカナ'full-katakanahalf-katakana'
② カタカナ ⇒ ローマ字'katakana, romaji'
③ 全角アルファベット ⇒ 半角アルファベット

(英数記号も対象。
 ただし全角中点「・」は半角にならなかった。
 ①の指定方法では半角になった)
'full-alphabet, half-alphabet'




④ 小文字 ⇒ 大文字'lowercase, uppercase'


変換パターンは、以下のように逆指定も可。

例:
kpropcase( 対象変数名,  'lowercase, uppercase' )
kpropcase( 対象変数名,  'uppercase, lowercase' )




変換例

data DT1;
  length VAR1 A B C D $30.;
  VAR1 = "あカキ(1abC";
  A = kpropcase( VAR1, 'full-alphabet, half-alphabet' ) ;
  B = kpropcase( VAR1, 'lowercase, uppercase' ) ;
  C = kpropcase( VAR1, 'half-katakana, full-katakana' ) ;
  D = kpropcase( VAR1, 'katakana, romaji' ) ;
run;

結果
VAR1あカキ(1abC
A あカキ(1abC
B あカキ(1AB
C あカ(1abC
D KAKI(1abC



注意

①ふたつめの引数は 「'lowercase', 'uppercase'」ではなく「'lowercaseuppercase'」です。
間違えやすいので注意が必要です。


②半角を全角に変換したい場合、
たとえば以下のプログラムを実行すると、VAR1の値は全角”A”となる。

data DT3;
  length VAR1 $2.;
  VAR1 = "AB";
  VAR1 = kpropcase( VAR1, 'half-alphabet, full-alphabet' );
run;


これは全角変換したことによって、LENGTHが4バイト必要なのに、2バイトしかないため、文字切れを起こしているから。そのため、変換前にLENGTHを2倍に指定し直す必要がある。

(※上記はWindowsのsjis環境での話で、他の環境ならもっとLENGTHが必要)

2013年12月13日金曜日

SQLの小技「CALCULATEDキーワード」


SASのSQL独自の便利機能「CALCULATED」キーワード
MySQLとかでは動かなかった。

このキーワードを使うと、SELECT句で作成した変数を、同じSQL内で参照することが出来る。


*** サンプルデータ ;
data DT1;
   do V1=1 to 3 ;
      output;
   end;
run;


*** 普通は以下のエラーが出る ;
proc sql;
  select sum(V1) as V2 ,
            V2+1 as V3
  from DT1;
quit;

ERROR: 次の列はテーブル内に存在しません: V2.


*** 「CALCULATED」を使った場合 ;
proc sql;
  select sum(V1) as V2,
           calculated V2+1 as V3
  from DT1;
quit;



正直この例だと、「sum(V1)+1 as V3」と書いてもいいけど、、
・「V2」の式が長文の場合、「V3」作る時にもう1回長文かく手間が省けていい。
・内部の処理効率的に「calculated」を使った方がいいのかも。

という理由で、個人的には「calculated」を愛用してる。

2013年12月10日火曜日

欠損値のチェックを簡単に行う。


CMISS関数」は、欠損値の数をカウントしてくれます。
数値変数・文字変数、どちらも指定可能です。

ロジカルチェックやデータクリーニングの際に重宝します。
以下に使用例をまとめてみた。


サンプルデータ

data DT1;
input X1 X2 X3$;
cards;
1 2 aa
3 . bb
5 . .
. . .
;
run;


使用例

/* 欠損値の数を取得 */
data DT2;
  set DT1;
  Y = cmiss(X1,X2,X3);
run;


/* いずれかが欠損値のOBSを特定 */
data DT3;
  set DT1;
  if cmiss(X1,X2,X3) > 0 then FLG=1;
run;


/* すべて欠損値のOBSを特定 */
data DT3;
  set DT1;
  if cmiss(X1,X2,X3) = 3 then FLG=1;
run;


2013年12月6日金曜日

INPUT関数の小技


「INPUT関数」で文字を数値に変換する時、
"100未満"や"2013/10/初旬"とかだと、ログに無効なデータがある旨のメッセージが表示され欠損値となる。

サンプルプログラム

data DT1;
   length V1 $20.;

   V1="2013/10/初旬";
   V2=input(V1,yymmdd10.) ;
run;


ログ






そこで以下のように「??」を入れると、「問題ない」という扱いになりログから上記メッセージを消せる。
「V2」の値は上記の結果と変わらない。

   V2=input(V1,?? yymmdd10.)  ;

ログ









本来、おかしなデータがないか把握する上で、
無効なデータがある旨のログメッセージは絶対出しておくべき。


しかし、
ロジカルチェックなどで「生年月日に日付として不正な記載がある」
のようなチェックをかける場合、不正な記載そのものを抽出するので、わざわざそこをログに注意されなくてもいいと思う時は、「??」を入れたほうが、後のログチェックもスムーズにいく。

2013年12月2日月曜日

色々な例数を簡単に出す。



「SQLプロシジャでフラグ変数を簡単に作成。」を発展させたやり方。


A薬投与例数、B薬投与例数、中止例数、、etc
色々な例数をカウントしたい場合、SQLなら1STEPで簡単に出来てしまう。

サンプルデータ
data DT1;
  attrib
     SUBJID   label="症例番号"       length=$3.
     ARM       label="群"                 length=$10.
     SEX        label="性別"              length=$1.
     AEYN      label="有害事象有無" length=$1.
  ;
  input SUBJID$ ARM$ SEX$ AEYN$ ;
cards;
001 A薬 M  Y
002 B薬 F  Y
003 A薬 F  N
004 A薬 M  Y
005 B薬 F  N
;
run;


求めたい結果



SQLプロシジャで各例数を計算
proc sql;
   create table DT2 as
   select sum(ARM="A薬")  as N_ARM1, 
             sum(ARM="B薬")  as N_ARM2
   from DT1;
quit;


解説
関数の中に条件式を入れてるとこがポイント。

仕組みはまず、条件式に合致する場合「true=1」
合致しない場合「false=0」が返される。
その「0」か「1」になった値をsum関数で合計することで、条件に合致する例数をカウントしたことになる。

ちなみによくやる間違えとして、sum関数じゃなくcount関数を使ってしまいがち。
count関数は非欠損値の数をカウントするので、「0」も「1」もカウントしちゃって意味のない処理になっちゃうので注意。



応用
グループ毎に色々な有無を出すこともできる。

たとえば、上記で作成したサンプルデータで以下のように「群毎の有無」を出したいとする。
ちなみに「0=無」「1=有」を表す。






SQLプロシジャで群毎の各有無を出す。
proc sql;
   create table DT3 as
   select ARM,
          max(AEYN="Y")  as AEYN,
          max(SEX="M" and AEYN="Y")  as MALEYN
   from DT1
   group by ARM;
quit;



解説
条件式が「1=true」「0=false」となることを利用し、
「max(条件式)」とすることで「0=無」「1=有」という感じで、有無を得ることが出来てしまう。


SQLの素晴らしい柔軟さが伺える。

SQLプロシジャでフラグ変数を簡単に作成。


SQLプロシジャで、意外に使われてないと思ったやり方。
CASE式を使用しなくても、簡単にフラグ変数を作成することが出来る。

*** サンプルデータ作成 ;
data DT1;
  do V1=1 to 3;
     output;
  end;
run;

*** SQLプロシジャでフラグ変数を作成 ;
proc sql;
 create table DT2 as
 select  (V1>1) as FLG1,
           (1<V1 and V1<3) as FLG2
 from DT1;
quit;



結果






解説
SELECT 条件式  as  新規変数名」で、
「条件式」に合致する場合「1:true」、合致しない場合「0:false」が新規変数に返される。

これを知っていると色々な応用がきく。