3

假设我有 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

如何在没有 POINT= 的情况下通过数据步骤从数据集 A 和 B 中做到这一点?

我试过这个方法:

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

结果是:

A1
B1
B2
B3
A2

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

我还尝试了另一种使用 POINT= 的方法,得到了正确的结果。但是,由于从 B 访问特定 obs 时需要大量 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;
4

1 回答 1

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;

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

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

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 秒实时/12 秒 CPU时间。
  • 使用较小的 A,变得更有效,但仍然优于散列(尽管只是略微,可能不值得编码难度的差异)。两者都接近 10 秒的写入时间来写出 1e4 A/1e3 B 组合(产生与第一个相似大小的文件)。
  • 对于小 A 和大 B(3 行 A,1e7 行 B),哈希需要更长的时间,因为它具有昂贵的首次设置成本;哈希解决方案(28 秒 CPU)为 67 秒,而点为 65 秒(17 秒 CPU)。

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

于 2015-08-21T14:28:05.057 回答