2017-06-23 133 views
0

我有一个SAS表,其中有很多缺失值。这只是一个简单的例子。 真正的表格要大得多(> 1000行),数字也不一样。但同样的是,我有一个没有缺失数字的专栏。列b和c的序列比a的长度短。通过重复值填充SAS变量

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 

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

+0

在同一数据集所有这些是最初?看起来像一个不好的合并? – Reeza

+0

是的,它实际上是一个“坏”合并。但是这不会影响目标。我想知道如何从矢量a,b和c得到这张决赛桌。 – fossekall

+0

我问这个问题的原因是,如果你已经有了单独的数据集中的数据,它可以更容易地加载到临时数组或设置一个SQL步骤。首先“迈出”一步可能会使这个问题更容易处理。您已经有解决方案,因此您可以随意忽略这一点,因为您已经实现了“目标”。 – Reeza

回答

1

哈希的哈希值的解决方案是最灵活的在这里,我怀疑。

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; 

基本上,一个散列是为您正在使用的每个变量而构建的。它们都被添加到哈希散列。然后我们遍历它,并搜索以查看所请求的变量是否已填充。如果是,那么我们将它添加到它的散列。如果不是,那么我们检索合适的一个。

0

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

设置数据

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; 
+0

这看起来不错。我必须检查它。似乎解决了我的问题 – fossekall

0
data want; 
    set have; 
    n=mod(_n_,3); 
    if n=0 then b='3b'; 
    else b=cats(n,'b'); 
    if n in (1,0) then c=1000; 
    else c=2000; 
    drop n; 
run; 
+0

这工作,但不是一般的。在我真正的问题中,我确实有30个变量。 – fossekall

1

假设你能告诉多少行每个变量的使用计数非遗漏值有多少列,那么你可以使用此代码生成技术来生成将使用POINT =选项设置数据的步骤语句循环遍历变量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; 

现在使用它来生成DATA步骤所需的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个总观测日志中产生的数据步的示例数据文件是这样的:

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.