宏和设置局部变量中的 SAS 语法错误

SAS Syntax error in macro and setting up local variables

提问人:Segeana 提问时间:9/15/2023 更新时间:9/20/2023 访问量:30

问:

我是SAS的新手。我从两个 excel 电子表格中导入了数据。从第一个开始,我计算了新变量名称 Sorptivity 和 Kfs。此步骤工作正常。然后,我将新创建的变量(其中有 24 个变量)与第二个表(有 237 个观测值)合并。第一个表中的 21 个观测值对应于第二个表中的 21 个独特的处理 x 块组合,因此实际上每个处理 x 块都会多次添加吸附率和 Kfs 值,对应于时间和 CI 条目(每个处理 x 块有 7 到 12 个时间和 CI 条目)。3 个“缺失条目”是从第二个表中删除的异常值。

我想运行一个非线性模型(CI = 吸附率 * sqrt(Time) + Kfs)。它必须为我提供每个处理 x 块组合的输出。我希望将 Time、CI、Sorptivity 和 Kfs 的原始值以及与每次时间测量对应的预测 CI 值作为输出。

在 ChatGPT 的帮助下,我设置了以下代码,但我遇到了一个错误,并且由于 erorr 在宏中,我收到了一个额外的假脱机错误,这意味着我无法确定错误在哪里。我希望有人能帮我弄清楚问题出在哪里以及如何纠正它。

%macro run_model(treatment, block, time, ci, s, k);
data temp;/* Create local macro variables */
    merge infiltration  (where=(Treatment = "&treatment" and Block = "&block"))
        InfilNewData  (where=(Treatment = "&treatment" and Block = "&block"));
    by Treatment Block;
    Time = &time;
    CI = &ci;
    Sorptivity = &s;
    Kfs = &k;
run;
proc nlin data=temp;
    parms Sorptivity = &s Kfs = &k;
    model CI = Sorptivity * sqrt(Time) + Kfs;
    output out=PredictedCI_&treatment Block=Block Time=Time CI=CI Sorptivity=Sorptivity Kfs=Kfs predicted=PredictedCI;
run;
data PredictedCI_&treatment;/* Add a Treatment group identifier to the output */
    set PredictedCI_&treatment;
    Treatment = "&treatment";
    Block = "&block";
run;
%mend;

%macro run_all_models;
%local treatment_list block_list s_list k_list time_list ci_list;
/* Create macro variable lists within the macro */
proc sql noprint;
  select distinct Treatment into :treatment_list separated by ' ' from InfilDF;
  select distinct Block into :block_list separated by ' ' from InfilDF;
  select distinct Sorptivity into :s_list separated by ' ' from InfilNewData;
  select distinct Kfs into :k_list separated by ' ' from InfilNewData;
  select distinct Time into :time_list separated by ' ' from InfilDF;
  select distinct CI into :ci_list separated by ' ' from InfilDF;
quit;
/* Loop over the macro variables and run the models */
%do i = 1 %to %sysfunc(countw(&treatment_list));
    %let current_treatment = %scan(&treatment_list, &i);
    %let current_block = %scan(&block_list, &i);
    %let current_s = %scan(&s_list, &i);
    %let current_k = %scan(&k_list, &i);
    %let current_time = %scan(&time_list, &i);
    %let current_ci = %scan(&ci_list, &i);
    %run_model(&current_treatment, &current_block, &current_time, &current_ci, &current_s, &current_k);
    proc print data=PredictedCI_&current_treatment;
    run;
%end;
%mend;

%run_all_models;

在run_model宏中,我最初设置为获取仅来自名为 InfilDF 的组合 DF 的局部变量,该 DF 具有上述所有 4 个数值变量。然后,我尝试将其更改为您在此处看到的代码,该代码从两个原始表中提取变量。结果/错误是一样的:data temp

      WHERE (Treatment='Biochar10tha') and (Block='Block1');  
22: LINE and COLUMN cannot be determined.
ERROR 22-322: Syntax error, expecting one of the following: ;, (, /, ESS, H, J, L95,
              L95M, LCL, LCLM, LMAX, OUT, P, PARMS, PRED, PREDICTED, PRES, PROJRES,
              PROJSTUDENT, PRSTUD, R, RESEXPEC, RESIDUAL, REXPEC, SSE, STDI, STDP, STDR,
              STUDENT, U95, U95M, UCL, UCLM, WEIGHT.
76: LINE and COLUMN cannot be determined.
ERROR 76-322: Syntax error, statement will be ignored.

数据和代码可在以下网址获得:https://github.com/AnelD13/SAS_infiltration。我发现错误的两个主要位置是在设置临时 DF 的第一个宏和模型代码本身中。吸附率和 Kfs 宏变量的设置方式可能存在问题,因为以前的错误都指向了这一点。

SAS 宏局部 变量

评论

0赞 Reeza 9/15/2023
我看到这在治疗上循环,但没有阻止?此外,当在循环的 i 索引处选择它时,k 会是什么。如何创建该循环/索引根本没有意义。
0赞 Reeza 9/15/2023
PROC NLIN 支持 BY 语句,鉴于您的语句,是否有某些原因在这里不起作用?
0赞 Segeana 9/15/2023
我几乎不知道我在这里到底在做什么,我在SAS根本没有做过太多事情。Iyt 的意思是循环治疗和阻断。我不想要 k (Kfs) 或 s(吸附率)的预测值,我想使用模型中的值来预测 CI。我没有意识到 proc nlin 有一个 by 语句 - 会尝试。

答:

1赞 Segeana 9/15/2023 #1

对于任何寻找类似答案的人,我最终简化了它。我问题中的宏创建了局部变量,这些变量旨在以迭代方式输入到 nlm 中,目的是创建一个“旁循环”。我来自 R 背景,并在那里使用了 smiliar 方法。一旦模型遍历了所有处理变量和模块变量,它就应该输出到新的数据框,使用初始输入数据框中的变量以及新创建的变量。我让它在 3 次 spearate 场合工作,但不知道如何或为什么,但预测的输出总是相差甚远,并且数据帧输出也具有来自初始数据帧的错误输入变量值。

根据上面的评论,我尝试使用 SAS 的内置 nlin 函数和 by-statement 来循环访问 Treatment 和 Block。我已经在其他程序中使用了副语句,但在我提出问题之前没有想过要为这个程序这样做。下面的代码与宏中的过程基本相同,但没有尝试在外部循环它。然后,对两个数据帧进行简单的合并,而不是按照宏循环进行合并。

proc nlin data=InfilDF;
    parms Sorptivity=0.01 Kfs=0.01;
    model CI = Sorptivity * sqrt(Time) + Kfs;
    by Treatment Block;
    output out=PredictedResults predicted=PredictedCI;
run;
data InfilPredicted;
    retain Block Treatment Time CI Infiltration Sorptivity Kfs; /* I had to do this as my Time 
                variable showed up empty*/
    merge InfilDF PredictedResults;
    by Treatment Block;
run;
proc sort data=InfilPredicted;
by Treatment Block Time;
run;
proc print data=InfilPredicted;
run;

这是一个更简单的解决方案,与SAS程序中的许多简单性一致。它可以防止添加不必要的代码或变量。