Arrays SAS-如何使用数组跳过循环中的某些列
我有一个包含多个数字和字符列的数据集。大多数字符列都是简单的“是”或“否”问题,但有些不是。对于数字列,我觉得我有一个有效的解决方案。对于字符列,我尝试最小化它,但没有成功我想做并尝试的是一个循环,它指出当j=var4的列数时,使用大/小/IU替换。这个想法是,这将减少代码的“变量依赖性”,因为我可以在%let语句中更改var4的变量,并且代码的长度将更短 由于dim语句给出了数字或字符列的总数,我猜有一些语句给出了特定变量的列位置,我将用于secound循环。但是,我没有发现这样的说法 我的代码到目前为止Arrays SAS-如何使用数组跳过循环中的某些列,arrays,if-statement,sas,Arrays,If Statement,Sas,我有一个包含多个数字和字符列的数据集。大多数字符列都是简单的“是”或“否”问题,但有些不是。对于数字列,我觉得我有一个有效的解决方案。对于字符列,我尝试最小化它,但没有成功我想做并尝试的是一个循环,它指出当j=var4的列数时,使用大/小/IU替换。这个想法是,这将减少代码的“变量依赖性”,因为我可以在%let语句中更改var4的变量,并且代码的长度将更短 由于dim语句给出了数字或字符列的总数,我猜有一些语句给出了特定变量的列位置,我将用于secound循环。但是,我没有发现这样的说法 我的代
%let v1 = var1;
%let v2 = var2;
%let v3 = var3;
%let v4 = var4;
data have;
infile datalines delimiter = '|';
input surveyYear id var1 var2$ var3 var4$20. ;
datalines;
2016 | 1 | 10 | Yes | 5 | BIG
2016 | 2 | 6 | YES | 8 | Big
2016 | 3 | 8 | YEs | 99999 | big
2016 | 4 | . | yes | 5 | 99999
2017 | 5 | 6 | No | 7 | SMALL
2017 | 6 | 5 | Ye | . | small
2017 | 7 | 99999 | no | 3 | 99999
2018 | 8 | 3 | 99999 | 1 | SMall
2018 | 9 | 2 | iu | 2 | IU
2018 | 10 | 15 | IU | . | Iu
;
run;
data want;
set have;
array var_num[*] _numeric_;
do i=3 to dim(var_num);
if var_num[i] = 99999 then var_num[i] = .;
end;
array var_cha[*] _character_;
do j=1 to dim(var_cha);
var_cha(j) = upcase(var_cha(j));
if var_cha[j] = 'YES' then var_cha[j] = 'Yes';
if var_cha[j] = 'NO' then var_cha[j] = 'No';
if var_cha[j] = 'IU' then var_cha[j] = 'IU';
if var_cha[j] = '99999' then var_cha[j] = 'IU';
if var_cha[j] = '' then var_cha[j] = 'IU';
end;
/* Integrate the code below into the loop*/
if &v4 = 'BIG' then &v4 = 'Big city';
if &v4 = 'SMALL' then &v4 = 'Small city';
if &v4 = 'IU' then &v4 = 'Unknow city size';
if &v4 = '99999' then &v4 = 'Unknow city size';
drop i j;
run;
我想如何编程的概念性想法
data want;
set have;
array var_cha[*] _character_;
do j=1 to dim(var_cha);
var_cha(j) = upcase(var_cha(j));
/* All of the if statements for the yes, no and IU */
if var_cha[j] = ColumnNumerOfVar4 then do;
/* where ColumnNumerOfVar4 is equal to the column number of var4*/
if var_cha[j] = 'BIG' then var_cha[j] = 'Big city';
if var_cha[j] = 'SMALL' then var_cha[j] = 'Small city';
if var_cha[j] = 'IU' then var_cha[j] = 'Unknow city size';
if var_cha[j] = '99999' then var_cha[j] = 'Unknow city size';
end;
end;
run;
如果需要获取数组中变量的名称,可以使用vName函数:
if (vName(var_cha[j]) = 'var4') then do;
/* where ColumnNumberOfVar4 is equal to the column number of var4*/
if var_cha[j] = 'BIG' then var_cha[j] = 'Big city';
if var_cha[j] = 'SMALL' then var_cha[j] = 'Small city';
if var_cha[j] = 'IU' then var_cha[j] = 'Unknow city size';
if var_cha[j] = '99999' then var_cha[j] = 'Unknow city size';
end;
据我所知,这将解决你的问题。但是,如果还想获取特定变量的列号,可以通过查看sasHelp.vColumns并将该数字放入宏变量中来实现。或者在数据步骤开始时执行类似操作:
retain columnNumberOfVar4;
if (_n_ eq 1) then do;
id = open("work.have","i");
num = attrn(id,"nvars");
columnNumberOfVar4 = varNum(id, 'var4');
rc = close(id);
end;
但我相信这并不是您在本例中需要做的。也许我并不完全理解您想要什么,但看起来您只是想用do循环应用的变量名列表创建一个宏变量,并使用它来定义数组
%let yesnovars=var4 ;
array yesno &yesnovars;
然后,您可以执行如下循环:
do j=1 to dim(yesno);
yesno(j) = upcase(yesno(j));
if yesno[j] = 'YES' then yesno[j] = 'Yes';
if yesno[j] = 'NO' then yesno[j] = 'No';
if yesno[j] = 'IU' then yesno[j] = 'IU';
if yesno[j] = '99999' then yesno[j] = 'IU';
if yesno[j] = '' then yesno[j] = 'IU';
end;
但看起来您只是想对值应用格式。因此,如果定义了$YESNO格式和$CITYSIZE格式,则可以执行类似操作,将所有字符变量从原始值转换为格式化值。只需记住将它们定义为足够长的时间来保存格式化的值,而不仅仅是原始值
format var2 $yesno. var4 $citysize.;
array _c _character_;
do j=1 to dim(_c);
_c(j)=vvalue(_c(i));
end;
或者更好地定义信息并在读取原始数据时使用它们。我认为您希望VNAME()函数测试变量是否是您认为的那样?我不想测试变量是否是我认为的那样。我想知道他们的数字位置。在我的例子中,dim(var_cha)会给我一个最大j值3。J=1是var2所有字符列的数字位置,J=2是var4所有字符列的数字位置。我想要的是将var4(在本例2中)的数字位置放在X中,然后声明如果var_cha[j]=X,则执行以下if语句。但我不知道如何找到X。老实说,不清楚你想做什么。J是索引,这是变量在数组中的位置。答案的多样性表明,其他人也不清楚你在问什么。我想我解释得更好,但正如答案的多样性所表明的,你是对的!我试图循环通过一定数量的数字和字符变量,但跳过其中的一个特定变量。假设我有10个字符变量。其中8个变量有简单的“是”或“否”答案,但其中2个字符变量有相同的输入(例如“大”和“小”),但应该有不同的输出(一个变量中“大”是“大城市”,另一个变量中是“大蛋糕”)。我试着在循环中确定一种方法,用它们的特定文本替换这2个变量。换句话说,将第一个代码(到目前为止我的代码标题)中的最后一部分代码集成到循环中。我发布的代码将完成我需要它做的事情,但我认为如果一切都在循环中,它会更干净。在matlab中,我可以通过[row-col]来确定它。我希望这能让事情变得更清楚?我已经有了替换是、否和IU部分的代码。我想要的是将大/小/IU集成到循环中,但在循环中声明,如果j等于某个变量(例如Var4),则执行其他stud。例如,在我的真实数据集中,有几个变量具有相同的输入(大、小或IU),但它们的含义不同。因此,我想知道是否有一种简单的方法来确定这些变量的列位置。例如,MATLAB[row col]我要说的是不需要在同一个循环中。为每个要重新编码的变量类创建单独的数组和循环。这会更清楚。它感觉这可能接近我想要的,但是你可以通过它的变量名而不是它的数字位置来确定位置。但是,当我尝试运行代码时,它会说“需要一个算术运算符”。对于if station,哪部分运行时有错误?我想我都查过了。要通过名称获取变量位置,可以使用varNum(id,“var4”)。它将为您提供名为“var4”的变量在数据集中的位置。如果(vName(var_cha[j])='var4',则执行;获取错误。表示'var4'需要算术运算符。看起来这是一个旧版本。很抱歉,一开始我犯了一个错误,错过了一个右大括号。应该是(vName(var_cha[j])='var4')这取决于任务,但在大多数情况下,我引用的是变量名,而不是它的位置。我认为SAS/Base中的数组功能非常差,因此您必须使用SAS数据集(表)并按名称引用所有变量。