【问题标题】:rename SAS variables in reverse order using do loops使用 do 循环以相反的顺序重命名 SAS 变量
【发布时间】:2018-05-11 00:02:52
【问题描述】:

我有 10 个变量 (var1-var10),我需要在 SAS 中重命名 var10-var1。所以基本上我需要将 var10 重命名为 var1、var9 var2、var8 var3 等等。

这是我根据这篇论文使用的代码,http://analytics.ncsu.edu/sesug/2005/PS06_05.PDF

%macro new;

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %do j=1 %to 10 %by 1;
                var.&i=var.&j
            %end;
        %end;
        ;
%mend new;

%new;

我遇到的问题是它只将 var1 重命名为 var10,因此是 do-loop 中的最后一次迭代。

提前感谢您的帮助!

艾米丽

【问题讨论】:

  • 我想知道为什么投反对票?这是一个相当高质量的问题;它相当基本,但它具有我们在一个好问题中寻找的所有元素 - 重现的详细代码、不正确行为的明确陈述和特异性。
  • 如果您只想重命名变量而不创建数据集的新副本,请使用 proc datasets 来执行此操作,使用 reeza 答案中的重命名语句。

标签: sas rename sas-macro do-loops


【解决方案1】:

您真的不需要这样做,您可以使用列表引用重命名变量,特别是如果它们已按顺序命名。

即:

rename var1-var10 = var10-var1;

这是一个证明这一点的测试:

data check;
    array var(10) var1-var10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    output;
run;

data want;
    set check;
    rename var1-var10 = var10-var1;
run;

如果您出于某种原因确实需要手动操作,那么您需要两个数组。分配变量后,您就丢失了旧变量,因此您无法再访问它。所以你需要某种临时数组来保存新值。

【讨论】:

  • 谢谢瑞萨!!我不知道它是如此简单。出于某种原因,我认为您不能在重命名语句中使用连字符。
【解决方案2】:

虽然 Reeza 的回答是正确的,但可能值得了解一下为什么您的方法不起作用 - 这是另一种合理的方法,如果复杂的话。

首先,您有一些小的语法问题,例如分号位置错误、句点位置错误(它们结束宏变量名称,而不是开始它们),以及缺少运行语句;我们将忽略这些并在更改代码时对其进行修复。

其次,你有两个嵌套循环,当你真的不想要的时候。您不想为 i 的每次迭代(总共 100 次)执行 10 次内部代码(每次 j 迭代一次);您想为ij 的每次迭代执行一次内部代码。

让我们看看这个修复给我们带来了什么:

data temp;
  array var[10];
  do _n_ = 1 to 15;
    do _i = 1 to 10;
      var[_i] = _i;
    end;
    output;
  end;
  drop _i;

run;

%macro new();

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            var&i.=var&j.;
        %end;
    run;

%mend new;

%new();

好的,现在这更接近你想要的了;但你有问题,对吧?您会丢失后半部分的值(好吧,实际上是前半部分,因为您使用了%by -1),因为它们没有存储在单独的位置。

您可以通过在其中暂存原始变量的临时转储区域来做到这一点,从而允许您同时更改值并访问原始变量。一种常见的基于数组的方法(而不是基于宏)以这种方式工作。这是它在宏中的样子。

%macro new();

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            _var&i. = var&i.;
            var&i.=coalesce(_var&j., var&j.);
        %end;
        drop _:;
    run;

%mend new;

我们使用coalesce(),它返回第一个非缺失参数;对于前五次迭代,它使用var&j.,但后五次迭代使用_var&j.。除了使用这个函数,你也可以只预填充变量。

一个更好的选择是使用rename,就像 Reeza 在上面的答案中所做的那样,但这里提供的东西更像你原来的答案:

%macro new();

    data temp_one;
        set temp;
        rename
        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            var&i.=var&j.
        %end;
        ;
    run;

%mend new;

这是有效的,因为rename 实际上并没有移动任何东西 - 它只是将“请将此值写入输出时_____变量”的值设置为不同的值。

这实际上是链接论文中的作者提出的,我怀疑你只是错过了rename 位。这就是为什么你在整个事情之后有一个分号(因为它只是一个 rename 语句,所以只有一个 ; )而不是在每次迭代之后都有单独的分号(因为你需要分配)。

【讨论】:

  • 谢谢乔!你的回答非常彻底。我只是好奇,代码顶部的 n =1 to 15 对应什么?我也不太清楚为什么在 var&i 和 var&j 之前有一个 _...谢谢!
  • 我只是在第一部分创建了一些示例数据; _n_ 是一个自动变量,通常对应于数据步骤迭代,并且在像上面这样我们进行自己的迭代的数据步骤中,通常使用 _n_ 作为迭代器来明确这一点(并采取自动删除变量这一事实的优势)。
  • 对于_var&j_var&i,它们是临时变量数组,用于将原始值存储在var1-var10 中,以便您可以访问它们,尽管实际中的值已更改变量。原始数组的只读镜像排序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
  • 2018-10-03
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多