2016-02-03 5 views
2

У меня есть что-то похожее на код ниже, я хочу создать каждую комбинацию из двух символов в моих строках, а затем подсчитать каждое из них и сохранить в таблице. Я буду менять оператор substr на цикл do для повторения всей строки. Но сейчас я просто хочу, чтобы первая пара символов работала;Создайте динамическое имя переменной SAS из строки

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 transpose, поскольку я не могу пройти через строку, чтобы создать все пары символов. Я должен будет вручную создать их, и у меня есть до 500 символов в строке, плюс я хотел бы искать 3 и 4 строковых шаблона.

+0

Знаете ли вы имена потенциальных переменных раньше времени или это только обнаружено в первом чтении? Невозможно выполнить то, что вы хотите выше, но если вы заранее знаете имена, если вы можете создать эти переменные, а затем создать массив с ними, VNAME получит имя, которое имеет переменная, и вы можете выполнять итерацию по массиву. – Joe

ответ

0

Вы не можете делать то, о чем вы просите напрямую. Вам придется либо использовать макроязык, либо использовать PROC TRANSPOSE. SAS не позволяет вам ссылаться на данные в том виде, в котором вы пытаетесь, потому что он должен был сконструировать имена переменных и так, прежде чем читать что-либо.

Я отправлю другое решение, в котором используется макрос язык, но я подозреваю, что TRANSPOSE является конечным решением здесь; нет никакой практической причины, по которой это не должно работать с вашей реальной проблемой, и если у вас возникнут проблемы с этим, вам следует помочь - разместите цикл do и то, что вы хотите, и мы можем, конечно, помочь. Вероятно, вам просто нужно поставить OUTPUT в цикл 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; 
0

Вот решение, которое использует CALL EXECUTE, а не на языке макросов, как я решил, что было на самом деле является лучшим решением. Я бы не использовал это в производстве, но он, надеюсь, показывает концепцию (в частности, я бы не запускал PROC DATASETS для каждой переменной отдельно - я бы выполнил все переименования в одну строку, а затем запустил это в конце. ., показывающие, как этот процесс может работать)

Это имеет преимущество времени, а именно - CALL EXECUTE происходит после того, как шаг данных заканчивается, поэтому, тем моментом вы знаете, что переменных карты, в какую точку данных. Он должен передавать данные дважды, чтобы отбросить ложные переменные, хотя, если вы либо знаете фактическое количество переменных, которые хотите иметь, либо если вы в порядке с избыточными переменными, зависающими вокруг, было бы нормально пропустить что и PROC DATASETS фактически не открывают весь набор данных, поэтому он будет довольно быстрым (даже выше, с пятью вызовами довольно быстро).

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; 
+0

Для CARDS используйте опцию INFILE EOF –

+0

Что скачет вас, правда? Я предпочитаю избегать этого, кроме случаев, когда это действительно необходимо ... и в сценарии реального использования END будет доступен. – Joe

+0

Я бы не назвал это прыжком. Он обеспечивает механизм, необходимый для обнаружения конца файла без буферизации и принятия соответствующих мер. Опция предвзятого утверждения, которая для меня нова. –