保持采样宏变量常量
Holding Sampled Macro Variable Constant
希望是一个简单的答案。我正在进行一项模拟研究,我需要在一千次左右的重复中从均匀分布 U(25,200) 中抽取随机数量的个体 N。一次复制的代码如下所示:
%LET U = RAND("UNIFORM");
%LET N = ROUND(25 + (200 - 25)*&U.);
我在 DATA 步之外创建了这两个宏变量,因为我需要在后续 DATA 步和 SAS 和 IML 中的 DO 循环中重复调用 N 变量。
问题是每次我在复制中调用 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 必然保持不变。
有没有办法使用宏变量来做到这一点?
我不确定如何在宏观世界中做到这一点,但这是您可以将代码转换为数据步骤以完成相同事情的方法。
关键是设置随机数流初始化值,使用CALL STREAMINIT。
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
,无论哪种方式,这都不是真正正确的答案。
首先,如果您重复采样重复,请查看论文 Don't be Loopy', which has some applications here. Also consider Rick Wicklin's paper, Sampling with Replacement,他在其中引用的书 ("Simulating Data in 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 的调用输出 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;
有关为什么 BY-group 方法更有效(总时间 = 不到 1 秒!)的更多详细信息,请参阅文章 "Simulation in SAS: The slow way or the BY way."
希望是一个简单的答案。我正在进行一项模拟研究,我需要在一千次左右的重复中从均匀分布 U(25,200) 中抽取随机数量的个体 N。一次复制的代码如下所示:
%LET U = RAND("UNIFORM");
%LET N = ROUND(25 + (200 - 25)*&U.);
我在 DATA 步之外创建了这两个宏变量,因为我需要在后续 DATA 步和 SAS 和 IML 中的 DO 循环中重复调用 N 变量。
问题是每次我在复制中调用 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 必然保持不变。
有没有办法使用宏变量来做到这一点?
我不确定如何在宏观世界中做到这一点,但这是您可以将代码转换为数据步骤以完成相同事情的方法。
关键是设置随机数流初始化值,使用CALL STREAMINIT。
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
,无论哪种方式,这都不是真正正确的答案。
首先,如果您重复采样重复,请查看论文 Don't be Loopy', which has some applications here. Also consider Rick Wicklin's paper, Sampling with Replacement,他在其中引用的书 ("Simulating Data in 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 的调用输出 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;
有关为什么 BY-group 方法更有效(总时间 = 不到 1 秒!)的更多详细信息,请参阅文章 "Simulation in SAS: The slow way or the BY way."