SAS中选择唯一记录的有效方法

SAS中选择唯一记录的有效方法,sas,Sas,数据集如下所示: Code Type Rating 0001 NULL 1 0002 NULL 1 0003 NULL 1 0003 PA 1 3 0004 NULL 1 0004 PB 1 2 0005 AC 1 3 0005 NULL 6 0006 AC 1 2 我希望输出数据集看起来像 Code Type Rating

数据集如下所示:

Code    Type     Rating
0001    NULL      1
0002    NULL      1
0003    NULL      1
0003    PA 1      3
0004    NULL      1
0004    PB 1      2
0005    AC 1      3
0005    NULL      6
0006    AC 1      2
我希望输出数据集看起来像

Code    Type     Rating
0001    NULL      1
0002    NULL      1
0003    PA 1      4        
0004    PB 1      3        
0005    AC 1      9        
0006    AC 1      2
对于每个
代码
类型
最多有两个值。我想通过求和
评级
来选择唯一的
代码
。但问题是,对于
类型
,如果它只有一个值,则会将其值传递给输出数据集。如果is有两个值(一个必须为
NULL
),则将不等于
NULL的值传递给输出数据集


观察总数
N>100000000
。那么,有什么棘手的方法来实现这一点吗

如果按照您的示例对数据进行排序,那么您可以在单个数据步骤中实现这一点。我假设实际缺少空值,但是如果没有,则将[if missing(type)]更改为[if type='NULL']。所有这些都是对每个代码的额定值求和,然后输出最后一条记录,保持非空类型。如果您的数据没有在代码上进行排序或索引,那么您需要首先进行排序,这显然会增加相当多的执行时间

/* create input file */
data have;
input Code Type $ Rating;
infile datalines dsd;
datalines;
0001,,1
0002,,1
0003,,1
0003,PA 1,3
0004,,1
0004,PB 1,2
0005,AC 1,3
0005,,6
0006,AC 1,2
;
run;

/* create summarised dataset */
data want;
set have;
by code;
retain _type; /* temporary variable */
if first.code then do;
    _type = type;
    _rating_sum = 0; /* reset sum */
end;
_rating_sum + rating; /* sum rating per Code */
if last.code then do;
    if missing(type) then type = _type; /* pick non-null value */
    rating = _rating_sum; /* insert sum */
    output;
end;
run;

在一个SQL步骤中也很容易做到。只需使用一个CASE…WHEN…END来删除空值,然后使用MAX来获得非空值

data have;
input @1 Code 4.
      @9 Type $4.
      @19 Rating 1.;
datalines;
0001    NULL      1
0002    NULL      1
0003    NULL      1
0003    PA 1      3
0004    NULL      1
0004    PB 1      2
0005    AC 1      3
0005    NULL      6
0006    AC 1      2
;;;;
run;

proc sql;
create table want as
    select code, 
        max(case type when 'NULL' then '' else type end) as type,
        sum(Rating) as rating
        from have
        group by code;
quit;

如果要返回NULL,则需要将select包装在
select代码中,当“”时为case type,然后为'NULL'否则类型结束为type,评级从(…),但我建议将其留空。

给出注释后,出现了另一种可能性,即哈希解决方案。这是内存受限的,因此它可能无法处理实际数据(哈希表不是很大,但100M行可能意味着哈希表中有60或70M行,乘以40或50字节仍然相当大)

如果数据集是按代码排序的,那么这几乎肯定不如普通数据步骤方法,因此这应该只用于未排序的数据

这些概念:

  • 创建对代码进行键控的哈希表
  • 如果传入记录是新的,则添加到哈希表
  • 如果传入记录不是新代码,则获取检索到的值并对评级求和。检查类型是否需要更换
  • 输出到数据集
代码:


您有多少不同的
类型值?数据是按上述方式排序,还是不按排序(至少按
code
)?我们用什么“不难处理”的方式将其与之进行比较(即,您现在有什么,需要多长时间)?数百个
类型
。数据按
代码
排序,然后按
类型
排序。我为每个唯一的
代码连接
类型
。然后寻找非空子字符串。如果它已经被排序(即,你不只是为了这个而排序),那么Keith提供的数据步解决方案可能是最快的。如果不是,那么数组解决方案可能是最快的,如果它只有几百种类型的话。但是最好不要先对它排序,因为执行时间会增加很多。我应该尝试一个不排序的数组解决方案和一个带有排序数据的日期步骤,看看哪一个更快?你应该尝试各种解决方案,看看哪一个更快。你需要使用摘要功能(以便GROUP BY正常工作)。MAX在字符上的作用与数字相同(Z>A,空格=missing最小)。我将NULL改为空格,这样它就保证与其他值相比是最小的。这很大程度上取决于一个代码最多只有两个观察值,你能告诉我如果有更多的观察值,它将如何扩展吗?好的,但已经明确指出,最多出现两个观察值。如果还有更多的话,那只是对逻辑的简单改变。如果是first.code,则调用缺失(\u type,\u rating\u sum);如果不缺少(类型),则_type=类型_评级\总和+评级;etcIt不是一次攻击,只是一个关于如何扩展到另一个更接近我的案例的问题。抱歉,如果这是冒犯性的,没问题,安东尼。事后看来,我可能应该发布包含任意数量条目的解决方案,而不是2条。几乎没有任何额外的代码来做这件事,而且它更具可扩展性
data _null_;
  if _n_=1 then do;
      if 0 then set have;
      declare hash h(ordered:'a');
      h.defineKey('code');
      h.defineData('code','type','rating');
      h.defineDone();
  end;
  set have(rename=(type=type_in rating=rating_in)) end=eof;
  rc_1 = h.find();
  if rc_1 eq 0 then do;
    if type ne type_in and type='NULL' then type=type_in;
    rating=sum(rating,rating_in);
    h.replace();
  end;
  else do;
    type=type_in;
    rating=rating_in;
    h.add();
  end;
  if eof then do;
    h.output(dataset:'want');
  end;
run;