Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SAS-重复数据步骤以求解值_Sas - Fatal编程技术网

SAS-重复数据步骤以求解值

SAS-重复数据步骤以求解值,sas,Sas,如果重复次数取决于数据步骤的结果,是否可以重复一个数据步骤多次(就像在%do-%while循环中一样) 我有一个带有数字变量a的数据集。我计算一个新变量result=min(1,a)。我希望结果的平均值等于一个目标,我可以通过用常数k缩放变量a来达到这个目标。这是对k的求解,其中target=average(min(1,A*k))——其中k和target是常数,A是列表 以下是我到目前为止的情况: filename f0 'C:\Data\numbers.csv'; filename f1 'C

如果重复次数取决于数据步骤的结果,是否可以重复一个数据步骤多次(就像在%do-%while循环中一样)

我有一个带有数字变量a的数据集。我计算一个新变量result=min(1,a)。我希望结果的平均值等于一个目标,我可以通过用常数k缩放变量a来达到这个目标。这是对k的求解,其中target=average(min(1,A*k))——其中k和target是常数,A是列表

以下是我到目前为止的情况:

filename f0 'C:\Data\numbers.csv';
filename f1 'C:\Data\target.csv';

data myDataSet;
    infile f0 dsd dlm=',' missover firstobs=2;
    input A;
    init_A = A; /* store the initial value of A */
run;

/* read in the target value (1 observation) */
data targets;
    infile f1 dsd dlm=',' missover firstobs=2;
    input target;
    K = 1; * initialise the constant K;
run;

%macro iteration; /* I need to repeat this macro a number of times */
    data myDataSet;
        retain key 1;
        set myDataSet;
        set targets point=key;

        A = INIT_A * K; /* update the value of A /*
        result = min(1, A);
    run;

    /* calculate average result */
    proc sql;
        create table estimate as 
        select avg(result) as estimate0
        from myDataSet;
    quit;

    /* compare estimate0 to target and update K */
    data targets;
        set targets;
        set estimate;

        K = K * (target / estimate0);
    run;
%mend iteration;
我可以通过运行几次
%iteration
来获得所需的答案,但理想情况下,我希望运行迭代直到
(target-estimate0<0.01)
。这可能吗


谢谢

前几天我也遇到了类似的问题。下面是我使用的方法,您需要将循环结构从
for
循环更改为
do-while
循环(或任何适合您的目的):

首先对表执行初始扫描,以确定循环终止条件,并获得表中的行数:

data read_once;
  set sashelp.class end=eof;

  if eof then do;
    call symput('number_of_obs', cats(_n_) );    
    call symput('number_of_times_to_loop', cats(3) );
  end;
run;
确保结果符合预期:

%put &=number_of_obs;
%put &=number_of_times_to_loop;
在源表上再次循环多次:

data final;

  do loop=1 to &number_of_times_to_loop;
    do row=1 to &number_of_obs;
      set sashelp.class point=row;
      output;
    end;
  end;

  stop; * REQUIRED BECAUSE WE ARE USING POINT=;

run;
答案分两部分

首先,你说什么当然可以做什么。如果你想要一个有用的迭代宏代码示例,可以在网上找到一些这样的代码示例;例如,大卫·伊兹雷尔(David Izrael)的开创性研究,通过迭代一个相对简单的过程(基本上是proc freqs)来执行一个加权过程。这和你正在做的很相似。在此过程中,它在数据步骤中查看各种终止标准,并输出一个宏变量,即满足的标准总数(因为每个分层变量分别需要满足终止标准)。然后,它检查
%是否满足该标准,如果满足,则终止

这其中的核心是两件事。首先,你应该有一个固定的最大迭代次数,除非你喜欢无限循环。这个数字应该比你所需要的最大合理数字大,通常大约是两倍。其次,您需要收敛条件,以便在满足这些条件时可以终止循环

例如:

data have;
  x=5;
run;

%macro reduce(data=, var=, amount=, target=, iter=20);
   data want;
     set have;
   run;
   %let calc=.;
   %let _i=0;
   %do %until (&calc.=&target. or &_i.=&iter.);
     %let _i = %eval(&_i.+1);
      data want;
        set want;
        &var. = &var. - &amount.;
        call symputx('calc',&var.);
      run;
   %end;
   %if &calc.=&target. %then %do;
     %put &var. reduced to &target. in &_i. iterations.; 
   %end;
   %else %do;
     %put &var. not reduced to &target. in &iter. iterations.  Try a larger number.;
   %end;
%mend reduce;

%reduce(data=have,var=x,amount=1,target=0);
这是一个非常简单的示例,但它具有所有相同的元素。我更喜欢自己使用do-until和increment,但您也可以使用相反的方法(正如
%rakinge
所做的那样)。遗憾的是,宏语言不允许像data step语言那样使用do by。哦,好吧


其次,您通常可以在单个数据步骤中执行类似的操作。即使在旧版本(9.2等)中,您也可以在一个数据步骤中完成上述所有要求,尽管它可能看起来有点笨拙。在9.3+中,特别是在9.4中,有一些方法可以在数据步骤中运行proc sql,并在不等待另一个数据步骤的情况下,使用run_宏或DOSUBL和/或FCMP语言返回结果。即使是一些简单的事情,比如:

data have;
  initial_a=0.3;
  a=0.3;
  target=0.5;
  output;
  initial_a=0.6;
  a=0.6;
  output;
  initial_a=0.8;
  a=0.8;
  output;
run;

data want;
  k=1;
  do iter=1 to 20 until (abs(target-estimate0) < 0.001);
    do _n_ = 1 to nobs;
      if _n_=1 then result_tot=0;
      set have nobs=nobs point=_n_;
      a=initial_a*k;
      result=min(1,a);
      result_tot+result;
    end;
    estimate0 = result_tot/nobs;
    k = k * (target/estimate0);
  end;
  output;
  stop;
run;
数据已经存在;
初始_a=0.3;
a=0.3;
目标=0.5;
产出;
初始_a=0.6;
a=0.6;
产出;
初始_a=0.8;
a=0.8;
产出;
跑
数据需求;
k=1;
do iter=1至20,直到(abs(目标估计值0)<0.001);
do=1至nobs;
如果_n_=1,则结果_tot=0;
设置有nobs=nobs点=_n_u;
a=初始值_a*k;
结果=最小值(1,a);
结果_tot+结果;
结束;
估计值0=结果总和/nobs;
k=k*(目标/估计值0);
结束;
产出;
停止
跑

这一切都在一个数据步骤中完成。我有点作弊,因为我正在编写自己的数据步迭代器,但这在这类事情中很常见,而且速度非常快。迭代多个数据步骤和proc sql步骤的宏通常会慢得多,因为每个步骤都会产生一些开销。

如果将Target、estimate0或Target-estimate0总计放入一个或多个宏变量中。然后您可以在宏中使用%do%until循环,直到(%eval)总数为。我的代码中缺少的部分似乎是
call symputx
行。我是SAS的新手,我认为宏就像C/C++预处理器命令,但如果代码正常工作,一定会有一些神奇的事情发生。谢谢