複数の変数を縦持ち変換にしたい
臨床試験のデータを集計する前に、変数が横持ちになっている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を使用して実現する場合、
*---白血球数とリンパ球数の架空のデータを作成---;
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)を使ってみる
*---白血球数とリンパ球数の架空のデータを作成---;
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レコードあたりの白血球数とリンパ球数のデータ数が同じだったが、
異なる場合は工夫する必要がある。
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を触りたての初心者なので、もっと良いやり方があれば是非教えてくださると嬉しいです。