如何按特定顺序从两个数据集中读取?

时间:2015-08-21 09:26:41

标签: sas datastep

假设我有2个数据集A和B:

Data A;
input data $;
datalines;
A1
A2
A3
;
run;

Data B;
input data $;
datalines;
B1
B2
B3
;
run;

我想生成一个具有以下特定顺序的数据集:

A1
B1
B2
B3
A2 
B1
B2
B3
A3
B1
B2
B3

如何通过数据步骤从数据集A和B执行此操作而不使用POINT =?

我尝试过这种方法:

DATA WRONG_ANSWER;
SET A;
OUTPUT;
DO i = 1 to 3;
SET B;
OUTPUT;
END;
RUN;

结果是:

A1
B1
B2
B3
A2

看起来B的文件结束指示符终止了这个数据步骤。

我还尝试了另一种POINT =的方法,我得到了正确的结果。然而,由于从B访问特定障碍物时的大量I / O时间,这种方法非常慢:

DATA WRONG_ANSWER;
SET A;
OUTPUT;
DO i = 1 to 3;
SET B POINT=i;  //this is the only different from above 
OUTPUT;
END;
RUN;

1 个答案:

答案 0 :(得分:2)

假设有一些事情,最快的方法可能是哈希迭代器解决方案。假设:

  • 数据集B小到足以适合(一次)在内存中。
  • 您不关心结果数据集中数据集B行的顺序,或者您的关键变量具有升序或降序,或者您可以构造关键顺序变量。
  • 数据集B可以定义一个键,使其包含唯一的行,或者您可以使用“multidata:yes”(有一个足够新的SAS版本来支持它)。

鉴于这些假设,这有效:

data want;
  if 0 then set b;
  if _n_=1 then do;
    declare hash b_hash(dataset:'b', ordered:'a');
    b_hash.defineKey('data');
    b_hash.defineData('data');
    b_hash.defineDone();
    declare hiter b_iter;
    b_iter = _new_ hiter('b_hash');
  end;
  set a;
  output;
  rc = b_iter.first();
  do while (rc=0);
    output;
    rc = b_iter.next();
  end;
run;

根据您的使用情况,您可能希望通过宏系统和/或dictionary.columns查询构建defineData调用,以避免对列名进行硬编码。

这比点快得多;与基线相比:

data want_point;
  set a;
  output;
  do _n_ = 1 to nobs_b;
    set b point=_n_ nobs=nobs_b;
    output; 
  end;
run;
  • 对于大的A,1e7行和小的B,3行,它需要~10秒实时/ 8秒CPU时间(基本上不超过总写入时间),而基线点需要100秒实时/ CPU时间为12秒。
  • 使用较小的A,变得更有效,但仍然优于哈希(虽然只是略微,可能不值得编码难度的差异)。写入1e4 A / 1e3 B组合(它产生与第一个类似的大小文件)接近10秒写入时间。
  • 对于小A和大B(3行A,1e7行B),哈希需要更长的时间,因为它具有昂贵的第一次设置成本;哈希解决方案为67秒(CPU为28秒),对于点为65秒(CPU为17秒)。

因此,如果您拥有大型数据集并且将其与小数据集重复组合,则建议使用Hash。如果两个数据集的大小相似或重复设置的数据集较大,那么点可能与您将得到的一样好(给定维护哈希的难度较高)。