最近手头有一个回顾性研究的项目,需要从已完成的项目中抽取部分受试者数据进行新的其他分析。统计师将随机抽取的受试者ID通过EXCEL文件发给我们,我们需要将EXCEL中的受试者ID信息导入SAS,再与之前项目的数据集拼接,获取当前这个项目入组受试者。这篇文章分享一下,我们在将EXCEL时间数据导入SAS时遇到问题。
先看一下,统计师传过来的EXCEL文件的内容。EXCEL中除了受试者的ID (SUBJID)外,还有5个分析访视的日期。这些日期变量有一个特征,前两个日期变量是没有缺失值的,后三个是有缺失值的。
EXCEL文件导入SAS,需要使用Import
过程步,直接看下导入结果:
proc import datafile = "&path/subjectlist.xlsx" out = subj dbms = xlsx replace;
run;
从导入结果看,无缺失值的时间变量直接转换成带有时间格式的数值变量,而带有缺失值的变量,直接转换成字符变量。为什么会出现这种情况呢?
事实上,Excel中的日期和时间本质上是以数值的形式存储在单元格里,而日期是数值的“显示格式”。我们可以在设置单元格属性中,查看单元格内存储的原始值。例如,10Dec2009
这个显示形式对应的是数字40157
。
同时,SAS的Import
过程步会将EXCEL中的时间变量以ANYDTDTMw.
的格式读入。但这里有一个注意点,时间变量中不能以点号(.
)作为分隔符,否则SAS会判定这不是有效的时间变量(具体参考,SAS官方文档:ANYDTDTMw. )。于是,这就造成EXCEL中有缺失值的时间变量,以原始值的形式转换成SAS字符变量。
既然这是SAS的导入机制造成的,那我们只好在导入EXCEL数据之后,单独对数据进行处理,将字符变量转换成带有日期格式的数值变量。如以下示例代码:
proc import datafile = "&path/subjectlist.xlsx" dbms = xlsx replace
out = subj(rename=(month_6 = m6 month_12 = m12 month_24 = m24)) ;
run;
data subjid;
set subj;
format MONTH_6 MONTH_12 MONTH_24 date9.;
MONTH_6 = input(m6, best.);
MONTH_12 = input(m12, best.);
MONTH_24 = input(m24, best.);
drop m6 m12 m24;
run;
经过这样的处理,数值看起来转换成功了。但仔细观察以及与EXCEL原始文件对比后发现,处理后的时间变量与EXCEL中的时间变量不一致。以Month_6第一行数据为例,这两个时间变量差了近60年。
这究竟是什么原因呢?原来,SAS跟EXCEL一样,时间变量的显示也是通过存储具体的数值来实现的,但两个软件选取的参考时间不同。下面举一个简单的例子来说明,时间2021-08-21
在EXCEL中对应数字是44429
;
而在SAS中,时间2021-08-21
对应的数字是22513
。
也就是说,为显示的相同的时间,EXCEL与SAS存储的数值差为是44429-22513= 21916
。因为EXCEL和SAS中选定日期参照时间始终固定不变,所以为显示相同的时间,两者存储的数值差值也保持不变,即,EXCEL数值始终比SAS数值多21916
。
于是,EXCEL中的时间变量因有缺失值,因而导入SAS中无法直接转换成数值型时间变量的问题,可以通过EXCEL存储的数值减去21916
后,再转换成SAS数值型时间变量来解决。开头介绍的EXCEL文件,经这样处理后,导入SAS数据集中的时间变量已显示正常。
proc import datafile = "&path/subjectlist.xlsx" dbms = xlsx replace
out = subj(rename=(month_6 = m6 month_12 = m12 month_24 = m24)) ;
run;
data subjid;
set subj;
format MONTH_6 MONTH_12 MONTH_24 date9.;
MONTH_6 = input(m6, best.) - 21916;
MONTH_12 = input(m12, best.) - 21916;
MONTH_24 = input(m24, best.) - 21916;
drop m6 m12 m24;
run;
若有疑问,欢迎评论区交流!