在SAS中,使用一个变量来选择要更改的另一个变量

时间:2014-04-08 18:38:00

标签: sas

我有一个包含数字标识符的变量col1-col5的数据集。标识符有2000个可能的值。我还有2000个名为dX的变量,其中X是2000个不同标识符值之一。

我想循环遍历col变量,然后将由标识符索引的相应d变量设置为等于。

例如,假设我有观察结果:

col1  col2    col3   col4   col5   d10007   d10010   d10031 ... d10057 ...
10031 10057      .      .      .        .        .        .          .

我想将d10031d10057设置为等于1。

这可能吗?如果数字是连续的,我会看到如何使用数组,但鉴于它们不是我看不懂怎么做。

2 个答案:

答案 0 :(得分:2)

可以在数组中完成。在关于数据结构的强制性论战之后,我将解释。

这看起来应该是一个垂直数据结构,即col d个变量和多行(有一些ID将它们绑在一起)。

现在,要在您拥有的结构中执行此操作:

您需要使用VNAME功能。这允许您将数组变量的名称作为字符串获取。您无法col1=10531并创建语句d10531=1,但可以查看d10531并将其值与col1进行比较。

这很慢,因为您需要在变量上循环两次,除非您有可靠的排序。您上面的数据确实遵循排序(即,COL1-n按顺序排列,D1-n按顺序排列,因此您可以从左向右移动而不是循环两次)。如果不是这种情况,那么您可能希望将call sortn与COL数组一起使用,如果这是可接受的。 Dxx数组应该能够以正确的顺序定义(如果它在数据集上的顺序不正确,你可以在宏变量中构造数组语句,在那里排序变量 - 数组语句中的顺序很重要,顺序在除非您使用d:,否则数据集不会。)

以下是从左到右结构的示例。

data want;
set have;
array cols col1-col2000;
array ds d1:; *or whatever defines d;
_citer=1;
do _diter = 1 to dim(ds) while (_citer le dim(cols)); *safety check;
  if compress(vname(ds[_diter]),,'kd') = cols[_citer] then do;
    ds[_diter] = 1;
    _citer+1;
  end;
end;
run;

迭代ds,针对当前col检查每一个,当找到匹配时,设置然后停止。这应该是灵活的 - 即使它有很多值,也适用于ds的任何结构。但是,如果cols未按值的升序排序,则 not 将起作用。如果不是,你需要设置一个内循环来检查每个cols变量,这意味着你有[dim(ds)* dim(cols)]循环迭代而不是[dim(ds)]循环迭代最多

答案 1 :(得分:2)

另一个选择是创建整个顺序D数组,然后在最后删除'假'd变量,如下所示:

data have;    
    Col1 = 10;
    Col2 = 35;
    Col3=.;
    Array Dvars {*} d1 d10 d25 d35;
run;
/* Get a list of all actual D variable /*    
proc sql noprint ;    
    select name into :dColumnsToKeep separated by ' '
    From SASHELP.VColumn
    where libname="WORK" and memname = "HAVE"
    AND name LIKE 'd%';
;quit;    
%put &dColumnsToKeep;    

data want (keep=Col: &dColumnsToKeep);    
    set have;
    array AllDVars {*} d1-d9999; *Set d9999 to as big as needed;
    array ColVars {*} Col:;
    do i = 1 to Dim(ColVars);
        if colvars(i) ne . Then AllDvars(Colvars(i)) = 1;
    end;
run;    

这可能会加快处理速度,因为它可以避免循环。虽然我不知道SAS在datastep中创建10K或100K变量的记忆方式是什么。