我有一个数据集,其中每个观察结果是二元指示变量的组合,但不一定是所有可能的组合。我想消除作为其他观察的子集的观察。举个例子,假设我有这三个观察结果:
var1 var2 var3 var4
0 0 1 1
1 0 0 1
0 1 1 1
在这种情况下,我想要消除观察1,因为它是观察的一个子集3.观察2不是其他任何的子集,因此我的输出数据集应包含观察2和3。
在SAS中有一种优雅且最快速的方法吗?到目前为止,我最好的解决方案是使用带有set
选项的第二个point
语句通过数据集进行暴力循环,以查看当前观察是否是任何其他观察的子集,但这些数据集可能变为一旦我开始处理很多变量,我就希望能找到更好的方法。
答案 0 :(得分:3)
首先,一个考虑因素:一行是否可以为所有指标设置1?您应首先检查 - 如果一行确实拥有全部1,那么它将始终是唯一的解决方案。
_POINT_
效率低下,但加载到哈希表中并不是一种非常糟糕的方法。只需加载一个包含二进制指示符CATted字符串的哈希表,然后搜索该表。
首先,使用PROC SORT NODUPKEY
消除完全匹配。除非你有非常多的指标变量,否则这将消除很多行。
然后,按照更“复杂”行位于顶部的顺序对其进行排序,而在底部则不那么复杂。这可能就像创建一个变量一样简单,该变量是二进制指标的总和,并按降序排序;或者如果您的数据显示,可能按特定的指标顺序排序(如果某些指标更有可能存在)。这样做的目的是减少我们搜索的次数;如果可能的匹配位于顶部,我们将更快地保持循环。
最后,使用散列迭代器按照指标变量的降序搜索列表,以查找任何匹配项。
请参阅下面的部分测试示例。我没有验证它是否消除了所有有效消除,但它消除了大约一半的行,这听起来很合理。
data have;
array vars var1-var20;
do _u = 1 to 1e4;
do _t = 1 to dim(Vars);
vars[_t] = round(ranuni(7),1);
end;
complexity = sum(of vars[*]);
indicators = cats(of vars[*]);
output;
end;
drop _:;
run;
proc sort nodupkey data=have;
by indicators;
run;
proc sort data=have;
by descending complexity;
run;
data want;
if _n_ = 1 then do;
format indicators $20.;
call missing(indicators, complexity);
declare hash indic(dataset:'have', ordered:'d');
indic.defineKey('indicators');
indic.defineData('complexity','indicators');
indic.defineDone();
declare hiter inditer('indic');
end;
set have(drop=indicators rename=complexity=thisrow_complex); *assuming have has a variable, "indicators", like "0011001";
array vars var1-var20;
rc=inditer.first();
rowcounter=1;
do while (rc=0 and complexity ge thisrow_complex);
do _t = 1 to dim(vars);
if vars[_t]=1 and char(indicators,_t) ne '1' then leave;
end;
if _t gt dim(Vars) then delete;
else rc=inditer.next();
rowcounter=rowcounter+1;
end;
run;
答案 1 :(得分:1)
我很确定他们可能是一种更加以数学为导向的方式,但是现在我可以考虑这个。请谨慎行事,因为我只检查了一个小号码。测试用例。
我的伪算法: (位模式=将所有二进制变量串联成一个字符串。)
PROC SQL
步骤正在做的事情在上一个data step
中,您将获得需要排除的位模式列表。注意:此方法不会处理重复的模式,如下所示:
record1: 1 0 0 1
record2: 1 0 0 1
可以通过PROC SORT
& amp; NODUPKEY
。
/*sample data*/
data sample_data;
input id var1-var4;
bit_pattern = compress(catx('',var1,var2,var3,var4));
datalines;
1 0 0 1 1
2 1 0 0 1
3 0 1 1 1
4 0 0 0 1
5 1 1 1 0
;
run;
/*in the above example, 0001 0011 need to be eliminated. These will be highlighted in the last datastep*/
/*get unique combination of patterns in the dataset*/
proc sql ;
create table all_poss_patterns as
select
var1,var2, var3,var4,
count(*) as freq
from sample_data
group by var1,var2, var3,var4
order by var1,var2, var3,var4;
quit;
data patterns_to_exclude;
set all_poss_patterns;
by var1-var4;
length lagged1-lagged4 8;
array first_array{*} var1-var4;
array lagged{*}lagged1-lagged4;
length bit_pattern $32.;
length lagged_bit_pattern $32.;
bit_pattern = '';
lagged_bit_pattern='';
do i = 1 to dim(first_array);
lagged{i}=lag(first_array{i});
end;
do i = 1 to dim(first_array);
bit_pattern=cats("", bit_pattern,lagged{i}*first_array{i});
lagged_bit_pattern=cats("",lagged_bit_pattern,lagged{i});
end;
if bit_pattern=lagged_bit_pattern then exclude_pattern=1;
else exclude_pattern=0;
/*uncomment the following two lines to just keep the patterns that need to be excluded*/
/*if bit_pattern ne '....' and exclude_pattern=1;*/ /*note the bit_pattern ne '....' the no. of dots should equal no. of binary vars*/
/*keep bit_pattern;*/
run;