Here's a very similar question
我的问题与上述链接中的问题略有不同。
背景
我有一个包含每小时数据的数据集。因此每个对象每天有24条记录。现在,我想创建K
个新列,表示每个对象的下一个1,2,...K
小时记录。如果不存在,请将其替换为缺失值。
K
是动态的,由用户定义。
必须保留原始订单。无论是在数据步骤中保证还是在最后使用排序。
我正在寻找一种有效的方法来实现这一目标。
示例
原始数据:
Object Hour Value
A 1 2.3
A 2 2.3
A 3 4.0
A 4 1.3
给定K = 2
,所需的输出为
Object Hour Value Value1 Value2
A 1 2.3 2.3 4.0
A 2 2.3 4.0 1.3
A 3 4.0 1.3 .
A 4 1.3 . .
可能的解决方案
当没有。观察量很大,这不应该是一种理想的方式。
proc expand
。我不熟悉它,因为它从未在我的电脑上获得许可。
在数据步骤中使用point
。
retain
语句。我不确定这是如何运作的。
答案 0 :(得分:3)
您可以转换小时数,然后在每个对象内自由访问前面的小时数。只需设置K的值并生成一些虚拟数据:
* Assign K ;
%let K=3 ;
%let Kn=value&k;
* Generate test objects each containing 24 hourly records ;
data time ;
do object=1 to 10 ;
do hour=1 to 24 ;
value=round(ranuni(1)*10,0.1) ;
output ;
end ;
end ;
run ;
编辑:我更新了以下步骤,因为意识到转置不是必需的。一步完成这一切可使CPU时间提高约20%
使用24小时值的数组,每小时循环一次do i=1 to &k
:
* Populate K variables ;
data output(keep=object hour value value1-&kn ) ;
set time ;
by object ;
retain k1-k24 . ;
array k(2,24) k1-k24 value1-value24 ;
k(1,hour)=value ;
if last.object then do hour=1 to 24 ;
value=k(1,hour) ;
do i=1 to &k ;
if hour+i <=24 then k(2,i)=k(1,hour+i) ;
else k(2,i)=.;
end ;
output ;
end ;
run ;
答案 1 :(得分:3)
假设这是作为宏变量提供的,这很容易通过左右合并来完成。当然比K的转置要快于总记录数的K,并且可能比循环POINT更快。
基本上,您将原始数据集合并到自身,并使用FIRSTOBS
将每个连续合并迭代的起点向下推一个。如果您有需要保护的BY组,这需要一些额外的工作,但这通常不会太难管理。
以下是使用SASHELP.CLASS的示例:
%let K=5;
%macro makemergesets(k=, datain=, varin=, keepin=);
%do _i = 2 %to &k;
&datain (firstobs=&_i rename=&varin.=&varin._&_i. keep=&keepin. &varin.)
%end;
%mend makemregesets;
data class_all;
merge sashelp.class
%makemergesets(k=&k,datain=sashelp.class, varin=age,keepin=)
;
run;