かきためぬ

書き溜めたいきもちは山々だけど

【SAS】1つのDATAステップで複数のデータセットを作成【OUTPUTステートメント】

条件ごとにデータセットを分けたいとき、OUTPUTステートメントを使用すると1つのDATAステップで作成できる。


例えば、未成年者と成年者のデータが混ざったデータセットを、それぞれ分けたいとする。
f:id:hhohh:20161211140412p:plain

/*元データ作成*/
data sample1;
  length id 8. name  $10. age 8.;
  input id name$ age;
  datalines;
  1 Rose 5
  2 Nicole 20
  3 Stephen 14
  4 Teresa 37
  5 Brenda 42
  ;
run;

以下の2つの書き方だと、後者であればコードの冗長が防げる。

/*OUTPUTステートメントを使用しない例(2つのDATAステップが必要)*/
data minors;
  set sample1;
  if .<age<20;
run;

data majors;
  set sample1;
  if 20<=age;
run;
/*OUTPUTステートメントを使用する例(1つのDATAステップが必要)*/
data minors majors;
  set sample1;
  *20歳未満ならデータセットminorsにoutput;
  if .<age<20 then output minors;
  *20歳以上ならデータセットmajorsにoutput;
  if 20<=age  then output majors;
run;
  • 結果は同じ

f:id:hhohh:20161211141138p:plain

【SAS】文字列連結③ CATX関数の活用例【連結する変数の数が定まっていないとき】

連結する変数の数が決まってるなら連結演算子(||)でも可能だけど、決まってないときはCATX関数が活用できる。

例えば以下のようなとき。
f:id:hhohh:20161211124215p:plain
元データのほうは、それぞれの人が何個かずつ買うものがあって、その数の分だけレコードをもつ。それを、1人1レコードにまとめたい。

/*元データ作成*/
data sample1;
  length id 8. name item $10.;
  input id name$ item$;
  label item='買うもの';
  datalines;
  1 Rose Book
  1 Rose Pen
  1 Rose Stapler
  2 Nicole Scissors
  2 Nicole Glue
  2 Nicole Notebook
  2 Nicole Book
  3 Stephen Ruler
  3 Stephen Scissors
  4 Teresa Glue
  4 Teresa Notebook
  4 Teresa Book
  4 Teresa Ruler
  4 Teresa Scissors
  5 Brenda Pen
  5 Brenda Notebook
  ;
run;
/*変数idでソート*/
proc sort data=sample1;
  by id;
run;
/*新しい変数「shoppinglist」を作成*/
data sample2;
  set sample1;
  by id;
  length shoppinglist $500.;
  label name='名前' shoppinglist='買い物リスト';
  retain shoppinglist;
  *そのidの1オブザベーション目のときは、itemの値をそのままshoppinglistに入れる;
  if first.id then shoppinglist=item;
  *1オブザベーション目でないときは、shoppinglistの値とitemの値を「/」で結合してshoppinglistに入れる;
  else shoppinglist=catx('/',shoppinglist,item);
  *そのidの最後のオブザベーションのときはoutputした後shoppinglistに欠損値を入れる;
  if last.id then do;
    output;
    call missing(of shoppinglist);
  end;
  keep id name shoppinglist;
run;
  • 作ったデータセットの中身をPRINTプロシジャで表示してみると以下のようになる
proc print data=sample2 label;
run;

f:id:hhohh:20161211131447p:plain

【SAS】文字列連結② 連結演算子(||)を使う場合の、空白なしの連結【STRIP関数】

単純に空白なしで連結したいだけなら、連結演算子使っても書ける。


※連結のところ以外は前回の記事と同じ。

 /*元データ作成*/
 data sample1;
   length animal1-animal5 $10. ;
   input animal1-animal5;
   datalines;
   dog
   cat
   rabbit
   bird
   mouse
   ;
 run;
 /*文字列連結*/
 data sample2;
   set sample1;
   length animal_all1 animal_all2 $100.;
   
   *連結演算子とSTRIP関数を使って連結;
   animal_all1=strip(animal1)||'/'||strip(animal2)||'/'||strip(animal3)||'/'||strip(animal4)||'/'||strip(animal5);
   
   *CATX関数を使って連結;
   animal_all2=catx('/',of animal1-animal5);
   
   keep animal_all:;   
 run;
  • 結果比較

f:id:hhohh:20161211113539p:plain
STRIP関数を使うと先頭末尾の空白が削除されて、CATX関数使った場合と同じ結果が得られる。

【SAS】文字列連結① 区切り文字を使う連結で、余計な空白にイライラしない【CATX関数】

例えば別々の変数に入った値「dog」「cat」「rabbit」「bird」「mouse」みたいなのを「/」で区切って「dog/cat/rabbit/bird/mouse」としてひとつの変数に入れたいとき、単純に連結演算子(||)だけを使うと余計な空白が入る。さらにもし連結する変数が多かったら書くのが大変になる。

CATX関数を使うと先頭と末尾の空白も削除されてコードの見た目もすっきりする。

 /*元データ作成*/
 data sample1;
   length animal1-animal5 $10. ;
   input animal1-animal5;
   datalines;
   dog
   cat
   rabbit
   bird
   mouse
   ;
 run;
 /*文字列連結*/
 data sample2;
   set sample1;
   length animal_all1 animal_all2 $100.;
   
   *連結演算子だけ使って連結;
   animal_all1=animal1||'/'||animal2||'/'||animal3||'/'||animal4||'/'||animal5;
   
   *CATX関数を使って連結;
   animal_all2=catx('/',of animal1-animal5);
   
   keep animal_all:;   
 run;
  • 結果比較

f:id:hhohh:20161211111136p:plain


連結演算子の方は「dog」の後とかに余計な空白(長さ10を指定してる変数なので、その長さに足りない分空白入れてくれちゃってる)が入るけど、CATX関数の方は入ってない。

【SAS】SCAN関数を活用して「1-1」みたいな値を持つ文字変数をソートする

  • テストデータ作成
DATA test;
  INPUT id $;
  CARDS;
  2-2
  1-3
  1-9
  2-6
  1-4
  2-5
  1-6
  1-7
  1-8
  2-7
  1-10
  2-1
  1-2
  2-4
  2-3
  1-1
  2-8
  1-5
  2-9
  2-10
  ;
RUN;

f:id:hhohh:20160907225833p:plain


この文字変数を
1-1
1-2
1-3
1-4
1-5
1-6
1-7
1-8
1-9
1-10
2-1
2-2
2-3
2-4
2-5
2-6
2-7
2-8
2-9
2-10

↑こうソートしたいけど、このままSORTプロシジャを実行すると

PROC SORT DATA=test;
  BY id;
RUN;

うまくいかない。
f:id:hhohh:20160907230047p:plain









SCAN関数を使ってソートに使う変数を作る

「-」を区切り文字として変数idを区切って、それぞれ別々の変数id1、id2に入れる

DATA test2;
  SET test;


  /*「-」の前の部分を変数id1に入れる*/
  id1=SCAN(id,1,'-');

  /*「-」の後ろの部分を変数id2に入れる*/
  id2=SCAN(id,2,'-');

  
  /*id2の長さが1だったら「0」を前につける*/
  IF LENGTH(id2)=1 THEN id2='0'||id2;

RUN;


id1、id2でソートすると

PROC SORT DATA=test2;
  BY id1 id2;
RUN;

想定通りにidがソートされた。
f:id:hhohh:20160907231347p:plain




id1、id2がいらないならDROPステートメントとかで削除する


DATA test2;
  SET test2;
  
  DROP id1 id2;
RUN;


f:id:hhohh:20160907231646p:plain

【SAS】アウトプットウィンドウへの出力を制御

PRINTプロシジャを実行するとアウトプットウィンドウにデータセットの中身が表示される。

PROC PRINT DATA=test;
RUN;

以上を実行するとアウトプットウィンドウに以下の内容が出力される
f:id:hhohh:20160907215108p:plain



でも、プロシジャによっては実行結果をアウトプットウィンドウにいちいち出力したくないこともある。
(実行結果をデータセットに出力するときなど)


例えば、一度にたくさんのTTESTプロシジャ(t検定を行うプロシジャ)などを実行した場合、それぞれの実行結果が全部アウトプットウィンドウに表示されてしまうと少し鬱陶しい。






アウトプットウィンドウの表示を制御するやり方

ODS EXCLUDE ALL;

以上を実行するとアウトプットウィンドウへの出力が制御される。
先ほどのPRINTプロシジャを実行してもアウトプットウィンドウには何も表示されなくなる。



アウトプットウィンドウの表示を戻すやり方

ODS SELECT ALL;

または、

ODS EXCLUDE NONE;

どちらかを実行すると、再びアウトプットウィンドウに出力されるようになる。





↓活用例

/*アウトプットウィンドウへの出力を止める*/
ODS EXCLUDE ALL;

/*アウトプットウィンドウに結果を出力したくないプロシジャを実行*/
PROC TTEST DATA=[データセット名];
  ODS OUTPUT TTESTS=[プロシジャの結果を出力するデータセット名];
  VAR [分析する変数名];
RUN;

/*アウトプットウィンドウへの出力を再開する*/
ODS SELECT ALL;

【SAS】オブザベーション数をカウントする【SQLプロシジャ使用】

SQLプロシジャを使ってオブザベーション数をカウントするやり方
※データは前回と同じものを使用


PROC SQL;
  CREATE TABLE count AS 
  SELECT
  COUNT(*) AS cnt
  FROM test;
QUIT;
  • 作成されたデータセットの中身は前回と同じ

f:id:hhohh:20160907210005p:plain




  • categoryごとにカウントならgroup by
PROC SQL;
  CREATE TABLE count AS 
  SELECT
  category,COUNT(*) AS cnt
  FROM test
  GROUP BY category;
QUIT;

f:id:hhohh:20160907214036p:plain