使用 do 循环以相反的顺序重命名 SAS 变量
rename SAS variables in reverse order using do loops
我有 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 循环中的最后一次迭代。
在此先感谢您的帮助!
艾米丽
您真的不需要这样做,您可以使用列表引用重命名变量,尤其是在它们已按顺序命名的情况下。
即:
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;
如果您出于某种原因确实需要手动执行此操作,那么您需要两个数组。一旦你分配了变量,你就失去了旧变量,所以你不能再访问它了。所以你需要某种临时数组来保存新值。
虽然 Reeza 的回答是正确的,但可能值得仔细研究一下为什么您的方法不起作用 - 这是另一种合理的方法,如果令人费解的话。
首先,您有一些小的语法问题,例如分号放错地方、句号放在错误的位置(它们 end 宏变量名称,而不是开始它们),以及缺少 运行 语句;我们将忽略这些并在更改代码时修复它们。
其次,你有两个嵌套循环,当你真的不想要它的时候。您不想为 i
的每次迭代执行 10 次内部代码(每次 j
的迭代一次)(总共 100 次);您想为 i
和 j
的每次迭代执行一次内部代码。
让我们看看这个修复给我们带来了什么:
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()
其中 returns 第一个非缺失参数;对于前五次迭代,它使用 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
实际上并没有移动东西 - 它只是将 "please write this value out to _____ variable on output" 的值设置为不同的值。
这实际上是作者在链接论文中提出的建议,我怀疑您只是错过了 rename
位。这就是为什么你在整个事情之后有一个分号(因为它只是一个 rename
语句,所以只有一个 ;
)而不是在每次迭代之后有单独的分号(因为你需要分配)。
我有 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 循环中的最后一次迭代。
在此先感谢您的帮助!
艾米丽
您真的不需要这样做,您可以使用列表引用重命名变量,尤其是在它们已按顺序命名的情况下。
即:
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;
如果您出于某种原因确实需要手动执行此操作,那么您需要两个数组。一旦你分配了变量,你就失去了旧变量,所以你不能再访问它了。所以你需要某种临时数组来保存新值。
虽然 Reeza 的回答是正确的,但可能值得仔细研究一下为什么您的方法不起作用 - 这是另一种合理的方法,如果令人费解的话。
首先,您有一些小的语法问题,例如分号放错地方、句号放在错误的位置(它们 end 宏变量名称,而不是开始它们),以及缺少 运行 语句;我们将忽略这些并在更改代码时修复它们。
其次,你有两个嵌套循环,当你真的不想要它的时候。您不想为 i
的每次迭代执行 10 次内部代码(每次 j
的迭代一次)(总共 100 次);您想为 i
和 j
的每次迭代执行一次内部代码。
让我们看看这个修复给我们带来了什么:
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()
其中 returns 第一个非缺失参数;对于前五次迭代,它使用 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
实际上并没有移动东西 - 它只是将 "please write this value out to _____ variable on output" 的值设置为不同的值。
这实际上是作者在链接论文中提出的建议,我怀疑您只是错过了 rename
位。这就是为什么你在整个事情之后有一个分号(因为它只是一个 rename
语句,所以只有一个 ;
)而不是在每次迭代之后有单独的分号(因为你需要分配)。