小编是医药行业的,所以小编的推送涉及的知识也多为SAS在临床研究中的运行及SAS数据清洗等相关的程序,在临床试验中,很多SOP相对完善的公司,出于对数据质量的把控,一般项目都会采用double programming,一个项目会有多个人参与,写俩份独立的程序,最终会对结果进行compare,今天的主题就是数据的compare.
一个过程步,这个过程步就是proc compare,关于Proc compare的用法,在实际的运用中其实比较单一。 这个过程步呢,是有一些强大的,比对速度也很快。小编有见了好几个公司的程序,数据的compare也都是采用这个过程步,实现的过程也是大同小异。想必这个过程步应该是行业内部通用的一种方式。用法比较简单,小编在这里仅举一个常用的例子。
例子
上图中,小编将过程步放在ods中,可以实现一个比对结果的输出。小编这里输出的rtf,通过ods还可以输出Excel,html等,都是比较快捷和方便的。我有一个习惯,在做compare前喜欢sort一下,在看这个compare中的 ID 参数后面的变量很重要,他作为你数据集中每条记录的识别标志。直接影响比对的结果。compare里面的一些选项,在这里借用一本书上的一部分来展现。
其实,小编觉得很多可能用不到,但是小编还是列在这个,另外贴一个链接网上看到一个实例比较好的一个关于compare的例子(https://www.sascrunch.com/proc-compare.html)。
今天要做一回彻头彻尾的拿来主义~其实这个参数这么多,能用到的比较常用的大概也就是小编贴的自己的那个实例代码的截图。
小编曾长期从事偏数据清理的SAS programmer,与小编对接的(提需求)大多是DM同事,在数据清理的过程中,经常会遇到数据compare,将以几个简单的需求和例子来讲解与提供几种不一样的数据compare的方式.
以一个事例来说一下SQL中的except与Union all的用法
随便举一个例子(线下程序跑出的query,这次和上次比对,标记出那些是新出的,那些是已经出国的query)
data old;/*模拟前一次query数据集*/
set Sashelp.class;
if_n_<8;
run;
data Now;/*模拟本次query数据集*/
set Sashelp.class;
run;
proc sql noprint;
createtable new_obs as
(select * from Now) except (select * from old);
createtable old_obs as
(select * from Now) except (select * from new_obs);
createtableoutput as
select * ,"UPDATA" as Comments length=20 from new_obs
union all
select *,"NO Change" as Comments length=20 from old_obs;
quit
这个用法其实很简单,不知道正在阅读的你在日常编程中,有没有使用它呢,可以快捷的找出俩个数据集相同的记录/不太的记录/或某些变量相同的记录等等等....union all其实在这里就相当一个数据的set过程,数据集的追加。数据集的追加和可以使用下面的 proc append过程步
(proc append base=a data=b;run;)
结果
这种方式同样有一定局限性,其实都是根据相应的需求而写的,就看你具体的需求是什么,然后选用合适的方式,接下来还有俩种方式...
以一个事例来说一下transpose在此处的妙用...
在临床试验中,我们经常会遇到数据库锁库后又开库,修改数据,补录数据等情况,在这个时候呢,一些比较严谨的DM都会要求programmer进行数据的compare,找出那些数据点修改了,变化了等等。
data old;/*模拟之前数据*/
set Sashelp.class;
if _n_<8;
run;
data Now;/*模拟本次数据*/
set Sashelp.class;
if _N_=4 then sex="NA";
run;
proc sort data=old out=old ;by name ;quit ;
proc transpose data=old out=tran_old(where=(_NAME_ not in ("Name")) ) prefix=old ;
by name ;
var _all_;
run;
proc sort data=Now out=Now ;by name ;quit ;
proc transpose data=Now out=tran_Now(where=(_NAME_ not in ("Name")) ) prefix=Now ;
by name ;
var _all_;
run;
proc sort data=tran_Now out=tran_Now ;by name _Name_ ;quit;
proc sort data=tran_old out=tran_old ;by name _Name_ ;quit;
data output;
merge tran_Now tran_old;
by name _Name_;
old1=strip(old1);
Now1=strip(Now1);
if old1^=Now1;
label old1="先前结果" Now1="本次结果";
run;
结果
在这里其实可以做的更好一些更精确一些,比如标记出那些记录是新增,那些记录是修改,那些记录是delete掉的...在见下面的那张图,这个是小编曾经写过的一个程序出的比对结果,相对来说,信息都是比较完善的(数据来源,记录状态)都能很明确的知道这个条记的这个数据点变化的状态...
看完上的一个图,在来看这个图,当时小编采用了2种方式写比对,第一种就是transpose,出的结果在上面,另外一种出的结果在下面,下面的这个,以整行记录作为维度来的,那个点发生了变化就以颜色在改点上打上颜色,如果整行都变化则都标记上颜色,同时也会有数据来源于记录状态这个点(见下图,出于保密,部分内容打上了码,但不妨碍看颜色)...
上面最后俩张图是怎么产生的呢,原理是这样的:先将俩次数据left join 到一起,做俩次left join (分别以俩次做主集),然后将生成的俩个数据集set到一起,按照一定顺序sort,接着就是report过程,通过print /noprint 显示与隐藏一些需要的变量,利用compute来参与运算,或逻辑表达。这里仅列以小部分,这个Macro代码太多,而且是针对项目进行写的,所有就不贴完整的代码,仅提供编程的思路...我想思路比程序更重要.
今天其实主要提供的是一种解决问题的思路,与程序实现的方法,代码不太多,自我感觉已经差不多涵盖了好几种比对方式,小编目前用到的也就这几种,如果有好的建议,或者好的思路欢迎留言~不好的建议不好的思路也欢迎留言~其实程序实现的方法没有好与不好之分,只有合适与不合适之说...