我有一堆字符变量,我需要从大型数据集中进行整理。不需要的变量都具有相同或全部缺失的条目(这意味着我希望在进一步处理数据之前将这些条目从数据集中删除)。数据集非常大,所以这不能手动完成,我会做很多次,所以我试图创建一个宏,这将做到这一点。我使用以下代码创建了包含所有字符变量的列表宏变量(我的部分数据不同,但我使用相同类型的代码):
data test;
input Obs ID Age;
datalines;
1 2 3
2 2 1
3 2 2
4 3 1
5 3 2
6 3 3
7 4 1
8 4 2
run;
proc contents
data = test
noprint
out = test_info(keep=name);
run;
proc sql noprint;
select name into : testvarlist separated by ' ' from test_info;
quit;
我的想法是只使用数据步骤从原始数据集中删除此变量列表。现在,问题是我需要遍历每个变量,并确定该变量的观察是否完全相同。我的想法是创建一个循环遍历所有变量的宏,并为每个变量计算条目的出现次数。由于此表的长度等于唯一条目的数量,我知道如果表的长度为1,则应删除该变量。到目前为止,我的尝试是以下代码:
%macro ListScanner (org_list);
%local i next_name name_list;
%let name_list = &org_list;
%let i=1;
%do %while (%scan(&name_list, &i) ne );
%let next_name = %scan(&name_list, &i);
%put &next_name;
proc sql;
create table char_occurrences as
select &next_name, count(*) as numberofoccurrences
from &name_list group by &next_name;
select count(*) as countrec from char_occurrences;
quit;
%if countrec = 1 %then %do;
proc sql;
delete &next_name from &org_list;
quit;
%end;
%let i = %eval(&i + 1);
%end;
%mend;
%ListScanner(org_list = &testvarlist);
虽然我遇到了语法错误,但是由于我的实际数据无法正确读取数据,因此我遇到了其他类型的问题,但我一步一步。我想我可能会使事情过于复杂,所以如果有人有更简单的解决方案,或者可以看到可能出错的地方,我会非常感激。
答案 0 :(得分:0)
就您的具体初步问题而言,这是相当简单的。假设&testvarlist
是包含您感兴趣的变量的宏变量,并在have
中创建一些测试数据:
%let testvarlist=x y z;
data have;
call streaminit(7);
do id = 1 to 1e6;
x = floor(rand('Uniform')*10);
y = floor(rand('Uniform')*10);
z = floor(rand('Uniform')*10);
if x=0 and y=4 and z=7 then call missing(of x y z);
output;
end;
run;
data want fordel;
set have;
if min(of &testvarlist.) = max(of &testvarlist.)
and (cmiss(of &testvarlist.)=0 or missing(min(of &testvarlist.)))
then output fordel;
else output want;
run;
这不是特别低效,但在评论中引用的肯定有更好的方法。
答案 1 :(得分:0)
有很多方法可以做到这一点。 但是,让我们来看看你遇到的问题。
首先循环遍历以空格分隔的名称列表,更容易让%do循环为您增加索引变量。使用countw()
函数查找上限。
%do i=1 %to %sysfunc(countw(&name_list,%str( )));
%let next_name = %scan(&name_list,&i,%str( ));
...
%end;
您的SQL代码中的输入数据集在哪里?在宏定义中添加另一个参数。您想在哪里编写没有空列的数据集?所以也许是另一个参数。
%macro ListScanner (dsname , out, name_list);
%local i next_name sep drop_list ;
第三,您可以使用单个查询一次统计所有变量。只需使用count( distinct xxxx )
代替group by
。
proc sql noprint;
create table counts as
select
%let sep=;
%do i=1 %to %sysfunc(countw(&name_list,%str( )));
%let next_name = %scan(&name_list,&i,%str( ));
&sep. count(distinct &next_name) as &next_name
%let sep=,;
%end;
from &dsname
;
quit;
因此,这将获得一个观察数据集。您可以使用PROC TRANSPOSE将每个变量转换为一个观察值。
proc transpose data=counts out=counts_tall ;
var _all_;
run;
现在您可以查询该表以查找具有0个非缺失值的列的名称。
proc sql noprint ;
select _name_ into :drop_list separated by ' '
from counts_tall
where col1=0
;
quit;
现在您可以使用新的DROP_LIST
宏变量。
data &out ;
set &dsname ;
drop &drop_list;
run;
所以现在剩下的就是自我清理。
proc delete data=counts counts_tall ;
run;
%mend;