【问题标题】:Bucketing data and selecting only some of the bucketed values分桶数据并仅选择一些分桶值
【发布时间】:2018-11-19 14:16:52
【问题描述】:

假设我希望仅校准每个类别中值的频率大于或等于 10 的数据值。(这是对我的 SAS 表中数据的简化方式,有同一类别的相同值出现在不同行的原因,实际数据集中有4个类别和数十万个值观察值

  Category        Value                Frequency
  A             -1                       6
  A             -1                       7
  A             -0.5                     4
  A              0.1                     12
  B             -1                       9
  B             -0.9                     6
  B             -0.9                     5
  B             -0.5                     14

因此,在上面的 A 类示例中,值 -1 和 0.1 将被校准,因为它们的频率分别为 13 和 12,大于或等于 10,但 -0.5 不会。但是,对于 B 类,值 -0.9 和 -0.5 将在(频率=11,14)上进行校准。不同的类别将分别进行校准。 我正在尝试使用 SAS 仅选择每个类别中频率大于或等于 10 的值。

最好先尝试选择一个值,然后再将其扩展到其他值。如果我将上述数据集称为“分类”,而我正在尝试创建的新数据集为“已校准”,那么我已经得到了:

data Calibrated;
     set Categorised;
     if Category="A" and Value= -1 then new = sum(Frequency);
run;

但这只会生成一个名为“新”的额外列,其中包含与“分类”数据集中 -1 值相同的频率条目。我应该如何进行?

【问题讨论】:

    标签: sas


    【解决方案1】:

    您可以使用 proc sql 执行以下操作。

    data have;
    input 
    Category $       Value                Frequency;
    datalines;
    A             -1                       6
    A             -1                       7
    A             -0.5                     4
    A              0.1                     12
    B             -1                       9
    B             -0.9                     6
    B             -0.9                     5
    B             -0.5                     14
    ;
    
    proc sql;
    create table have_to_calibrate as
    select * from have
    group by category, value
    having sum(frequency)> 10;
    

    【讨论】:

    • 我的数据集似乎太大而无法使用 Proc SQL。我可以改用数据步骤吗?
    • 数十万行对于 PROC SQL 来说应该不是问题。
    • 测试了这个确切的场景,在 1 秒 (0.37) 内处理了 800,000 行,其中 SAS UE 在 1 个内核和 2GB 的 RAM 上运行。
    【解决方案2】:

    您尚未在输出中指明是否需要 (a) 频率聚合满足您的条件的所有原始记录,或 (b) 仅满足条件的唯一(类别、值)对。

    如果你想要 (a),Kiran 已经提供的 SQL 解决方案很好,是我能想到的最简单的解决方案。但是,如果您希望在 DATA 步骤中使用它,也可以这样做。首先,假设您的数据按(类别,值)排序,就像它看起来的那样。然后你可以编写所谓的双 DoW 循环:

    data want (drop = _:) ;               
      do _n_ = 1 by 1 until (last.value) ;
        set have ;                        
        by category value ;               
        _fsum = sum (_fsum, frequency) ;  
      end ;                               
      do _n_ = 1 to _n_ ;                 
        set have ;                        
        if _fsum > 10 then output ;       
      end ;                               
    run ;                                 
    

    如果你的数据没有排序,可以用哈希表来达到效果:

    data want (drop = _:) ;                      
      dcl hash h (ordered:"a") ;                 
      h.definekey ("category", "value") ;        
      h.definedata ("_fsum") ;                   
      h.definedone () ;                          
      do until (last) ;                          
        set have end = last ;                    
        if h.find() ne 0 then _fsum = frequency ;
        else _fsum + frequency ;                 
        h.replace() ;                            
      end ;                                      
      do until (0) ;                             
        set have ;                               
        h.find() ;                               
        if _fsum > 10 then output ;              
      end ;                                      
    run ; 
    

    如果您想要 (b),即只有不同的 (category,value) 对,SQL(以提供的形式)将不起作用。如果您将排序输入数据解决方案的代码简化为以下代码,则 DATA 步骤将:

    data want (keep = category value) ;   
      do until (last.value) ;
        set have ;                        
        by category value ;               
        _fsum = sum (_fsum, frequency) ;  
      end ;                               
      if _fsum > 10 ;                     
    run ;   
    

    对于未排序的数据(哈希方法):

    data _null_ ;                                       
      dcl hash h (ordered:"a") ;                        
      h.definekey ("category", "value") ;               
      h.definedata ("category", "value", "_fsum") ;     
      h.definedone () ;                                 
      do until (last) ;                                 
        set have end = last ;                           
        if h.find() ne 0 then _fsum = frequency ;       
        else _fsum + frequency ;                        
        h.replace() ;                                   
      end ;                                             
      h.output (dataset:"want (where = (_fsum > 10))") ;
      stop ;                                            
    run ;          
    

    问候,

    保罗·多夫曼

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-22
      • 2019-12-09
      • 2015-03-01
      • 1970-01-01
      相关资源
      最近更新 更多