僕の頁 <SASと臨床試験と雑談と>

徒然なるままにSAS暮らし

----

スポンサーサイト  

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Posted on --/--/-- --. --:-- [edit]

CM: --
TB: --

0130

SGANNOによるSGプロシジャのAnnotate機能(テキスト出力)  

SAS9.3から使用可能になったSGプロシジャのAnnotate機能でテキストを出力してみます。以下では、IDごとの値(VAL)を棒グラフで出力し、padオプションで右側にスペースを設定します。SGANNOオプションでそのスペースにIDに対応した変数GRPの値を出力しています。functionにtext、X軸の出力座標はx1space = "graphpercent"でパーセントを指定します。
*** TEXT挿入の例 ;
data aaa ;
input ID @@ ;
VAL = round(rannor(100),.1) ;
GRP = (mod(ID,2)=0) ;
*--- annotateここから ;
function = "text" ;
label = put(GRP,best.) ;
y1space = "datavalue" ;
y1 = ID ;
x1space = "graphpercent" ;
x1 = 90 ;
textcolor = "black" ;
textweight = "normal" ;
anchor = "right";

cards;
1 2 3 4 5 6 7 8 9 10
;
run ;
*** padで右側を空けてannotateデータセットを出力 ;
proc sgplot data=aaa pad=(right=25%) sganno=aaa ;
hbar ID / response=VAL ;
run ;

結果は以下になります。赤枠で囲まれた部分がSGANNOオプションで出力したGRPの値です。
SG_Anno.png
Annotateは有用な機能ですので他のオプションも随時紹介したいと思います。

スポンサーサイト

Posted on 2014/01/30 Thu. 01:04 [edit]

CM: 0
TB: 0

0129

SQLプロシジャのcount distinctでユニークなオブザベーション数をカウントする  

前回のメモでINTO句の紹介をしましたが、そこで使ったcount関数についてもメモしておきます。count(distinct 変数)で、指定された変数のユニークなオブザベーション数をカウントしてくれます。これは非常に便利で、被験者ごとに複数レコードを持つ場合に各投与群の例数をカウントする際などに威力を発揮します。SQLを使用しない場合は、SORTプロシジャのnodupkeyで重複レコードを削除した後にMEANSプロシジャ等で結果をデータセットに吐き出すといった面倒なステップを踏むことになりますが、この機能を使用するとわずか一行で処理が終わってしまいます。

IDが重複するレコードを持つデータセットを作成して各投与群の例数をカウントします。
*** 被験者IDと投与群のみのデータ作成 ;
data DUP ;
do I = 1 to 5 ;
SUBJID = put(I,Z3.) ;
TRT01AN = rantbl(1000,1/2,1/2) ;
output ; output ;
end ;
drop I ;
run ;
*** count distinctでユニークなオブザベーション数をカウントする ;
proc sql ;
select TRT01AN, count(distinct SUBJID) as _N from DUP group by TRT01AN ;
quit ;

データセットと結果は以下になります。1群目が2例、2群目が3例となり、正しく計算されています。
SQL_count_distinct2.png
SQL_count_distinct_result.png

Posted on 2014/01/29 Wed. 00:24 [edit]

CM: 0
TB: 0

0128

SQLプロシジャのInto句による複数列・複数行のマクロ変数への取り込み   

何かと便利なSQLプロシジャのINTO句ですが、複数列・複数行のデータをまとめてマクロ変数に格納する方法をメモしておきます。医薬品開発では、投与群の例数を格納しておいて、パーセント算出時の分母として使用する際なんかに便利かと思います。

まずはデータを作成します。
*** 被験者IDと投与群のみのデータ作成 ;
data ADSL_DUM ;
do I = 1 to 10 ;
SUBJID = put(I,Z3.) ;
TRT01AN = rantbl(1000,1/2,1/2) ;
output ;
end ;
drop I ;
run ;

作成されたデータセットは以下になります。
SQL_Into

続いてINTO句で各投与群のコードと例数を格納します。ハイフン「-」で各オブザベーション、カンマ「,」で各列を区別してそれぞれのマクロ変数に格納します。各オブザベーションの値をマクロ変数に格納する場合は、変数名の最後の数字を連番にしたマクロ変数名で作成しておく必要があります。
*** Into句による投与群と例数の複数列のマクロ変数への取り込み ;
proc sql noprint ;
select TRT01AN, count(distinct SUBJID) into: _G1-:_G2, :_N1-:_N2
from ADSL_DUM group by TRT01AN ;
quit ;
*** マクロ変数の確認 ;
%put *** &_G1: &_N1 *** ;
%put *** &_G2: &_N2 *** ;

%putステートメントの結果は以下になります。
SQL_Into_2.png

各投与群のコードと例数が格納されていることが確認できます。INTO句はこの他にも様々な場面で活躍してくれますのでこれからもどんどん使いたいと思います。

Posted on 2014/01/28 Tue. 23:57 [edit]

CM: 0
TB: 0

0126

SGプロシジャのgroupdisplayオプション  

SGプロシジャのgroupdisplayオプションを紹介します。
例えば、棒グラフなどで縦に積んで帯グラフにしたいか、横に並べたいかを制御できます。
groupdisplay=stack|clusterでそれぞれ制御します。

ここでは、車種ごとの街中の燃費の平均値をメーカーの地域間で比較しており、group変数には
地域を指定しています。
title "MPG(City) by Type" ;
*** GROUPDISPLAY= STACK | CLUSTER ;
*** 1. STACK ;
proc sgplot data=sashelp.cars ;
vbar TYPE / response=MPG_City group=origin groupdisplay=stack
stat=mean dataskin=sheen ;
format MPG_City 8.1 ;
run ;
*** 2. CLUSTER ;
proc sgplot data=sashelp.cars ;
vbar TYPE / response=MPG_City group=origin groupdisplay=cluster
stat=mean dataskin=sheen datalabel ;
format MPG_City 8.1 ;
run ;
title ;

結果は以下になります。
①groupdisplay=stack
groupdisplay_1
②groupdisplay=cluster
groupdisplay_2
用途によって使い分けることができるので重宝しそうです。

Posted on 2014/01/26 Sun. 23:12 [edit]

CM: 0
TB: 0

0121

call execute  

call executeの使用例を一つ紹介します。
call executeは、プログラム自体をデータの文字列を用いて自動生成する機能です。
詳細についてはもう少し丁寧な説明が必要ですが、要するに
「自分でプログラムを書くよりもデータセットに格納されている文字列をそのまま
プログラムに使用したいときに使う機能」
と言えるかもしれません。処理の流れは以下になります。

DATAステップでcall execute用のステートメントを生成
⇒入力スタックに格納
⇒DATAステップの終了
⇒入力スタックに格納されているプログラムを実行

実際にコードを見てみましょう。以下では、call executeを用いて、
sashelp.classとsashelp.carsをproc printで出力するプログラムを
生成し、DATAステップ終了後に実行するプログラムです。

*** libnameとデータセット名 ;
data _DTLIST ;
length LIB DSNAME $8. ;
input LIB DSNAME $ ;
cards;
sashelp class
sashelp cars
;
run ;
*** call executeによる_DSLISTのデータセットを順番に出力するプログラム ;
data _null_ ;
set _DTLIST ;
*--- libname.datasetnameの文字列を作成 ;
call execute("proc print data="||compress(LIB)||"."||compress(DSNAME)||"; run ;") ;
run ;

ログ画面を見てみましょう。入力スタックにproc printの実行プログラムが
格納され、DATAステップ完了後に実行されていることが確認できます。
結果は上記データセットがアウトプット画面に出力されます。

call_execute.png

Posted on 2014/01/21 Tue. 00:40 [edit]

CM: 0
TB: 0

0118

ODS tagsets.ExcelXP  

Excelにデータや帳票を出力できるods tagsets.ExcelXPを使用してみます。
CARSデータセットのメーカーごとの車種一覧をシートごとに出力します。
*** メーカーごとの車種一覧をシートごとに出力する ;
*** 目次シートの作成,フィルター,ウィンドウの固定,シートはby変数ごと,カラムの幅等を指定 ;
ods listing close ;
ods tagsets.ExcelXP file="C:\temp\Output_Cars.xls"
style=styles.statistical
options(
contents = 'yes'
autofilter = 'all'
frozen_headers = '2'
frozen_rowheaders = '1'
sheet_interval = 'bygroup'
sheet_label = ' '
suppress_bylines = 'no'
fittopage = 'yes'
absolute_column_width = '30,10,10,10,10,10,10,10,10,10,10,10,10,10') ;
*** データをメーカーごとに出力 ;
proc print data=sashelp.CARS noobs label ;
by MAKE ;
run ;
ods tagsets.ExcelXP close ;
ods listing ;

出力イメージは以下になります。出来上がるファイルはxmlなので純粋なエクセルファイルに変換するには
名前を付けて保存してください。
①目次
excelxp_1.png

②Audiのシート
excelxp_2.png

ちなみにhelpを見たい場合は下記を実行すればログファイルにhelpが出力されます。
*** helpをログ画面に出力 ;
ods tagsets.ExcelXP file='test.xml' options(doc='help') ;
ods tagsets.ExcelXP close ;


Posted on 2014/01/18 Sat. 00:28 [edit]

CM: 0
TB: 0

0115

fetchobs関数  

入社1年目(約10年前)に上司が使っていて、未だに完全に理解できていないfetch関数とfetchobs関数についてメモを残しておきます。fetch関数もfetchobs関数も、DATAステップから異なるデータセットを読み込んでそのオブザベーションに対して処理を行うことができる関数です。複数のデータセットから情報を取得する必要がある際に便利な関数です。
fetch関数:データセットの次のオブザベーションを読み込みます。fetch(dsid)で使用します。dsidはデータセットの番号で、open関数で取得します。。
fetchobs関数:データセットの指定したオブザベーションを読み込みます。fetch(dsid,i)で使用します。iはオブザベーションの番号を指定します。

ここでは、fetchobs関数を使用して、classデータセットの「トーマス」という生徒が、欲しい製品が「パソコン」で、それぞれ別のデータセットから情報を取得する方法を例示します。
%let NAME   = %str(トーマス) ; *--- 名前
%let SHOHIN = %str(パソコン) ; *--- 欲しい製品 ;
*** 製品のリスト ;
data _LIST ;
input NO PRODUCT $ PRICE yen10. ;
cards;
1 冷蔵庫 \123,000
2 パソコン \98,000
3 タブレット \39,800
4 デスク \60,000
5 掃除機 \29,800
6 エアコン \230,000
;
run ;
*** 名前と欲しい製品データを各データセットから抽出 ;
data TEST ;
*--- 外から読み込むデータセットに存在する変数を定義 ;
length NAME $12 SEX $4 AGE HEIGHT WEIGHT NO 8 PRODUCT $ 8 PRICE 8 ;
_DSID = open("sashelp.class") ; *--- データセットID取得 ;
_NOBS = attrn(_DSID,"nobs") ; *--- オブザベーション数の取得 ;
call set(_DSID) ; *--- 変数のひも付けのおまじない ;
*--- classデータセットからトーマスのデータを抽出 ;
do I = 1 to _NOBS ;
rc = fetchobs(_DSID, I) ;
if NAME = "&NAME" then do ;
_NAME = NAME ;
_AGE = AGE ;
_HGT = HEIGHT ;
_WGT = WEIGHT ;
end ;
end ;
_DSID = open("_LIST") ; *--- データセットID取得(製品リストのデータ) ;
_NOBS = attrn(_DSID,"nobs") ; *--- オブザベーション数の取得 ;
call set(_DSID) ; *--- 変数のひも付けのおまじない ;
*--- トーマスの欲しい製品のパソコンのデータを抽出 ;
do J = 1 to _NOBS ;
rc=fetchobs(_DSID,J) ;
if PRODUCT = "&SHOHIN" then do ;
_NO = NO ;
_PRODUCT = PRODUCT ;
_PRICE = PRICE ;
end ;
end ;
keep _NAME _AGE _HGT _WGT _NO _PRODUCT _PRICE ;
run ;
proc print ; run ;

結果を見てみましょう。classデータセットからトーマス君の情報、_LISTデータセットからパソコンの番号と値段を取得しています。
fetchobs

まだまだ便利な使い方があるはずなので引き続き調査します。

Posted on 2014/01/15 Wed. 01:11 [edit]

CM: 0
TB: 0

0113

SGPLOTプロシジャのdataskinオプション  

SASにはSGプロシジャという高品質なグラフを作成することができるプロシジャが用意されていますが、棒グラフの見た目を綺麗に出力してくれるdataskinオプションを紹介します。sgplotプロシジャのvlineステートメントで棒グラフを作成し、dataskinオプションで見た目をいくつか変えて出力してみます。

dataskinオプションの種類:
CRISP | GLOSS | MATTE | PRESSED | SHEEN

使用例:
データセットCARSから、車のタイプごとの燃費(Miles per Gallon)を棒グラフで出力します。
title "MPG(City) by Type" ;
*** sheen ;
proc sgplot data=sashelp.cars ;
vbar TYPE / response=MPG_City group=TYPE stat=mean datalabel
dataskin=sheen ;
format MPG_City 8.1 ;
run ;
*** gloss ;
proc sgplot data=sashelp.cars ;
vbar TYPE / response=MPG_City group=TYPE stat=mean datalabel
dataskin=gloss ;
format MPG_City 8.1 ;
run ;
*** matte ;
proc sgplot data=sashelp.cars ;
vbar TYPE / response=MPG_City group=TYPE stat=mean datalabel
dataskin=matte ;
format MPG_City 8.1 ;
run ;
title ;

結果は以下になります。テストデータと言えど、やはりハイブリッドの燃費は抜群ですね。
①dataskin=sheen
dataskin.png
②dataskin=gloss
dataskin1.png
③dataskin=matte
dataskin2.png

SGプロシジャが登場してからSASのグラフも随分綺麗になりましたが、さらにその幅が広がった気がします。

Posted on 2014/01/13 Mon. 23:43 [edit]

CM: 0
TB: 0

0113

VNAME関数  

とある仕事でVNAME関数の存在を知ったのでメモを残しておきます。

VNAME関数とは、指定した変数がデータセットの中に存在するかどうかを確認できる関数です。
vnamex("変数名")と記述することで、変数が存在する場合は変数名、存在しない場合はブランクを返します。

サンプルプログラム:
data _VNAMEX ;
   x=1 ;
   y=vnamex("x") ; *--- 存在する ;
   z=vnamex("D_NASHI") ; *--- 存在しない ;
run ;
proc print data=_VNAMEX ; run ;

アウトプット画面には、存在する変数はその変数名、存在しない変数についてはブランクとなっていることが確認できます。
アウトプット画面:
アウトプット画面

注意点ですが、変数が存在しない場合、何故かログに引数が適切でない旨が出力されてしまいます。テクサポのサンプルPGMを流しても出るのでバグの可能性があります。
VNAME関数(テクニカルサポート)
ログ画面:
ログ画面

ちなみに、VNAME関数が必要となる場面は業種によっても異なるかと思いますが、我々のような医薬品開発においては、お上に医薬品の承認申請を行う際、それまでに実施した臨床試験データの統合が必要となる場合があり、試験によって収集している情報が異なるため、この試験ではこの変数は作成していなかった(つまり収集していなかった)ことを確認できる有用な関数だと感じた次第です。

Posted on 2014/01/13 Mon. 18:03 [edit]

CM: 0
TB: 0

プロフィール

最新記事

最新コメント

最新トラックバック

月別アーカイブ

カテゴリ

訪れた人

▲Page top

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。