SAS-跨行复制多个观察结果

SAS-跨行复制多个观察结果,sas,rows,replicate,Sas,Rows,Replicate,我的数据结构如下所示: DATA have ; INPUT famid indid implicate imp_inc; CARDS ; 1 1 1 40000 1 1 2 25000 1 1 3 34000 1 1 4 23555 1 1 5 49850 1 2 1 1000 1 2 2 2000 1 2 3 3000 1 2 4 4000 1 2 5 5000 1 3 1 . 1 3 2 . 1 3 3 . 1 3 4 . 1 3 5 . 2 1 1 40000 2 1 2 45000

我的数据结构如下所示:

DATA have ; 
INPUT famid indid implicate imp_inc; 
CARDS ; 
1 1 1 40000
1 1 2 25000
1 1 3 34000
1 1 4 23555
1 1 5 49850
1 2 1 1000
1 2 2 2000
1 2 3 3000
1 2 4 4000
1 2 5 5000
1 3 1 .
1 3 2 .
1 3 3 .
1 3 4 .
1 3 5 .
2 1 1 40000
2 1 2 45000
2 1 3 50000
2 1 4 34000
2 1 5 23500
2 2 1 .
2 2 2 .
2 2 3 .
2 2 4 .
2 2 5 .
2 3 1 41000
2 3 2 39000
2 3 3 24000
2 3 4 32000
2 3 5 53000
RUN ;
DATA want ; 
INPUT famid indid implicate imp_inc; 
CARDS ; 
1 1 1 40000
1 1 2 25000
1 1 3 34000
1 1 4 23555
1 1 5 49850
1 2 1 40000
1 2 2 25000
1 2 3 34000
1 2 4 23555
1 2 5 49850
1 3 1 40000
1 3 2 25000
1 3 3 34000
1 3 4 23555
1 3 5 49850
2 1 1 40000
2 1 2 45000
2 1 3 50000
2 1 4 34000
2 1 5 23500
2 2 1 40000
2 2 2 45000
2 2 3 50000
2 2 4 34000
2 2 5 23500
2 3 1 40000
2 3 2 45000
2 3 3 50000
2 3 4 34000
2 3 5 23500
RUN ;
因此,我们有家庭id、个人id、牵连人数和每个牵连的估算收入

我需要的是复制每个家族中第一个个体的结果,每个家族中其余的个体都有五个牵连,取代我们之前对这些细胞的价值观,如下所示:

DATA have ; 
INPUT famid indid implicate imp_inc; 
CARDS ; 
1 1 1 40000
1 1 2 25000
1 1 3 34000
1 1 4 23555
1 1 5 49850
1 2 1 1000
1 2 2 2000
1 2 3 3000
1 2 4 4000
1 2 5 5000
1 3 1 .
1 3 2 .
1 3 3 .
1 3 4 .
1 3 5 .
2 1 1 40000
2 1 2 45000
2 1 3 50000
2 1 4 34000
2 1 5 23500
2 2 1 .
2 2 2 .
2 2 3 .
2 2 4 .
2 2 5 .
2 3 1 41000
2 3 2 39000
2 3 3 24000
2 3 4 32000
2 3 5 53000
RUN ;
DATA want ; 
INPUT famid indid implicate imp_inc; 
CARDS ; 
1 1 1 40000
1 1 2 25000
1 1 3 34000
1 1 4 23555
1 1 5 49850
1 2 1 40000
1 2 2 25000
1 2 3 34000
1 2 4 23555
1 2 5 49850
1 3 1 40000
1 3 2 25000
1 3 3 34000
1 3 4 23555
1 3 5 49850
2 1 1 40000
2 1 2 45000
2 1 3 50000
2 1 4 34000
2 1 5 23500
2 2 1 40000
2 2 2 45000
2 2 3 50000
2 2 4 34000
2 2 5 23500
2 3 1 40000
2 3 2 45000
2 3 3 50000
2 3 4 34000
2 3 5 23500
RUN ;
在这个例子中,我试图只复制一个变量,但在我的项目中,我将不得不对几十个变量进行复制

到目前为止,我提出了以下解决方案:

%let implist_1=imp_inc;

%macro copyv1(list);
    %let nwords=%sysfunc(countw(&list));
    %do i=1 %to &nwords;
    %let varl=%scan(&list, &i);
        proc means data=have max noprint;
            var &varl;
            by famid implicate;
            where indid=1;
            OUTPUT OUT=copy max=max_&varl;  
        run;
        data want;
            set have;
            drop &varl;
        run;
        data want (drop=_TYPE_ _FREQ_);
            merge want copy;
            by famid implicate;
            rename max_&varl=&varl;
        run;
    %end;
%mend;
%copyv1(&imp_list1);
这适用于一个或两个变量。然而,在一个大小为1.5 GB的数据集中对400个变量执行此操作时,速度会非常慢

我很确定有一种更快的方法可以通过某种形式的proc-sql或first.var等实现这一点,但我对SAS比较陌生,到目前为止,我还没有找到更好的解决方案

非常感谢您的支持


致以最诚挚的问候

使用一点SQL,这相当简单:

proc sql;
create table want as 
  select a.famid, a.indid, a.implicate, b.* from 
  have a 
  left join (
    select * from have 
    group by famid 
    having indid = min(indid)
  ) b 
  on
        a.famid = b.famid 
    and a.implicate = b.implicate
  order by a.famid, a.indid, a.implicate
  ;
quit;
其思想是将表连接到其自身的子集,该子集只包含与每个族中第一个个体对应的行

它被设置为拾取每个族中编号最低的个体,因此即使没有indid=1的行,它也可以工作。如果确定始终存在这样的行,则可以使用稍微简单一点的查询:

proc sql;
create table want as 
  select a.famid, a.indid, a.implicate, b.* from 
  have(sortedby = famid) a 
  left join have(where = (indid = 1)) b 
  on
        a.famid = b.famid 
    and a.implicate = b.implicate
  order by a.famid, a.indid, a.implicate
  ;
quit;

指定sortedby=famid会向查询优化程序提供一个提示,提示它可以跳过联接所需的一个初始排序,这可能会稍微提高性能。

是的,这可以在数据步骤中使用第一个。通过by声明提供参考

data want;
  set have (keep=famid indid implicate imp_inc /* other vars */);

  by famid indid implicate; /* by implicate is so step logs an error (at run-time) if data not sorted */

  if first.famid then if indid ne 1 then abort;

  array across imp_inc           /* other vars */;
  array hold [1,5] _temporary_;  /* or [<n>,5] where <n> means the number of variables in the across array */

  if indid = 1 then do;          /* hold data for 1st individuals implicate across data */
    do _n_ = 1 to dim(across);
      hold[_n_,implicate] = across[_n_];  /* store info of each implicate of first individual */
    end;
  end;
  else do;
    do _n_ = 1 to dim(across);
      across[_n_] = hold[_n_,implicate];  /* apply 1st persons info to subsequent persons */
    end;
  end;
run;
由于单次传递数据,数据步骤可能会大大加快,但是在运行时计算所有这些讨厌的[]数组地址会带来内部处理成本;时间,而这一成本在某种程度上可能会产生影响


SQL语法更简单,理解更清晰,如果have数据集未排序或在by组中有一些特殊的排序,SQL也可以工作。

感谢您的回复。我对sql了解不多,但这似乎复制了所有变量,对吗?如果我想选择一个子集,我需要将select imp_inc而不是select*,对吗?您还可以指定一个逗号分隔的变量列表,或使用数据集选项,例如select*from havekeep=key1-key3 firstvar lastvarIs源数据已经按FAMID排序,以便第一条记录是要复制的记录?如果要复制的值在第一条记录上丢失了怎么办?使用SQL过程,我的整个程序每次迭代运行需要11分钟;使用此解决方案需要9分钟。谢谢!伟大的欢迎使用堆栈溢出,了解有关