通过重复值填充SAS变量

通过重复值填充SAS变量,sas,Sas,我有一个SAS表,其中有许多缺少的值。这只是一个简单的例子。 真正的表要大得多>1000行,而且数字不一样。但同样的是,我有一个a列,没有缺失的数字。列b和c的序列比a的长度短 a b c 1 1b 1000 2 2b 2000 3 3b 4 5 6 7 我想要的是用重复的序列填充b和c,直到它们的列满为止。结果应该如下所示: a b c 1 1b 1000 2 2b 2000 3 3b 1000 4 1b 2000

我有一个SAS表,其中有许多缺少的值。这只是一个简单的例子。 真正的表要大得多>1000行,而且数字不一样。但同样的是,我有一个a列,没有缺失的数字。列b和c的序列比a的长度短

a b  c 
1 1b 1000
2 2b 2000
3 3b
4 
5
6
7
我想要的是用重复的序列填充b和c,直到它们的列满为止。结果应该如下所示:

    a   b   c
    1   1b  1000
    2   2b  2000
    3   3b  1000
    4   1b  2000
    5   2b  1000
    6   3b  2000
    7   1b  1000
1229  data want ;
1230    set have(drop=_all_);
1231    %include code / source2;
NOTE: %INCLUDE (level 1) file CODE is file .../#LN00026.
1232 +_point1 =mod(_n_-1,7 )+1;
1233 +set have(keep=a ) point=_point1 ;
1234 +_point2 =mod(_n_-1,3 )+1;
1235 +set have(keep=b ) point=_point2 ;
1236 +_point3 =mod(_n_-1,2 )+1;
1237 +set have(keep=c ) point=_point3 ;
NOTE: %INCLUDE (level 1) ending.
1238  run;

NOTE: There were 7 observations read from the data set WORK.HAVE.
NOTE: The data set WORK.WANT has 7 observations and 3 variables.

我试图创建一个宏,但它变得凌乱。

用值填充一个临时数组,然后检查行并添加适当的值

设置数据

data have;
infile datalines delimiter="|";
input a b $ c;
datalines;
1|1b|1000
2|2b|2000
3|3b|    
4|  |    
5|  |    
6|  |    
7|  |    
;
获取非空值的计数

proc sql noprint;
select count(*)
    into :n_b
    from have
    where b ^= "";

select count(*)
    into :n_c
    from have
    where c ^=.;
quit;
现在,通过重复每个数组的内容来填充缺少的值

data want;
set have;
/*Temporary Arrays*/
array bvals[&n_b] $ 32  _temporary_;
array cvals[&n_c]  _temporary_;

if _n_ <= &n_b then do;
    /*Populate the b array*/
    bvals[_n_] = b;
end;
else do;
    /*Fill the missing values*/
    b = bvals[mod(_n_+&n_b-1,&n_b)+1];
end;

if _n_ <= &n_c then do;
    /*populate C values array*/
    cvals[_n_] = c;
end;
else do;
    /*fill in the missing C values*/
    c = cvals[mod(_n_+&n_c-1,&n_c)+1];
end;
run;

用值填充临时数组,然后检查行并添加适当的值

设置数据

data have;
infile datalines delimiter="|";
input a b $ c;
datalines;
1|1b|1000
2|2b|2000
3|3b|    
4|  |    
5|  |    
6|  |    
7|  |    
;
获取非空值的计数

proc sql noprint;
select count(*)
    into :n_b
    from have
    where b ^= "";

select count(*)
    into :n_c
    from have
    where c ^=.;
quit;
现在,通过重复每个数组的内容来填充缺少的值

data want;
set have;
/*Temporary Arrays*/
array bvals[&n_b] $ 32  _temporary_;
array cvals[&n_c]  _temporary_;

if _n_ <= &n_b then do;
    /*Populate the b array*/
    bvals[_n_] = b;
end;
else do;
    /*Fill the missing values*/
    b = bvals[mod(_n_+&n_b-1,&n_b)+1];
end;

if _n_ <= &n_c then do;
    /*populate C values array*/
    cvals[_n_] = c;
end;
else do;
    /*fill in the missing C values*/
    c = cvals[mod(_n_+&n_c-1,&n_c)+1];
end;
run;

我想,散列的解决方案在这里是最灵活的

data have;
infile datalines delimiter="|";
input a b $ c;
datalines;
1|1b|1000
2|2b|2000
3|3b|    
4|  |    
5|  |    
6|  |    
7|  |    
;;;;
run;


%let vars=b c;

data want;
  set have;
  rownum = _n_;
  if _n_=1 then do;
    declare hash hoh(ordered:'a');
    declare hiter hih('hoh');
    hoh.defineKey('varname');
    hoh.defineData('varname','hh');
    hoh.defineDone();

    declare hash hh();

    do varnum = 1 to countw("&vars.");
        varname = scan("&vars",varnum);
        hh = _new_ hash(ordered:'a');
        hh.defineKey("rownum");
        hh.defineData(varname);
        hh.defineDone();
        hoh.replace();
    end;
  end;

  do rc=hih.next() by 0 while (rc=0);
    if strip(vvaluex(varname)) in (" ",".")  then do;
        num_items = hh.num_items;
        rowmod = mod(_n_-1,num_items)+1;
        hh.find(key:rowmod);
    end;
    else do;
      hh.replace();
    end;
    rc = hih.next();
  end;
  keep a &Vars.;
run;

基本上,为您使用的每个变量构建一个哈希。它们都被添加到散列中。然后我们对其进行迭代,并搜索以查看是否填充了请求的变量。如果是,则将其添加到其哈希中。如果不是,那么我们将检索相应的解决方案。

我怀疑,散列解决方案在这里是最灵活的

data have;
infile datalines delimiter="|";
input a b $ c;
datalines;
1|1b|1000
2|2b|2000
3|3b|    
4|  |    
5|  |    
6|  |    
7|  |    
;;;;
run;


%let vars=b c;

data want;
  set have;
  rownum = _n_;
  if _n_=1 then do;
    declare hash hoh(ordered:'a');
    declare hiter hih('hoh');
    hoh.defineKey('varname');
    hoh.defineData('varname','hh');
    hoh.defineDone();

    declare hash hh();

    do varnum = 1 to countw("&vars.");
        varname = scan("&vars",varnum);
        hh = _new_ hash(ordered:'a');
        hh.defineKey("rownum");
        hh.defineData(varname);
        hh.defineDone();
        hoh.replace();
    end;
  end;

  do rc=hih.next() by 0 while (rc=0);
    if strip(vvaluex(varname)) in (" ",".")  then do;
        num_items = hh.num_items;
        rowmod = mod(_n_-1,num_items)+1;
        hh.find(key:rowmod);
    end;
    else do;
      hh.replace();
    end;
    rc = hih.next();
  end;
  keep a &Vars.;
run;

基本上,为您使用的每个变量构建一个哈希。它们都被添加到散列中。然后我们对其进行迭代,并搜索以查看是否填充了请求的变量。如果是,则将其添加到其哈希中。如果不是,那么我们将检索相应的一个。

假设您可以通过计算列中有多少非缺失值来判断每个变量要使用多少行,那么您可以使用此代码生成技术生成一个数据步骤,该步骤将使用POINT=option SET语句循环第一个Nx观测值变量X

首先获取变量名列表

proc transpose data=have(obs=0) out=names ;
  var _all_;
run;
然后使用它们生成一个PROC SQL select语句,以计算每个变量的非缺失值的数量

filename  code temp ;
data _null_;
  set names end=eof ;
  file code ;
  if _n_=1 then put 'create table counts as select ' ;
  else put ',' @;
  put 'sum(not missing(' _name_ ')) as ' _name_ ;
  if eof then put 'from have;' ;
run;

proc sql noprint;
%include code /source2 ;
quit;
然后将其转置,使每个变量名有一行,但这次它也有COL1中的计数

proc transpose data=counts out=names ;
  var _all_;
run;
现在,使用它生成数据步骤所需的SET语句,以从输入创建输出

filename code temp;
data _null_;
  set names ;
  file code ;
  length pvar $32 ;
  pvar = cats('_point',_n_);
  put pvar '=mod(_n_-1,' col1 ')+1;' ;
  put 'set have(keep=' _name_ ') point=' pvar ';' ;
run;
现在使用生成的语句

data want ;
  set have(drop=_all_);
  %include code / source2;
run;
因此,对于包含变量A、B和C以及7个总观测值的示例数据文件,生成数据步骤的日志如下所示:

    a   b   c
    1   1b  1000
    2   2b  2000
    3   3b  1000
    4   1b  2000
    5   2b  1000
    6   3b  2000
    7   1b  1000
1229  data want ;
1230    set have(drop=_all_);
1231    %include code / source2;
NOTE: %INCLUDE (level 1) file CODE is file .../#LN00026.
1232 +_point1 =mod(_n_-1,7 )+1;
1233 +set have(keep=a ) point=_point1 ;
1234 +_point2 =mod(_n_-1,3 )+1;
1235 +set have(keep=b ) point=_point2 ;
1236 +_point3 =mod(_n_-1,2 )+1;
1237 +set have(keep=c ) point=_point3 ;
NOTE: %INCLUDE (level 1) ending.
1238  run;

NOTE: There were 7 observations read from the data set WORK.HAVE.
NOTE: The data set WORK.WANT has 7 observations and 3 variables.

假设您可以通过计算列中有多少非缺失值来告诉每个变量要使用多少行,那么您可以使用此代码生成技术生成一个数据步骤,该步骤将使用POINT=option SET语句循环变量X的第一个Nx观察值

首先获取变量名列表

proc transpose data=have(obs=0) out=names ;
  var _all_;
run;
然后使用它们生成一个PROC SQL select语句,以计算每个变量的非缺失值的数量

filename  code temp ;
data _null_;
  set names end=eof ;
  file code ;
  if _n_=1 then put 'create table counts as select ' ;
  else put ',' @;
  put 'sum(not missing(' _name_ ')) as ' _name_ ;
  if eof then put 'from have;' ;
run;

proc sql noprint;
%include code /source2 ;
quit;
然后将其转置,使每个变量名有一行,但这次它也有COL1中的计数

proc transpose data=counts out=names ;
  var _all_;
run;
现在,使用它生成数据步骤所需的SET语句,以从输入创建输出

filename code temp;
data _null_;
  set names ;
  file code ;
  length pvar $32 ;
  pvar = cats('_point',_n_);
  put pvar '=mod(_n_-1,' col1 ')+1;' ;
  put 'set have(keep=' _name_ ') point=' pvar ';' ;
run;
现在使用生成的语句

data want ;
  set have(drop=_all_);
  %include code / source2;
run;
因此,对于包含变量A、B和C以及7个总观测值的示例数据文件,生成数据步骤的日志如下所示:

    a   b   c
    1   1b  1000
    2   2b  2000
    3   3b  1000
    4   1b  2000
    5   2b  1000
    6   3b  2000
    7   1b  1000
1229  data want ;
1230    set have(drop=_all_);
1231    %include code / source2;
NOTE: %INCLUDE (level 1) file CODE is file .../#LN00026.
1232 +_point1 =mod(_n_-1,7 )+1;
1233 +set have(keep=a ) point=_point1 ;
1234 +_point2 =mod(_n_-1,3 )+1;
1235 +set have(keep=b ) point=_point2 ;
1236 +_point3 =mod(_n_-1,2 )+1;
1237 +set have(keep=c ) point=_point3 ;
NOTE: %INCLUDE (level 1) ending.
1238  run;

NOTE: There were 7 observations read from the data set WORK.HAVE.
NOTE: The data set WORK.WANT has 7 observations and 3 variables.

这些数据最初都在同一个数据集中吗?看起来是错误的合并?是的,实际上是错误的合并。但这并没有改变目标。我想知道如何从向量a、b和c到这个最终的表。我问的原因是,如果您已经在单独的数据集中有数据,那么可以更容易地加载到临时数组或设置SQL步骤。先“后退”一步可能会使这个问题更容易处理。你已经有了解决方案,所以请随意忽略这一点,因为你已经实现了你的“目标”。你可能是对的。我稍后会更新这个问题。这些数据集最初都在同一个数据集中吗?看起来是错误的合并?是的,实际上是错误的合并。但这并没有改变目标。我想知道如何从向量a、b和c到这个最终的表。我问的原因是,如果您已经在单独的数据集中有数据,那么可以更容易地加载到临时数组或设置SQL步骤。先“后退”一步可能会使这个问题更容易处理。你已经有了解决方案,所以请随意忽略这一点,因为你已经实现了你的“目标”。你可能是对的。我以后会更新这个问题,看起来很棒。我得去看看。似乎解决了我的问题这看起来很棒。我得去看看。似乎解决了我的问题,这是有效的,但不是一般的。在我真正的问题中,我有30个变量。这是可行的,但不是一般的。在我真正的问题中,我有30个变量。