SAS Do循环:如何使用在变量名中包含迭代器的比较运算符?

SAS Do循环:如何使用在变量名中包含迭代器的比较运算符?,sas,iterator,do-loops,Sas,Iterator,Do Loops,我有一个类似Cars1的数据集(使用下面的代码生成),变量名中有年份 %macro test1(); data cars1; set sashelp.cars (keep = make model); %do i = 2012 %to 2014; make&i. = make; %end; run; %mend test1; %test1(); 看起来像这样 Make Model make2012 make201

我有一个类似Cars1的数据集(使用下面的代码生成),变量名中有年份

%macro test1();
data cars1;
    set sashelp.cars (keep = make model);

    %do i = 2012 %to 2014;
        make&i. = make;
    %end;
run;
%mend test1;
%test1();
看起来像这样

Make    Model             make2012  make2013    make2014
Acura   MDX               Acura     Acura       Acura
Acura   RSX Type S 2dr    Acura     Acura       Acura
Acura   TSX 4dr           Acura     Acura       Acura

我想在3年(2012-2014)内迭代,根据与各自值的比较,为我在Cars1中创建的3个变量中的每一个创建一个分类数据集(make_2012_cat等)。因此,如果我是“Acura”,我有一个声明。make2021 ne“Acura”也一样。由于某种原因,比较不起作用,我每次都会使用默认值(“它不可比较:-(”)

我最终只得到了默认值。我在宏内外都尝试过这一点,并对调用迭代器的方式进行了大量调整。我也尝试过声明全局变量,但现在我只是在旋转我的轮子。非常感谢任何帮助

Make   make_2012_cat        make_2013_cat        make_2014_cat 
Acura  It's not an Acura.   It's not an Acura.   It's not an Acura. 
Acura  It's not an Acura.   It's not an Acura.   It's not an Acura. 
Acura  It's not an Acura.   It's not an Acura.   It's not an Acura. 

因此,您需要理解宏语言和数据步语言之间的区别。这是两种不同的语言,实际上并不是做相同的事情

%if
和其他宏语言内容只影响正在编译的代码的文本。它们将SAS程序更改为其他SAS程序。但它们与数据无关

步骤:

  • 解析宏语言
  • 编写SAS数据步程序
  • 运行SAS数据步骤程序(一次加载一行数据等)
  • 因此,您需要将数据步骤(
    if
    )与宏语言(
    %if
    )分开

    把它变成

    %do i = 2012 %to 2014;
        if make&i. eq "Acura" then do;
            make_&i._cat = "It's an Acura!";
        end;
        else if make&i. ne "Acura" then do;          **note I added 'else' here;
            make_&i._cat = "It's not an Acura.";
        end;
        else do;
            make_&i._cat = "It's not comparable :-(";
        end;
    %end;
    
    宏语言正在发挥它的作用——它正在创造

    if make_2012_cat = ...;
    
    if make_2013_cat = ...;
    
    if make_2014_cat = ...;
    
    但是数据步语言实际上是用来将
    make\u 2012\u cat
    变量值与
    'Acura'
    进行比较的


    请注意另一件事;这不一定是非常惯用的SAS。这是合法的,很多人都这么做,但它并没有真正最大限度地使用SAS功能。最好是让
    make_cat
    ,然后为201220132014设置不同的行,如果可以的话。也许你不能-也许你有一个很好的理由-但是当你r变量名不包含数据(它们确实包含数据)。也许您的实际示例有所不同,但我发现大约80%的时候,当我看到人们大致上这样做时,在不同的数据结构中可以做得更好


    要完全在数据步骤中执行此操作,需要阵列

    data cars1;
        set sashelp.cars (keep = make model);
    
        array makes[3] make_2012-make_2014;
        do _i = 1 to dim(makes);
           makes[_i] = make;
        end;
    run;
    
    data cars2;
      set cars1;
      array makes[3] make_2012-make_2014;
      array makes_cat[3] make_cat_2012-make_cat_2014;  *slightly different, easier;
      do _i = 1 to dim(makes);
        if makes[_i] eq "Acura" then makes_cat[_i] = "It's an Acura!";
        else if makes[_i] ne "Acura" then makes_cat[_i] = "It's not an Acura.";
      end;
    run;
    

    没错!不过,还有一个问题……为什么这些都不能在常规数据步骤中工作?我最初尝试在数据步骤中工作,但得到了奇怪的结果。我现在猜测if语句比较使用数据步骤,但执行(do)部分)使用宏语言,这对我来说似乎是违反直觉的。对吗?它肯定会在数据步骤中起作用,只是不会像你那样。在数据步骤中,你很可能会使用数组。我将在一个示例中进行编辑。主要的是,数据步骤本身无法编辑-有很多方法可以做到这一点,但在大多数情况下,宏语言ge编辑代码,数据步骤编辑数据。
    if make_2012_cat = ...;
    
    if make_2013_cat = ...;
    
    if make_2014_cat = ...;
    
    data cars1;
        set sashelp.cars (keep = make model);
    
        array makes[3] make_2012-make_2014;
        do _i = 1 to dim(makes);
           makes[_i] = make;
        end;
    run;
    
    data cars2;
      set cars1;
      array makes[3] make_2012-make_2014;
      array makes_cat[3] make_cat_2012-make_cat_2014;  *slightly different, easier;
      do _i = 1 to dim(makes);
        if makes[_i] eq "Acura" then makes_cat[_i] = "It's an Acura!";
        else if makes[_i] ne "Acura" then makes_cat[_i] = "It's not an Acura.";
      end;
    run;