从当前观察中读取下一个 k 观察
Reading next k observation from current observation
Here's a very similar question
我的问题和上面的有点不同link。
背景
我有一个包含每小时数据的数据集。所以每个对象每天有 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 . .
可能的解决方案
- 逆序排序->获取前k条记录->向后排序
当没有。观察量很大,这不应该是一个理想的方式。
proc expand
。我不熟悉它,因为它从未在我的电脑上获得许可。
在数据步骤中使用 point
。
retain
数据步骤中的语句。我不确定这是如何工作的。
您可以调换小时数,然后在每个对象中自由访问提前的小时数。只是为了设置 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 ;
假设这是作为宏变量提供的,这很容易通过边到边合并提前完成。对于比总记录数大得多的 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;
Here's a very similar question
我的问题和上面的有点不同link。
背景
我有一个包含每小时数据的数据集。所以每个对象每天有 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 . .
可能的解决方案
- 逆序排序->获取前k条记录->向后排序
当没有。观察量很大,这不应该是一个理想的方式。
proc expand
。我不熟悉它,因为它从未在我的电脑上获得许可。在数据步骤中使用
point
。retain
数据步骤中的语句。我不确定这是如何工作的。
您可以调换小时数,然后在每个对象中自由访问提前的小时数。只是为了设置 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 ;
假设这是作为宏变量提供的,这很容易通过边到边合并提前完成。对于比总记录数大得多的 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;