摆脱SAS中数据集的第k个最小值和最大值
Get rid of kth smallest and largest values of a dataset in SAS
我有一个类似这样的数据集
观察|富 |酒吧 |更多
1 | 111 | 11 | 9
2 | 9 | 2 | 2个
.........
我需要扔掉 foo 中最大的 4 个和最小的 4 个(稍后我会用 bar 做类似的事情)才能继续,但我不确定最有效的方法。我知道有最小和最大的函数,但我不明白如何使用它们从已制作的数据集中获取最小的 4 个或最大的 4 个。我想我也可以只删除最小值和最大值 4 次,但这听起来不必要 tedious/time 消耗。有没有更好的方法?
您将需要至少遍历数据集 2 次,但是您这样做 - 一次找出顶部和底部 4 个值是什么,另一个排除这些观察值。
您可以使用 proc univariate 获取前 5 个值和后 5 个值,然后使用其输出为后续数据步骤创建 where 过滤器。这是一个例子:
ods _all_ close;
ods output extremeobs = extremeobs;
proc univariate data = sashelp.cars;
var MSRP INVOICE;
run;
ods listing;
data _null_;
do _N_ = 1 by 1 until (last.varname);
set extremeobs;
by varname notsorted;
if _n_ = 2 then call symput(cats(varname,'_top4'),high);
if _n_ = 4 then call symput(cats(varname,'_bottom4'),low);
end;
run;
data cars_filtered;
set sashelp.cars(where = ( &MSRP_BOTTOM4 < MSRP < &MSRP_TOP4
and &INVOICE_BOTTOM4 < INVOICE < &INVOICE_TOP4
)
);
run;
如果有多个观察结果并列第 4 大/最小,这将过滤掉所有观察结果。
您可以使用 proc sql 将 foo 的不同值的数量放入宏 var(包括作为不同的空值)。
在您的数据步骤中,您可以使用 first.foo 和宏变量来有选择地仅输出那些不是最小或最大 4 个值的值。
proc sql noprint;
select count(distinct foo) + count(distinct case when foo is null then 1 end)
into :distinct_obs from have;
quit;
proc sort data = have; by foo; run;
data want;
set have;
by foo;
if first.foo then count+1;
if 4 < count < (&distinct_obs. - 3) then output;
drop count;
run;
PROC RANK 会很容易地为你做到这一点。如果您知道观察的总数,那是微不足道的 - 如果您不知道,则稍微困难一些。
proc rank data=sashelp.class out=class_ranks(where=(height_r>4 and weight_r>4));
ranks height_r weight_r;
var height weight;
run;
例如,这会删除 4 个最小身高或体重的任何观测值。最大的 4 个需要知道最大等级,或者执行第二个处理步骤。
data class_final;
set class_ranks nobs=nobs;
if height_r lt (nobs-3) and weight_r lt (nobs-3);
run;
当然,如果您只是删除值,则在数据步骤中完成所有操作,如果满足条件,call missing
变量而不是删除观察值。
我还找到了一种似乎适用于 IML 的方法(我正在通过尝试以不同的方式重做来练习)。我知道我的最大观察数,并且已经按照感兴趣的变量的顺序对其进行了排序。
PROC IML;
EDIT data_set;
DELETE point {{1, 2, 3, 4,51, 52, 53, 54};
PURGE;
close data_set;
run;
我没有经常使用 IML,但我在阅读文档时偶然发现了这一点。感谢所有回答我问题的人!
我有一个类似这样的数据集
观察|富 |酒吧 |更多
1 | 111 | 11 | 9 2 | 9 | 2 | 2个 .........
我需要扔掉 foo 中最大的 4 个和最小的 4 个(稍后我会用 bar 做类似的事情)才能继续,但我不确定最有效的方法。我知道有最小和最大的函数,但我不明白如何使用它们从已制作的数据集中获取最小的 4 个或最大的 4 个。我想我也可以只删除最小值和最大值 4 次,但这听起来不必要 tedious/time 消耗。有没有更好的方法?
您将需要至少遍历数据集 2 次,但是您这样做 - 一次找出顶部和底部 4 个值是什么,另一个排除这些观察值。
您可以使用 proc univariate 获取前 5 个值和后 5 个值,然后使用其输出为后续数据步骤创建 where 过滤器。这是一个例子:
ods _all_ close;
ods output extremeobs = extremeobs;
proc univariate data = sashelp.cars;
var MSRP INVOICE;
run;
ods listing;
data _null_;
do _N_ = 1 by 1 until (last.varname);
set extremeobs;
by varname notsorted;
if _n_ = 2 then call symput(cats(varname,'_top4'),high);
if _n_ = 4 then call symput(cats(varname,'_bottom4'),low);
end;
run;
data cars_filtered;
set sashelp.cars(where = ( &MSRP_BOTTOM4 < MSRP < &MSRP_TOP4
and &INVOICE_BOTTOM4 < INVOICE < &INVOICE_TOP4
)
);
run;
如果有多个观察结果并列第 4 大/最小,这将过滤掉所有观察结果。
您可以使用 proc sql 将 foo 的不同值的数量放入宏 var(包括作为不同的空值)。
在您的数据步骤中,您可以使用 first.foo 和宏变量来有选择地仅输出那些不是最小或最大 4 个值的值。
proc sql noprint;
select count(distinct foo) + count(distinct case when foo is null then 1 end)
into :distinct_obs from have;
quit;
proc sort data = have; by foo; run;
data want;
set have;
by foo;
if first.foo then count+1;
if 4 < count < (&distinct_obs. - 3) then output;
drop count;
run;
PROC RANK 会很容易地为你做到这一点。如果您知道观察的总数,那是微不足道的 - 如果您不知道,则稍微困难一些。
proc rank data=sashelp.class out=class_ranks(where=(height_r>4 and weight_r>4));
ranks height_r weight_r;
var height weight;
run;
例如,这会删除 4 个最小身高或体重的任何观测值。最大的 4 个需要知道最大等级,或者执行第二个处理步骤。
data class_final;
set class_ranks nobs=nobs;
if height_r lt (nobs-3) and weight_r lt (nobs-3);
run;
当然,如果您只是删除值,则在数据步骤中完成所有操作,如果满足条件,call missing
变量而不是删除观察值。
我还找到了一种似乎适用于 IML 的方法(我正在通过尝试以不同的方式重做来练习)。我知道我的最大观察数,并且已经按照感兴趣的变量的顺序对其进行了排序。
PROC IML;
EDIT data_set;
DELETE point {{1, 2, 3, 4,51, 52, 53, 54};
PURGE;
close data_set;
run;
我没有经常使用 IML,但我在阅读文档时偶然发现了这一点。感谢所有回答我问题的人!