Создание одной записи из нескольких записей в SAS

У меня есть набор данных SAS под названием coaches_assistants со следующей структурой. Всегда есть только две записи на TeamID.

TeamID     Team_City    CoachCode
123        Durham       Head_242
123        Durham       Assistant_876
124        London       Head_876
124        London       Assistant_922
125        Bath         Head_667
125        Bath         Assistant_786
126        Dover        Head_544
126        Dover        Assistant_978
...        ...          ....

Что я хотел бы сделать с этим, так это создать набор данных с дополнительным полем с именем AssistantCode и сделать его похожим на:

TeamID     Team_City    HeadCode   AssistantCode
123        Durham       242        876
124        London       876        922
125        Bath         667        786
126        Dover        544        978
...        ...          ...        ...

Если возможно, я хотел бы сделать это за один шаг DATA (хотя я понимаю, что сначала мне может понадобиться шаг PROC SORT). Я знаю, как это сделать на python, ruby ​​или на любых традиционных языках сценариев, но не знаю, как это сделать в SAS.

Как лучше всего это сделать?


person Clay    schedule 06.07.2013    source источник


Ответы (3)


Вот два возможных решения (одно с использованием шага данных по запросу, а другое с использованием PROC SQL):

data have;
   length TeamID $3 Team_City CoachCode $20; 
   input TeamID $ Team_City $ CoachCode $;
   datalines;
123        Durham       Head_242
123        Durham       Assistant_876
124        London       Head_876
124        London       Assistant_922
125        Bath         Head_667
125        Bath         Assistant_786
126        Dover        Head_544
126        Dover        Assistant_978
run;

/* A data step solution */
proc sort data=have;
   by TeamID;
run;

data want1(keep=TeamID Team_City HeadCode AssistantCode);
   /* Define all variables, retain the new ones */
   length TeamID $3 Team_City $20 HeadCode $3 AssistantCode $3; 
   retain HeadCode AssistantCode; 
   set have;
      by TeamID;
   if CoachCode =: 'Head'
      then HeadCode = substr(CoachCode,6,3);
      else AssistantCode = substr(CoachCode,11,3);
   if last.TeamID;
run;

/* An SQL solution */
proc sql noprint;
   create table want2 as
   select TeamID
        , max(Team_City) as Team_City
        , max(CASE WHEN CoachCode LIKE 'Head%'
                   THEN substr(CoachCode,6,3) ELSE ' '
              END) LENGTH=3 as HeadCode
        , max(CASE WHEN CoachCode LIKE 'Assistant%'
                   THEN substr(CoachCode,11,3) ELSE ' '
              END) LENGTH=3 as AssistantCode
   from have
   group by TeamID;
quit;

PROC SQL имеет то преимущество, что не требует предварительной сортировки данных.

person BellevueBob    schedule 06.07.2013
comment
Спасибо за подробности. Я выбрал первый подход, и он отлично сработал. Я еще не углублялся в SAS SQL, поэтому посмотрю на него позже, когда у меня будет возможность. - person Clay; 07.07.2013
comment
Когда вы используете оператор BY в пошаговой обработке данных, автоматически создаются специальные переменные для облегчения обработки. Для каждой переменной, указанной в операторе, создаются две точечные переменные: FIRST.variable и LAST.variable, которые определяют относительное положение наблюдателя в группе. if LAST.TeamID; - это оператор подмножества IF, используемый для вывода только одного объекта на каждый TeamID. - person BellevueBob; 08.07.2013
comment
Спасибо за объяснение. Я не знал о FIRST и LAST. - person Clay; 08.07.2013

Хотя это возможно сделать за один этап данных, я обычно считаю, что такого рода проблемы лучше решать в PROC TRANSPOSE. Меньше ручного кодирования таким образом и больше гибкости для новых вещей (скажем, появилось новое значение «HeadAssistant», это сразу сработает).

data have;
length coachcode $25;
input TeamID     Team_City  $  CoachCode $;
datalines;
123        Durham       Head_242
123        Durham       Assistant_876
124        London       Head_876
124        London       Assistant_922
125        Bath         Head_667
125        Bath         Assistant_786
126        Dover        Head_544
126        Dover        Assistant_978
;;;;
run;

data have_t;
set have;
id=scan(coachcode,1,'_');
val = scan(coachcode,2,'_');
keep teamId team_city id val;
run;

proc transpose data=have_t out=want(drop=_name_);
by teamID team_city;
id id;
var val;
run;
person Joe    schedule 06.07.2013
comment
Мне нравится, насколько чисто это выглядит, но когда я попытался запустить его с моим набором данных (с более чем 120000 наблюдений), таблица want по какой-то причине была создана без каких-либо столбцов. Попробую позже. Спасибо! - person Clay; 07.07.2013

Предполагается, что вы отсортировали данные по teamID, а главные тренеры всегда идут раньше помощников. Предостережение: непроверено (мне действительно нужно снова получить доступ к SAS ....)

data want (drop=nc coachcode);
    set have;
    length headcode assistantcode $3;
    retain headcode;
    by teamid;
    nc = length(coachcode);
    if substr(coachcode, 1, 4) = 'Head' then
        headcode = substr(coachcode, nc-2, nc);
    else
        assistantcode = substr(coachcode, nc-2, nc);
    if last.teamid;
run;
person Hong Ooi    schedule 06.07.2013
comment
SCAN, вероятно, лучше для этого, чем подстрока :) - person Joe; 06.07.2013
comment
@Joe Спасибо, забыл об этом. - person Hong Ooi; 06.07.2013