2

sasでカテゴリ変数を作成しようとしています。次のマクロを作成しましたが、実行しようとすると「無効なシンボリック変数名 xxx」というエラーが表示されます。これが私の目標を達成するための正しい方法でさえあるかどうかはわかりません。

これが私のコードです:

%macro addvars;
proc sql noprint;
select distinct coverageid 
into :coverageid1 - :coverageid9999999
from save.test;

%do i=1 %to &sqlobs;
%let n=coverageid&i;
%let v=%superq(&n);
%let f=coverageid_&v;
%put &f;
data save.test;
 set save.test;
%if coverageid eq %superq(&v)
  %then &f=1;
  %else &f=0;
run;
%end; 
%mend addvars;
%addvars;
4

2 に答える 2

4

マクロ コードとデータ ステップ コードを正しく組み合わせていません。%if = マクロ言語。つまり、テキスト "coverageid" が %superq(&v) が評価するテキストと等しいかどうかを実際に評価していることを意味し、coverageid 変数の内容が &v の値と等しいかどうかではありません。%if を if に変換することもできますが、それが適切に機能したとしても、非常に非効率的です (データセットを N 回書き換えているため、coverageID に 1500 の値がある場合、500MB のデータセット全体または 1500 以外を書き換えます)。 1 回ではなく 2 回)。

あなたがやりたいことが変数「coverageid」を取り、それをカバレッジIDのすべての可能な値、1/0バイナリで構成される一連の変数に変換することである場合、それを行う方法はたくさんあります。ETSモジュールにはこれを行うだけの手順があると確信していますが、頭のてっぺんから思い出したことはありません-これをSASメーリングリストに投稿するとしたら、そこにいる人の1人が間違いなく持っているでしょうすぐに。

私にとって簡単な方法は、完全にデータステップ コードでこれを行うことです。最初に COVERAGEID の潜在的な値がいくつあるかを判断し、次にそれぞれを直接値に割り当て、その値を正しい変数に割り当てます。

COVERAGEID 値が連続している場合 (つまり、1 からいくつかの数値、スキップがない、またはスキップしてもかまわない) の場合、これは簡単です。配列を設定して、それを反復処理します。それらは連続していないと仮定します。

*First, get the distinct values of coverageID.  There are a dozen ways to do this, this works as well as any;
proc freq data=save.test;
tables coverageid/out=coverage_values(keep=coverageid);
run;

*Then save them into a format.  This converts each value to a consecutive number (so the lowest value becomes 1, the next lowest 2, etc.)  This is not only useful for this step, but it can be useful in the future in converting back.;

data coverage_values_fmt;
set coverage_values;
start=coverageid;
label=_n_;
fmtname='COVERAGEF';
type='i';
call symputx('CoverageCount',_n_);
run;
*Import the created format;
proc format cntlin=coverage_values_fmt;
quit;

*Now use the created format.  If you had already-consecutive values, you could skip to this step and skip the input statement - just use the value itself;
data save.test_fin;
set save.test;
array coverageids coverageid1-coverageid&coveragecount.;
do _t = 1 to &coveragecount.;
  if input(coverageid,COVERAGEF.) = _t then coverageids[_t]=1;
  else coverageids[_t]=0;
end;
drop _t;
run;
于 2012-11-01T01:57:06.817 に答える
1

フォーマットを使用しない別の方法を次に示します。

まず、いくつかのテスト データを作成します。

data test;
    input coverageid @@;
    cards;
3 27 99 105
;
run;

次に、オブザベーションを含まず、 の各レベルに 1 つの変数を含むデータ セットを作成しますcoverageid。このアプローチでは、ここで任意の値が許可されることに注意してください。

proc transpose data=test out=wide(drop=_name_);
    id coverageid;
run;

最後に、初期データ セットとワイド データ セットを組み合わせた新しいデータ セットを作成します。次に、x の各レベルについて、各カテゴリ変数を見て、それを「オン」にするかどうかを決定します。

data want;
    set test wide;
    array vars{*} _:;
    do i=1 to dim(vars);
        vars{i} = (coverageid = substr(vname(vars{i}),2,1));
    end;
    drop i;
run;

この線

vars{i} = (coverageid = substr(vname(vars{i}),2));

さらに説明が必要な場合があります。変数の名前を返します。 invnameを指定しなかったため、すべての変数は、 などの名前になります。したがって、変数名の 2 番目の位置から始まる部分文字列を取得し、それを;と比較します。それらが同じ場合、変数を 1 に設定します。それ以外の場合は 0 と評価されます。prefixproc transpose_1_2coverageid

于 2012-11-01T20:51:07.103 に答える