【问题标题】:Get rid of kth smallest and largest values of a dataset in SAS摆脱 SAS 中数据集的第 k 个最小值和最大值
【发布时间】:2015-05-27 18:17:39
【问题描述】:

我有一个类似这样的数据集

obs|富 |酒吧 |更多

1 | 111 | 11 | 9 2 | 9 | 2 | 2 ........

我需要扔掉 foo 中最大的 4 个和最小的 4 个(稍后我会用 bar 做类似的事情)才能继续进行,但我不确定最有效的方法。我知道有最小和最大的函数,但我不明白如何使用它们从已经制作的数据集中获取最小的 4 或最大的 4。我想或者我可以删除最小和最大 4 次,但这听起来不必要的乏味/耗时。有没有更好的办法?

【问题讨论】:

    标签: dataset sas


    【解决方案1】:

    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 中执行,而不是删除观察结果。

    【讨论】:

    • 我不知道这是 proc rank 的默认行为,没有 groups= 选项 - 感谢分享!
    【解决方案2】:

    您将需要至少 2 次遍历您的数据集,但是您这样做 - 一次是为了找出顶部和底部 4 个值是什么,另一次是为了排除这些观察结果。

    您可以使用 proc 单变量获取顶部和底部 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;
    

    如果有多个观测值并列第四大/最小,这将过滤掉所有观测值。

    【讨论】:

    【解决方案3】:

    您可以使用 proc sql 将 foo 的不同值的数量放入宏 var 中(包括 null 值作为不同的值)。

    在您的数据步骤中,您可以使用 first.foo 和宏 var 选择性地仅输出那些不是最小或最大 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;
    

    【讨论】:

    • 创造力满分,但这对于较大的数据集效率不高 - 每个过滤变量需要 2 个排序 + 1 个数据步骤,这是提问者试图避免的那种迭代过程。
    【解决方案4】:

    我还找到了一种似乎适用于 IML 的方法(我正在尝试以不同的方式重做事情)。我知道我的最大观察次数,并且已经按照感兴趣的变量的顺序对其进行了排序。

     PROC IML;
     EDIT data_set; 
     DELETE point {{1, 2, 3, 4,51, 52, 53, 54}; 
     PURGE;
     close data_set; 
     run;
    

    我没有经常使用 IML,但我在阅读文档时偶然发现了这一点。感谢所有回答我问题的人!

    【讨论】:

      猜你喜欢
      • 2013-06-05
      • 1970-01-01
      • 2017-09-09
      • 2021-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-16
      • 1970-01-01
      相关资源
      最近更新 更多