Sas 保持采样宏变量常数

Sas 保持采样宏变量常数,sas,sas-macro,sas-iml,Sas,Sas Macro,Sas Iml,希望是一个简单的答案。我在做一个模拟研究,我需要从均匀分布中随机抽取N个个体,U(25200),每一千个左右的重复中抽取一个。一次复制的代码如下所示: %LET U = RAND("UNIFORM"); %LET N = ROUND(25 + (200 - 25)*&U.); 我在数据步骤之外创建了这两个宏变量,因为我需要在后续的数据步骤中重复调用N变量,并在SAS和IML中执行循环 问题是,每次我在复制中调用N时,它都会对U进行重新采样,这必然会修改N。因此,N在复制中不是保持不变的

希望是一个简单的答案。我在做一个模拟研究,我需要从均匀分布中随机抽取N个个体,U(25200),每一千个左右的重复中抽取一个。一次复制的代码如下所示:

%LET U = RAND("UNIFORM");
%LET N = ROUND(25 + (200 - 25)*&U.);
我在数据步骤之外创建了这两个宏变量,因为我需要在后续的数据步骤中重复调用N变量,并在SAS和IML中执行循环

问题是,每次我在复制中调用N时,它都会对U进行重新采样,这必然会修改N。因此,N在复制中不是保持不变的。这个问题显示在下面的代码中,我首先创建N作为变量(在个体之间是常数),并使用DO循环为每个个体的X采样预测值。请注意,N中的值与个体总数不同,这也是一个问题

DATA ID; 
    N = &N.;
    DO PersonID = 1 TO &N.;
        X = RAND("NORMAL",0,1); OUTPUT;
    END;
RUN;
我猜我需要做的是在一次复制的整个过程中以某种方式保持U恒定,然后允许它为复制2重新采样,以此类推。通过保持U不变,N必然保持不变


有没有一种方法可以使用宏变量来实现这一点?

我不知道如何在宏世界中实现这一点,但这就是如何将代码转换为数据步骤来完成同样的事情

关键是使用callstreaminit设置随机数流初始化值

Data _null_;
call streaminit(35);
u=rand('uniform');
call symput('U', u);
call symput('N',  ROUND(25 + (200 - 25)*U));
run;


%put &n;
%put &u;

&N
不存储值
&N
存储代码“ROUND(…(RAND…)等。您在这里误用了宏变量:虽然您可以在
&N
中存储数字,但您没有这样做;您必须使用
%sysfunc
,无论哪种方式,这里的答案都不正确

首先,如果你重复取样,看看纸,这里有一些应用。也考虑Rick Wicklin的论文和他的参考书(“模拟数据在SAS”)。这也很好。如果您在一个样本一个执行模型上运行您的流程,那么这是一种缓慢且难以处理的方式。一次完成所有复制,一次处理所有复制;IML和SAS都很乐意为您这样做。使用统一的随机样本大小有点困难,但这并不安全能干的

如果你必须按照你现在的方式来做,我会要求数据步骤创建宏变量,如果有理由的话。在示例的末尾,你可以使用
call symput
来输出N的值。即:

%let iter=7; *we happen to be on the seventh iteration of your master macro;
DATA ID;
    CALL STREAMINIT(&iter.); 
    U = RAND("UNIFORM");
    N = ROUND(25 + (200 - 25)*U);
    DO PersonID = 1 TO N;
        X = RAND("NORMAL",0,1); 
        OUTPUT;
    END;
    CALL SYMPUTX('N',N);
    CALL SYMPUTX('U',U);
RUN;

但同样,一个数据步模型可能是最有效的模型。

正如Joe指出的,执行此模拟的有效方法是在一个数据步中生成所有1000个样本,如下所示:

data AllSamples;
call streaminit(123);
do SampleID = 1 to 1000;
   N = ROUND(25 + (200 - 25)*RAND("UNIFORM"));
   /* simulate sample of size N HERE */
   do PersonID = 1 to N;
      X = RAND("NORMAL",0,1);   
      OUTPUT;
   end;
end;
run;
这确保了随机数流的独立性,并且生成1000个样本需要几分之一秒的时间。然后,您可以使用BY语句分析每个样本上统计信息的采样分布。例如,以下对PROC MEANS的调用输出eac的样本大小、样本平均数和样本标准差h在1000个样本中:

proc means data=AllSamples noprint;
by SampleID;
var X;
output out=OutStats n=SampleN mean=SampleMean std=SampleStd;
run;

proc print data=OutStats(obs=5);
var SampleID SampleN SampleMean SampleStd;
run;

有关按组方法为何更高效(总时间=不到1秒!)的更多详细信息,请参阅文章

调用STREAMINIT是一个好主意,但在他的情况下,这不是问题:问题在于他的代码是
do PersonID=1到四舍五入(25+(200-25)*RAND('UNIFORM'));
每次都用一个新值重新创建循环结束。谢谢Joe!而且,是的,我的模拟过程很笨拙。对我来说,这是5分钟和10分钟之间的差异。给了我一些必要的时间从椅子上站起来走动。:)