在多个SAS数据步骤中生成可重复的随机数

在多个SAS数据步骤中生成可重复的随机数,sas,Sas,我正在努力找出使用多个SAS数据步骤重复生成随机数的最佳方法 要在一个数据步骤中完成这项工作,非常简单:只需在数据步骤开始时使用callstreaminit 然而,如果我使用第二个数据步骤,我无法找到任何方法来继续随机数序列。如果我在第二个数据步骤中根本不使用callstreaminit,那么第二个数据步骤中的随机数是不可复制的。如果我使用具有相同种子的callstreaminit,我会得到与第一个数据步骤相同的随机数 我唯一能想到的是在每个数据步骤中使用具有不同种子的callstreamini

我正在努力找出使用多个SAS数据步骤重复生成随机数的最佳方法

要在一个数据步骤中完成这项工作,非常简单:只需在数据步骤开始时使用callstreaminit

然而,如果我使用第二个数据步骤,我无法找到任何方法来继续随机数序列。如果我在第二个数据步骤中根本不使用callstreaminit,那么第二个数据步骤中的随机数是不可复制的。如果我使用具有相同种子的callstreaminit,我会得到与第一个数据步骤相同的随机数

我唯一能想到的是在每个数据步骤中使用具有不同种子的callstreaminit。不知何故,这似乎比只使用一个从第一个数据步骤开始的长随机数序列更不令人满意

例如,我可以这样做:

%macro myrandom;
  %do i = 1 %to 10;
    data dataset&i;
      call streaminit(&i);
      [do stuff involving random numbers]
    run;
  %end;
%mend;

但不知何故,使用可预测的种子序列似乎是作弊。我应该担心吗?这实际上是一种完全可以接受的方法,还是有更好的方法?

以下是我的尝试:

%macro dataset_rand(_num,_rows);

    data dataset;
        do i = 0 to &_rows - 1;
            call streaminit(123);
            c = rand("UNIFORM");
            varnum = mod(i,&_num.) +1;
            output;
        end;
    run;

    data %do i = 1 %to &_num.;
        dataset&i.
        %end;
        ;
        set dataset;

        %do j = 1 %to &_num;
            if varnum = &j. then
                output dataset&j.;
        %end;
    run;

%mend;

%dataset_rand(10,100);
在这里,我运行了一个步骤来创建每一行,其中包含一个随机变量和另一个用于将其分配给数据集的变量

输入是_num和_rows,允许您选择总共有多少行和多少个表,因此示例(10100)创建了10个10行的表。在数据集1举行第1次、第11次。。。随机序列的第91个成员


也就是说,我不知道为什么有10个种子的10个数据集会比有1个种子的1个数据集分成10个更好或更差。

使用
Ranui
或类似的“旧”随机数流,您可以使用
调用Ranui
来实现这一点。这使您可以为下一轮保存种子,然后可以
调用symputx
将该值添加到下一个数据步骤,并重新启动相同的流。这是因为在该算法中,一个伪随机值的输出值是下一个伪随机值种子的直接变化

但是,使用
RAND
,种子更复杂(在调用第一个数字之后,它实际上不仅仅是一个值)。从:

RAND函数由单个种子启动。但是,进程的状态不能由单个种子捕获。无法从发电机的停止点停止并重新启动发电机

这当然是一种简化(显然SAS能够做到这一点,它只是没有为您打开正确的挂钩,大概因为它不像
call ranuni
那么简单)

不过,您可以使用宏语言,具体取决于您要做什么。使用
%syscall
%sysfunc
,您可以获得跨越数据步骤的单个流

然而,有一个警告:看起来你永远无法重置它。发件人:

使用%SYSFUNC通过宏语言调用RANUNI函数时,将创建一个伪随机数流。除非关闭SAS并启动新的SAS会话,否则无法更改种子值。%SYSFUNC宏生成的伪随机数流与仅为第一次宏调用生成数据集A、B和C的数据步骤相同。任何后续宏调用都会生成单个流的延续

这是特定于
ranuni
系列的,但对于
rand
系列似乎也是如此

因此,启动SAS的新会话,并运行以下操作:

%macro get_rands(seed=0, n=, var=, randtype=Uniform, randargs=);
  %local i;
  %syscall streaminit(seed);
  %do i = 1 %to &n;
    &var. = %sysfunc(rand(&randtype. &randargs.));
    output;
  %end;
%mend get_rands;

data first;
  %get_rands(seed=7,n=10,var=x);
run;

data second;
  %get_rands(n=10,var=x);
run;

data whole;
  call streaminit(7);
  do _i = 1 to 20;
    x = rand('Uniform');
    output;
  end;
run;
但是不要犯在一个会话中运行两次的错误


否则,最好生成一次随机数,然后在多个数据步骤中使用它们。如果您按组使用,则很容易以这种方式进行管理。如果您有关于如何以这种方式实施项目的具体问题,请在新问题中告诉我们。

不确定这是否更容易,但您可以使用流子例程从同一初始种子生成多个独立的流。下面是一个示例,从随叫随到流稍作修改

%macro RepeatRand(N=, Repl=, seed=);
    %do k = 1 %to &Repl;
       data dataset&k;
          call streaminit('PCG', &seed);
          call stream(&k);
          do i = 1 to &N;
             u = rand("uniform");
             output;
          end;
       run;
    %end;
%mend;

%RepeatRand(N=8, Repl=2, seed=36457);

“也就是说,我不知道为什么有10个种子的10个数据集会比1个种子分成10个的1个数据集好或坏。”也许不是。也许我最初的想法是每次都使用一颗新种子,这和其他任何东西一样好。我想知道我是否忽略了一些简单的事情,但看起来我没有。谢谢,谢谢。我想你的回答让我明白,我并没有忽视任何简单的事情。