数据预处理
1.首先清空output
dm 'log;clear;output;clear;odsresults;clear';
options mprint nodate pageno=1;
%SYSMSTORECLEAR;
LIBNAME homework 'dir path'; *C:\Users\doc;
%include "dir path\Format.sas"; *载入format代码;
*载入上一步文件夹里的data.sas7bdat到work.dat(也许运行会更快);
*无论如何不要对源数据进行操作;
data dat1;
set homework.data;
run;
2.制定纳入排除标准
*Exclusion & inclusion criteria;
* =, ~=, lt, gt, le, ge, in, not in;
data anal;
set dat1;
age > 21
if age > 21;
** Exclude status = 2;
if status ~= 2;
If case = 0 then delete;
if seq_adm1 in (0,1);
if seq_adm2 not in (0,1);
if OS ~= .;
3.打标签,重新分组
* 格式可参考数据库的codebook;
proc format;
value gender 1 = "Male"
0 = "Female";
value hist 1= "Yes"
0 = "No";
value $ char 'a1', 'a2','a3' = 'A'
'b1', 'b2','b3' = 'B' ;
value order 1 = 'A1'
2 = 'A2'
0, 9, 3-4 = 'Else';
run;
data whas500;
set hw.whas500;
*重新分组 treatment 1-5 分为 surgery 1,0 也可使用and, or等逻辑运算;
if treatment in (1 3) then surgery = 1;
else if treatment in (2 4 5) then surgery = 0;
*替换na等;
if age in (0, 999 ,998) then age_year=.;
else TUMOR_SIZE_MM = TUMOR_SIZE;
*替换status编码;
if status = 0 then censor = 1; else censor = 0;
proc format ;
gender gender.
cvd hist.
label gender="Gender"
age = "Age (year)"
;
run;
Macro制作报表的一些思路
个人之谈,不一定是最优方法 以生存分析为例,使用macro制作下表 (主要说明解决思路,不用完全照抄)
%macro make_table1(data,time,censor,catevar,contvar,ngroups);
**主体;
%mend;
** 如下制作表格:
** 输入分别为data,survival time,cencer indicator,一串分类变量,一串连续变量,连续变量分为几组;
%make_table1(whas500,timeyr,fstat(0),gender cvd afb sho av3 miord mitype,age hr sysbp diasbp bmi,4);
整体思路:
1.统一数据格式
首先输入数据有continuous和categorical variables, 这里为table1,我们需要median survival time 和log-rank test的结果,所以需要将continuous按分位数等分(一般为三等分或四等分). 这里可以使用proc rank, 然后合并所有数据.
- SAS类似于for i in list的方法(in macro):
* list = var1 var2 var3 ...;
* 循环中依次var = var1, var2,...;
%let i=1;
%do %while (%scan(&list, &i) ne );
%let var = %scan(&list, &i);
*循环体;
%let i = %eval(&i + 1);
%end;
2.获取数据
接下来我们想获得表里的这些数据. 直接搜索SAS哪些proc能输出frequency,median survival,log rank test. 方法有很多,但是我发现proc lifetest能输出以上所有结果. 接着我还想把所有结果储存在dataset里方便整理,就要先知道每张表的名字. 这里我直接在sas help里搜索lifetest output. 可以看到The LIFETEST Procedure - Details里有Displayed output和ODS table names. 可以找到如下信息确认需要的表名:
ODS如下,插入proc lifetest里. proc lifetest输出的原表名为CensoredSummary,Quartiles,和HomTests,我将其储存到category,quantiles,testresults方便调用
ODS OUTPUT CensoredSummary = category
Quartiles = quantiles
HomTests = testresults;
-
有时候Result能直接显示表,我们想要导出却不知道表的名字. 这种情况直接右键properties查看Name就行. 除了Name, Template也经常会用到,可以用proc template 修改表格样式.
3.拼接表格整理格式
使用proc sql或data merge. 首先横向拼接freq-median-pvalue这些结果,然后向下拼接不同变量的结果 注意几点: SAS中P-value < 0.001使用的是标签, 使用proc sql会去丢掉标签 使用proc append拼接不同变量的结果,变量长度由第一张表决定. 比如说第一个变量是Age,第二个是gender,就会变成Age,gen. 需要手动设置变量长度.
如何设置不同格式的95%CI, sd等: 在data步用字符串处理: 使用||连接不同字符,compbl()紧密连接(去掉多余空格)
mid = compbl(round(Estimate,.01)||" ("||round(LowerLimit,.01)||","||round(UpperLimit,.01)||")");
这样新变量mid就是"est (lower, upper)"的格式
4.输出好看一点的表
经处理的结果如下, order是我希望的变量顺序,最后不显示.ods rtf file = "table1.rtf";
proc report data=results spanrows;
column order varname varlevel event mid Log_rank _2Log_LR_ ;
define order/ order noprint;
define varname / group 'Variable';
define event /display 'Events,n';
define varlevel / display "Category";
define mid / display "Median Time to Death (95% CI),years" style(column)=[cellwidth=1.5in];
define Log_rank / style(column)={cellwidth=.8in } group "P-value, Log-rank test";
define _2Log_LR_ / style(column)={cellwidth=.8in} group "P-value, Partial likelihood";
title "Table 1 Patients characteristics";
run;
ods rtf close;
以上通过group合并相同单元格并自定义表头名. 另外,如果数据集是没有重复行的,比如: gender下为空,可在proc report中使用:
compute id; *id列,逐行计算;
if variable ne ' ' then
call define('_col_','style','style=[pretext="\brdrt\brdrs\brdrw11 "]');
*实际上就是variable列非空(gender),则添加上框线;
*brdrb下框线,brdrdot点状线...;
endcomp;
另外column使用()可进行表头的层层叠加
column type ('spanned header 1' color cost ) season;
*在column里使用("\brdrb\brdrdot\brdrw5 hearder" A B C)添加下框线;
其它琐碎细节
当连续型变量转换成分类变量,如何保持原有的变量标签(如Age (years))
data _null_;
set &data (obs=1);
call symputx('varlabel',vlabel(&var));
run;
*call symputx获得标签后,存为varlabel, data步新建变量作为最终输出varname = "&varlabel";
数据打过标签,如gender的male和female,希望在varlevel中显示标签(male, female)而不是数字0,1 这里有一个坑,value的label在同一列是相同的. 比如gender是0,1,cvd也是0,1,两表向下合并后会全部显示male, female.
* 在循环中;
data result_tmp;
merge result_tmp _tmp1_ _tmp2_;
varlevel = vvalue(&var);
run;
其余的想起来再补充
完整代码没放出,因为代码很乱没还怎么整理. 这是survival analysis这课因为大家考得很差给的bonus作业. 居然总评才加1.25分,真滴不值.快毕业了想起这回事才整理下. 想要代码可以私戳我.