【问题标题】:Creating a single record from multiple records in SAS从 SAS 中的多个记录创建单个记录
【发布时间】:2013-07-06 17:28:13
【问题描述】:

我有一个名为 coaches_assistants 的 SAS 数据集,其结构如下。每个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 中做到这一点。

最好的方法是什么?

【问题讨论】:

    标签: sas datastep


    【解决方案1】:

    虽然可以在一个数据步中完成,但我通常发现这种问题在 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;
    

    【讨论】:

    • 我喜欢它看起来多么干净,但是当我尝试使用我的数据集(具有 120,000 多个观察值)运行它时,由于某种原因,want 表创建时没有任何列。我稍后再试一次。谢谢!
    【解决方案2】:

    这里有两种可能的解决方案(一种使用请求的数据步骤,另一种使用 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 的优点是不需要你提前对数据进行排序。

    【讨论】:

    • 感谢您提供详细信息。我采用了第一种方法,它就像一个魅力。 SAS SQL我还没有深入研究过,以后有机会再看。
    • 在数据步处理中使用BY语句时,会自动创建特殊变量来辅助处理。为语句中列出的每个变量创建两个“点”变量:FIRST.variableLAST.variable,它们标识组内 obs 的相对位置。 if LAST.TeamID; 是一个“subsetting-IF”语句,用于每个 TeamID 仅输出一个 obs。
    • 感谢您的解释。我不知道FIRSTLAST
    【解决方案3】:

    这假设您已按 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;
    

    【讨论】:

    • SCAN 可能比子字符串更好:)
    • @Joe 谢谢,忘了那个。
    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多