首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SAS中查找并替换单独表中的值

在SAS中查找并替换单独表中的值
EN

Stack Overflow用户
提问于 2018-05-26 22:45:35
回答 3查看 4.2K关注 0票数 2

Dataset HAVE包含两个变量,其中有拼写错误的名称:namesfriends

代码语言:javascript
复制
Name   Age   Friend
Jon     11   Ann
Jon     11   Tom
Jimb    12   Egg
Joe     11   Egg
Joe     11   Anne
Joe     11   Tom
Jed     10   Ann

我有一个小的数据集CORRECTIONS,其中包括wrong_namesresolved_names

代码语言:javascript
复制
current_names   resolved_names
Jon             John
Ann             Anne
Jimb            Jim

我需要names中的任何名称或HAVE中的friendsCORRECTIONSwrong_names列中的名称相匹配,以便在resolved_name中对相应的字符串进行编码。生成的数据集WANT应该如下所示:

代码语言:javascript
复制
Name   Age   Friend
John    11   Anne
John    11   Tom
Jim     12   Egg
Joe     11   Egg
Joe     11   Anne
Joe     11   Tom
Jed     10   Anne

在R中,我可以使用if_else()简单地调用每个数据帧和向量,但是SAS中的数据步骤不能很好地处理多个数据集。如何使用CORRECTIONS作为查找表来进行这些替换?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-05-28 00:19:27

给定数据

代码语言:javascript
复制
*** data to validate;
data have;
length name $10. age 4. friend $10.;
input name age friend;
datalines;
Jon     11   Ann
Jon     11   Tom
Jimb    12   Egg
Joe     11   Egg
Joe     11   Anne
Joe     11   Tom
Jed     10   Ann
run;

*** lookup table;
data corrections;
length from_name $10.  to_name $10.;
input  from_name       to_name;
datalines;
Jon             John
Ann             Anne
Jimb            Jim
run;

一种SQL替代方法是对要映射的每个字段执行存在的映射选择查找。对于要映射的每个字段,这将与加入更正表一次相反。

代码语言:javascript
复制
proc sql;
  create table want1 as
  select 
      case when exists (select *       from corrections where from_name=name)
           then        (select to_name from corrections where from_name=name)
           else name
      end as name
    , age
    , case when exists (select *       from corrections where from_name=friend)
           then        (select to_name from corrections where from_name=friend)
           else friend
      end as friend
  from
    have
  ;

另一种,SAS唯一的方式,执行内联左联接是使用自定义格式。

代码语言:javascript
复制
data cntlin;
  set corrections;
  retain fmtname '$cohen'; /* the fixer */
  rename from_name=start to_name=label;
run;
proc format cntlin=cntlin;
run;

data want2;
  set have;
  name = put(name,$cohen.);
  friend = put(friend,$cohen.);
run;
票数 2
EN

Stack Overflow用户

发布于 2018-05-27 10:09:36

在SAS中有很多方法来进行查找。

但是,首先,我建议取消复制您的查找表(例如,使用PROC排序和数据步骤/Set/By)--决定保留哪个副本(如果存在的话)。

至于查找任务本身,为了简单和学习,我建议如下:

“旧学派”的方法-有利于审计输入和输出(当输入表按所需的顺序排列时,更容易验证联接的结果):

代码语言:javascript
复制
*** data to validate;
data have;
length name $10. age 4. friend $10.;
input name age friend;
datalines;
Jon     11   Ann
Jon     11   Tom
Jimb    12   Egg
Joe     11   Egg
Joe     11   Anne
Joe     11   Tom
Jed     10   Ann
run;

*** lookup table;
data corrections;
length current_names $10.  resolved_names $10.;
input current_names   resolved_names;
datalines;
Jon             John
Ann             Anne
Jimb            Jim
run;

*** de-duplicate lookup table;
proc sort data=corrections nodupkey; by current_names; run;

proc sort data=have; by name; run;   

data have_corrected;
    merge have(in=a) 
          corrections(in=b rename=(current_names=name))
          ;
    by name;
    if a;
    if b then do;
        name=resolved_names;
    end;
run;

SQL方法--避免对have表进行排序:

代码语言:javascript
复制
proc sql;
    create table have_corrected_sql as
    select 
        coalesce(b.resolved_names, a.name) as name, 
        a.age, 
        a.friend
    from work.have as a left join work.corrections as b
    on a.name eq b.current_names
    order by name;
quit;

()用于将缺少的resolved_names值(即在没有更正时)替换为have表中的名称。

编辑:为了反映昆汀(正确)的评论,我错过了名字和朋友字段的更新。

在纠正这两个字段的基础上,同样有许多方法,但其本质是,只有在查找(更正)表中存在值的情况下才更新值。哈希对象非常擅长这一点,一旦您理解了它的声明。

注:哈希对象中的任何关键字段都需要事先在Length语句上指定。

编辑:按照ChrisJ的Length语句声明的替代方法,以及我的答复(见下文)--最好在声明哈希表之前定义关键变量。

代码语言:javascript
复制
data have_corrected;
keep name age friend;
length current_names $10.;

    *** load valid names into hash lookup table;
    if _n_=1 then do;
        declare hash h(dataset: 'work.corrections');
        rc = h.defineKey('current_names');
        rc = h.defineData('resolved_names');
        rc = h.defineDone();
    end;
    do until(eof);
        set have(in=a) end=eof;
        *** validate both name fields;  
        if h.find(key:name) eq 0 then
            name = resolved_names;
        if h.find(key:friend) eq 0 then
            friend = resolved_names;
        output;
    end;
run;

编辑:回复对ChrisJ的SQL/评论

基本上,您需要将每个UPDATE语句仅限于更正表中具有名称值或朋友值的行--这是通过在指定了set var =(子句)之后添加另一个where子句来完成的。见下文。

注意:AFAIK,您的需求的SQL解决方案将需要两个基本表和查找表的1次以上的传递。

但是,查找/哈希表需要基表的一次传递、查找表的负载以及查找操作本身。你可以在日志中看到性能差异..。

代码语言:javascript
复制
proc sql;
*** create copy of have table;
create table work.have_sql as select * from work.have;
*** correct name field;
update work.have_sql as u
    set name = (select resolved_names 
                from work.corrections as n
                where u.name=n.current_names)
    where u.name in (select current_names from work.corrections)
        ;
*** correct friend field;
update work.have_sql as u
    set friend = (select resolved_names 
                  from work.corrections as n
                  where u.friend=n.current_names)
    where u.friend in (select current_names from work.corrections)
        ;
quit;
票数 3
EN

Stack Overflow用户

发布于 2018-05-27 06:12:24

试试这个:

代码语言:javascript
复制
proc sql;
create table want as
    select p.name,p.age,
        case 
            when q.current_names is null then p.friend 
            else q.resolved_names 
        end 
    as friend1
        from
            (
        select 
            case 
                when b.current_names is null then a.name 
                else b.resolved_names 
            end 
        as name,
            a.age,a.friend
        from
            have a
        left join
            corrections b
            on upcase(a.name) = upcase(b.current_names)
            ) p
        left join
            corrections q
            on upcase(p.friend) = upcase(q.current_names);
quit;  

输出:

代码语言:javascript
复制
name age friend
John 11  Anne
Jed  10  Anne
Joe  11  Anne
Jim  12  Egg
Joe  11  Egg
Joe  11  Tom
John 11  Tom

如有任何澄清,请通知我。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50547587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档