是否有一种在SAS中转换大表的有效方法

时间:2013-05-29 09:12:09

标签: sas transpose

我在SAS中有一个我需要转置的数据集。它有形式 id日期类型值 我需要把它转换成 id date valueoftype1 valueoftype2 ...

有没有有效的方法来实现这一目标?我的数据是huuuge。

例如;

data one; 
input ID date type $ value; 

cards; 
1 2001 A 2
1 2002 A 4
1 2001 B 3
2 2001 B 1
2 2002 A 5
2 2002 C 2
2 2003 C 5
3 2001 B 6
4 2002 B 8
4 2003 B 4
4 2001 A 2
;

我希望将其转换为以下形式; (最后三列是valA,valB,valC)

1 2001 2 3 .
1 2002 4 . .
2 2001 . 1 .
2 2002 5 . 2
2 2003 . . 5
3 2001 . 6 .
4 2001 2 . .
4 2002 . 8 .
4 2003 . 4 .

3 个答案:

答案 0 :(得分:2)

PROC TRANSPOSE将非常非常有效地执行此操作,我冒昧地说,与其他任何DBMS的最有效方法相同或更好。您的数据也已经为该方法组织得很好。您只需按ID DATE进行排序,除非您已经拥有该组合的索引(如果您有数十亿条记录是必需的IMO)。没有其他解决方案可以接近,除非你有足够的内存将它全部放在内存中 - 这对于那个大小的数据集来说相当疯狂(即使是10亿条记录也至少有7GB,如果你有数百万的ID那么它就清楚了不是一个1字节的ID;我猜是25-30 GB或更多。)

proc sort data=one;
by id date;
run;
proc transpose data=one out=want;
by id date;
id type;
var value;
run;

对我的系统进行了一次天真的测试,其中包括以下内容:

data one; 
do id = 1 to 1e6;
  do date = '01JAN2010'd to '01JAN2012'd;
    type = byte(ceil(ranuni(7)*26)+64);
    value = ceil(ranuni(7)*20);
    output;
  end;
end;
run;
proc sort data=one;
by id date;
run;
proc transpose data=one out=want;
by id date;
id type;
var value;
run;

该数据集压缩约20GB(OPTIONS COMPRESS = YES)。最初写入花了大约4分15秒,花了11分钟进行排序,花了45分钟到PROC TRANSPOSE,写了一个~100GB的压缩文件。我猜这是你能做的最好的事情;在这45分钟内,超过20分钟可能写出来(5倍大的数据集将占用超过5倍的时间来写出来,加上压缩开销);我当时也在做其他事情,因此CPU时间可能会膨胀,因为它没有得到我的整个处理器(这是我的桌面,4核i5)。我认为这根本不是特别不合理的处理时间。

您可能会考虑查看自己的需求,也许转置并不是您想要的 - 您真的想长大吗?您可以在不转置整个数据集的情况下实现您的实际目标(您的分析/等)。

答案 1 :(得分:0)

if first.date then a=.;b=.;c=.;d=.; 

必须替换为:

if first.date then do;
    a=.;b=.;c=.;d=.;
end;

if first.date then call missing(a,b,c,d);

也代替

if last.date then do; output; a=.;b=.;c=.;d=.; end;

现在,它应该足够了:

if last.date then output;

我猜一个datastep总是比大数据上的PROC TRANSPOSE更有效率。限制是您必须找到转置变量的不同值并为这些变量创建新变量。我认为这是PROC TRANSPOSE的开销 - 它首先找出值。 (对不起,我编辑了你自己的答案,所以现在可能还不清楚是什么问题。)

答案 2 :(得分:0)

替代数据步骤方法(DOW-loop):

proc sort data = one;
  by ID date;
run;

data two;
  do _n_ = 1 by 1 until(last.date);
    set one;
    by ID DATE;
    if type = "A" then valA = value;
    else if type = "B" then valB = value;
    else if type = "C" then valC = value;
  end;
  drop value;
run;

在我的系统上,使用数据集大小为Joe使用的1/10,排序需要2分钟,使用proc转置需要9分40秒。 DOW循环在7分4秒内做同样的事情。在这个特殊情况下,它并不是非常令人印象深刻,但它比proc转置有一个很大的优势:你可以使用它在一次通过中转置多个变量。这是我使用的代码:

data one; 
do id = 1 to 1e5;
  do date = '01JAN2010'd to '01JAN2012'd;
    type = byte(ceil(ranuni(7)*26)+64);
    value = ceil(ranuni(7)*20);
    output;
  end;
end;
run;

data two;
  do _n_ = 1 by 1 until(last.DATE);
    set one;
    array vals[26] val65-val90;
    by ID DATE;
    do i = 1 to 26;
      if type = byte(64 + i) then vals[i] = value;
    end;
  end;
  drop value i;
run;

动态重命名所有26个转置类型变量有点棘手,但这可以通过调用execute来完成:

data _null_;
  call execute('proc datasets lib = work nolist;');
  call execute('modify two;');
  call execute('rename');
  do i = 1 to 26;
    call execute(compress('val' || i + 64) || ' = ' || compress('val' || byte(64+i)));
  end;
  call execute(';');
  call execute('run;');
  call execute('quit;');
run;