1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

SASで複数の変数を縦持ち変換にする

複数の変数を縦持ち変換にしたい

 臨床試験のデータを集計する前に、変数が横持ちになっているRawデータを縦持ちに変換(整形)するという作業が必要です。
臨床試験周りのDBの設計は横持ちになっていることが多く、何はともあれとりあえず縦持ちにしなければ何もできません。

やりたいこと

こうなっているデータを

SUBJID WBC01 WBC02 WBC03 LYMP01 LYMP02 LYMP03
01-0001 6500 5500 3200 3400 3500 1780
01-0002 4500 3200 2000 2000 2800 1280
01-0003 5500 7000 6400 3600 4350 5090
01-0004 3300 2900 1500 1500 1400 700

こうしたい

SUBJID WBC LYMP
01-0001 6500 3400
01-0001 5500 3500
01-0001 3200 1780
01-0002 4500 2600
01-0002 3200 2800
01-0002 2000 1200
01-0003 5500 3640
01-0003 7000 4350
01-0003 6400 5090
01-0004 3300 1550
01-0004 2900 1400
01-0004 1500 700

方法1. proc transpose

proc transposeを使用して実現する場合、

transpose.sas
*---白血球数とリンパ球数の架空のデータを作成---;
data lbset01;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 
 01-0002 4500 3200 2000 2600 2800 1200 
 01-0003 5500 7000 6400 3640 4350 5090 
 01-0004 3300 2900 1500 1550 1400 700
 ;
run;

*---WBCのみ転置----;
proc transpose data=lbset01 out=wbc PREFIX=WBC;
  var wbc01 wbc02 wbc03;
  by SUBJID;
run;

*---LYMPのみ転置----;
proc transpose data=lbset01 out=lymp PREFIX=LYMP;
  var LYMP01 LYMP02 LYMP03;
  by SUBJID;
run;

*--マージKeyでソートしておく---;
proc sort data=wbc;
 by SUBJID;
run;

proc sort data=lymp;
 by SUBJID;
run;

data Lbdata;
 merge trlbset01 trlbset02;
 by SUBJID;
run;

一見良さそうだけど

 今回は白血球数とリンパ球数の2項目だったが、実際、業務で扱う臨床検査値はもっと多い。
 10項目あれば、10項目分transposeする必要がある。

方法2. proc sql(union all)

sql(union all)を使ってみる

union_all_1.sas
*---白血球数とリンパ球数の架空のデータを作成---;
data lbset01;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 
 01-0002 4500 3200 2000 2600 2800 1200 
 01-0003 5500 7000 6400 3640 4350 5090 
 01-0004 3300 2900 1500 1550 1400 700
 ;
run;

*---union allを使わないと重複データが削除されるので注意----;
proc sql;
 create table lbdata as
 select SUBJID,WBC01,LYMP01 from lbset01
 union all select SUBJID,WBC02,LYMP02 from lbset01
 union all select SUBJID,WBC03,LYMP03 from lbset01
 ;
quit;

一見良さそうだけど

 今回は1レコードあたりの白血球数とリンパ球数のデータ数が同じだったが、
 異なる場合は工夫する必要がある。

union_2.sas

data lbset02;
 input SUBJID:$10. wbc01:$8. wbc02:$8. wbc03:$8. LYMP01:$8. LYMP02:$8. LYMP03:$8. LYMP04:$8.;
 cards;
 01-0001 6500 5500 3200 3400 3500 1780 1500
 01-0002 4500 3200 2000 2600 2800 1200 1000
 01-0003 5500 7000 6400 3640 4350 5090 4900
 01-0004 3300 2900 1500 1550 1400 700 1000
 ;
run;

*---WB04は存在しない変数のため""を取得するようクエリを書く---;
proc sql;
 create table lbdata as
 select SUBJID,WBC01,LYMP01 from lbset02
 union all select SUBJID,WBC02,LYMP02 from lbset02
 union all select SUBJID,WBC03,LYMP03 from lbset02
 union all select SUBJID,"",LYMP04 from lbset02
 ;
quit;

結論

普段はmysqlを触っていることもあり個人的な好みはsqlですが、
実行速度を考えると悩ましいですね。

最後に

まだまだSASを触りたての初心者なので、もっと良いやり方があれば是非教えてくださると嬉しいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?