从字符串创建动态SAS变量名

从字符串创建动态SAS变量名,sas,Sas,我有一些类似于下面的代码,我想在我的字符串中创建每2个字符的组合,然后计算每个组合的出现次数并存储在一个表中。我将把substr语句更改为do循环,以迭代整个字符串。但现在我只想让第一对角色开始工作 data temp; input cat $50.; call symput ('regex', substr(cat,1,2)); &regex = count(cat,substr(cat,1,2)); datalines; bvbvbsbvbvbvbvblb dvdvdvlxvdvdg

我有一些类似于下面的代码,我想在我的字符串中创建每2个字符的组合,然后计算每个组合的出现次数并存储在一个表中。我将把substr语句更改为do循环,以迭代整个字符串。但现在我只想让第一对角色开始工作

data temp;
input cat $50.;
call symput ('regex', substr(cat,1,2));
&regex = count(cat,substr(cat,1,2));
datalines;
bvbvbsbvbvbvbvblb
dvdvdvlxvdvdgd
cdcdcdcdvdcdcdvcdcded
udvdvdvdevdvdvdvdvdvdvevdedvdv
dvdkdkdvdkdkdkudvkdkd
kdkvdkdkvdkdkvudkdkdukdvdkdkdkdv
dvkvwduvwdedkd
;
run;
预期结果

cat bv  dv  cd  ud  kd
####    6               
####        4           
####            8       
####                1   
####        3           
####                    9
####        1       

我不希望使用proc转置,因为我无法循环字符串来创建所有字符对。我必须手动创建它们,每个字符串最多有500个字符,另外我想搜索3个和4个字符串模式。

您不能直接执行要求的操作。您必须使用宏语言,或者使用PROC转置。SAS不允许您以尝试的方式引用数据,因为它必须在读入任何内容之前已经构造了变量名等

我将发布一个使用宏语言的不同解决方案,但我怀疑转置是这里的最终解决方案;没有实际的理由认为这不适用于您的实际问题,如果您在这方面遇到问题,应该可以提供帮助-发布do循环和您想要的内容,我们当然可以提供帮助。可能您只需要将输出放入do循环中

data temp;
input cat $50.;
cat_val = substr(cat,1,2);
_var_ = count(cat,substr(cat,1,2));
output;
datalines;
bvbvbsbvbvbvbvblb
dvdvdvlxvdvdgd
cdcdcdcdvdcdcdvcdcded
udvdvdvdevdvdvdvdvdvdvevdedvdv
dvdkdkdvdkdkdkudvkdkd
kdkvdkdkvdkdkvudkdkdukdvdkdkdkdv
dvkvwduvwdedkd
;
run;

proc transpose data=temp out=temp_T(drop=_name_);
  by cat notsorted;  *or by some ID variable more likely;
  id cat_val;
  var _var_;
run;

这里有一个使用
callexecute
而不是宏语言的解决方案,因为我认为这实际上是一个更好的解决方案。我不会在生产中使用它,但希望它能显示出这个概念(特别是,我不会对每个变量分别运行
PROC DATASETS
——我会将所有重命名合并成一个字符串,然后在最后运行它。我认为这更适合于显示流程如何工作。)

这充分利用了时间的优势,即,
调用执行
发生在数据步骤终止之后,因此在该点上,您知道哪些变量映射到哪个数据点。它确实需要传递两次数据才能删除伪变量,但是如果您知道想要拥有的变量的实际数量,或者如果您对多余的变量感到满意,则可以跳过这一步,并且
PROC DATASETS
实际上并没有打开整个数据集,因此速度相当快(即使是上面的五个电话也相当快)


您是否提前知道可能的变量名称,或者只是在第一次读取时才发现?不可能完全按照上面的要求执行,但是如果您提前知道这些名称,如果您可以创建这些变量,然后使用它们设置数组,那么VNAME将为您提供变量的名称,并且您可以在数组。对于卡片,使用infle选项EOF,这会让你感到很不自在,不是吗?我宁愿避免这样做,除非真的有必要…在实际的用例场景中,END是可用的。我不会称之为跳跃。它提供了一种机制,你需要检测未缓冲文件的结尾,并采取适当的行动对我来说,这是一种新的陈述选择偏见。好吧,这基本上是一种“后路”…很难说服自己克服这种偏见;)
data temp;
  input cat $50.;
  array _catvars[50]; *arbitrary 50 chosen here - pick one big enough for your data;
  array _catvarnames[50] $ _temporary_;
  cat_val = substr(cat,1,2);
  _iternum = whichc(cat_val, of _catvarnames[*]);

  if _iternum=0 then do;
    _iternum = whichc(' ',of _catvarnames[*]);
    _catvarnames[_iternum]=cat_val;
    call execute('proc datasets lib=work; modify temp; rename '||vname(_catvars[_iternum])||' = '||cat_val||'; quit;');
  end;
  _catvars[_iternum]= count(cat,substr(cat,1,2));
  if _n_=7 then do;   *this needs to actually be a test for end-of-file (so add `end=eof` to the set statement or infile), but you cannot do that in DATALINES so I hardcode the example.;
    call execute('data temp; set temp; drop _catvars'||put(whichc(' ',of _catvarnames[*]),2. -l)||'-_catvars50;run;');
  end;
datalines;
bvbvbsbvbvbvbvblb
dvdvdvlxvdvdgd
cdcdcdcdvdcdcdvcdcded
udvdvdvdevdvdvdvdvdvdvevdedvdv
dvdkdkdvdkdkdkudvkdkd
kdkvdkdkvdkdkvudkdkdukdvdkdkdkdv
dvkvwduvwdedkd
;
run;