不存在的lob值_一日看尽长安花——缺失值(Missing Data)识别和定位的SAS实现

9823a224cdacdff4af5b6dc4a3f378f2.png

一、场景

在经历了长达数十月甚至数年之久的临床研究终于完成了最后一例受试者随访资料的搜集,希望的曙光就在眼前,仿佛看见了下面这种整整齐齐的数据在向你招手,似乎可以一天出图表,两天写报告......

f248d3bcb7faf86c2c980c3b0fe1a7f3.png
数据集class

然而现实中的数据可能是下面这样的

b0e06a6b9fa439cb870780beb936d5b9.png
数据集classmis

查找缺失值的过程是很重要的,有些与主要研究目的不相关的数据缺失(如电话号码、通讯地址、邮政编码等)可能并不重要,但如果是重要资料(如解释变量或被解释变量的缺失),无论是否后期继续对其进行方法学处理(如末次结转或其他各种结转方法、线性插值、多重填补等),首要的一步是先查找是否存在缺失值,如果有,这些缺失值它们又定位在哪里?


二、查找是否存在缺失值

为了方便我们直接用SAS自带的数据集class(图1),并描述数据集class的内容

/*利用SAS自带的数据集sashelp.class*/
data class;
	set sashelp.class;
run;

/*描述数据集class的内容*/
proc contents data=class;
run;

a0591e94dfe52eba2f351d3c0b142388.png
数据集共包含19个观测和5个变量,分别是Name, sex, age, height, weight

利用proc means和proc freq语句分别查找所有数值变量和字符变量的缺失值

title "Missing value check for the patients data set";/*输出结果增加标题*/
proc means data=class n nmiss;/*也可增加var语句选择感兴趣的变量*/
run;
proc format;
	value $misscnt ' ' = 'Missing'
		     other = 'Nonmissing';
run;
proc freq data=class;
	tables _character_ / nocum missing;/*table语句后也可选择感兴趣的变量*/
	format _character_ $misscnt.;
run;

2bd2307658a912fba674aeb3e368649b.png
结果显示数据集是完整的

在数据集class的基础上通过调用符合正态分布的随机数创建含有缺失数据的数据集classmis

data classmis;
	set class;
	if rannor(20200718) <0 then call missing(sex);
	if rannor(20200718) <0 then call missing(age);
	if rannor(20200718) <0 then call missing(height);
	if rannor(20200718) <0 then call missing(weight);
run;

结果如图2所示,然后再次调用刚才的proc means和proc freq看看结果如何

title "Missing value check for the patients data set";
proc means data=classmis n nmiss;
run;
proc freq data=classmis;
	tables _character_ / nocum missing;
	format _character_ $misscnt.;
run;

56f51c903420ef638933701e5fa55041.png

proc means的结果显示在数值变量中,age有11个缺失值,height有12个缺失值,weight有9个缺失值;proc freq的结果显示在字符变量中,name没有缺失值,sex有8个缺失值。


上面通过proc means和proc freq过程的目的是回答“是否存在?”以及“存在多少?”缺失值这两个问题,这个过程可以定性(是否存在)以及定量(存在多少)。这个问题的回答有以下两种情况:

  1. 如果不存在缺失值,则查找缺失值的过程结束(不要高兴太早,还有异常值等其他可能的坑等着填);
  2. 如果存在缺失值,则视数据集规模而定,如果像上面的class例子只有19个观测,则完全可以肉眼定位。但是通常情况,我们还是当自己是盲人吧,需要定位这些缺失值在哪里。

三、定位缺失值

继续使用前面的数据集classmis,确定缺失值的位置。

nunndata _null_; 
	set classmis end=last;
file print; 

if missing(sex) then do;
	put "Missing sex  for ID " name;
	N_sex + 1;
end;

if missing(age) then do;
	put "Missing age for ID " name;
	N_age + 1;
end;

if missing(Height) then do;
	put "Missing height for ID " name;
	N_Height + 1;
end;

if missing(Weight) then do;
	put "Missing weight for ID " name;
	N_Weight + 1;
end;

if last then 
		put // "Summary of missing values" /
		25*'-' /
		"Number of missing sex = " N_sex /
		"Number of missing age = " N_age /
		"Number of missing height = " N_Height /
		"Number of missing weight = " N_Weight;
run;

17d2a28c23a93e2292e3ba589d872dff.png
输出结果窗口通过name来定位,1-3行表示Alfred的sex,height和weight缺失;4-6行表示Alice的age,height和weight缺失

1ed3a135c959dbaaf9e35dfc2775acc9.png
缺失值汇总结果与第一步中proc means和proc freq过程步单独的结果一致

3928cb8128aa24984aa96b40767750ee.png
数据集class2,将上述代码data步的_null_修改为class2,体会累加的机制在该过程中所起到的作用

四、利用数组识别并定位多个变量的缺失值

上面的代码尽管可以详细的查找是否存在缺失值以及定位缺失数据,但是在实际应用中更推荐以下由array数组和do循环构成的方法,由于采用了SAS特殊名称列表_numeric_和_character_所以无需修改,使用时将数据集名替换即可。以数据集patients为例,执行后将会在数据集中创建新变量"mvarlist",列出每条观测的缺失值清单,以便数据管理人员核查确认。

bcbfcd586aea7b9e4fa84303b9be230a.png
mvarlist(最右侧)列出每一个观测的确实数据(如所有观测均缺少不良事件AE[adverse event]数据,观测6缺少除AE外的gender数据,观测7缺少除AE外的visit数据)
data patients;
	set clean.patients;
	length mvarlist $ 300;
	array num{*} _numeric_;
	array char{*} _character_;
	do n=1 to dim(num);
		if missing(num{n}) then
		mvarlist=catx("," ,mvarlist,vname(num{n}));
	end;
	do c=1 to dim(char);
		if missing(char{c}) then mvarlist=catx(",", mvarlist,vname(char{c}));
	end;
run;

如果在数据集patients中体验以上的数组代码可以参考以下附件:

以下为数据集patients的内容,复制粘贴虚线内数据至桌面创建txt文档,命名为patients。
---------------------------
001M11/11/1998 88140 80  10
002F11/13/1998 84120 78  X0
003X10/21/1998 68190100  31
004F01/01/1999101200120  5A
XX5M05/07/1998 68120 80  10
006 06/15/1999 72102 68  61
007M08/32/1998 88148102   0
   M11/11/1998 90190100   0
008F08/08/1998210        70
009M09/25/1999 86240180  41
010f10/19/1999    40120  10
011M13/13/1998 68300 20  41
012M10/12/98   60122 74   0
013208/23/1999 74108 64   1
014M02/02/1999 22130 90   1
002F11/13/1998 84120 78  X0
003M11/12/1999 58112 74   0
015F           82148 88  31
017F04/05/1999208    84  20
019M06/07/1999 58118 70   0
123M15/12/1999 60        10
321F          900400200  51
020F99/99/9999 10 20  8   0
022M10/10/1999 48114 82  21
023f12/31/1998 22 34 78   0
024F11/09/199876 120 80  10
025M01/01/1999 74102 68  51
027FNOTAVAIL  NA 166106  70
028F03/28/1998 66150 90  30
029M05/15/1998           41
006F07/07/1999 82148 84  10
------------END------------
/*创建永久数据库clean,并从桌面将数据集patients导入其中*/
libname clean 'C:Users123Desktopclean';
data clean.patients;
	infile 'C:Users123Desktoppatients.txt'
	 lrecl=30 truncover;
input @1 Patno $3. @4 gender $1.
@5 Visit mmddyy10.
@15 HR 3.
@18 SBP 3.
@21 DBP 3.
@24 Dx $3.
@27 AE $1.;
LABEL Patno = "Patient Number"
Gender = "Gender"
Visit = "Visit Date"
HR = "Heart Rate"
SBP = "Systolic Blood Pressure"
DBP = "Diastolic Blood Pressure"
Dx = "Diagnosis Code"
AE = "Adverse Event?";
format visit mmddyy10.;
run;

参考资料

  1. Ron Cody,Cody's data cleaning techniques using SAS, second edition
  2. 谷鸿秋,SAS编程演义
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值