从当前观察中读取下一个k观察

时间:2015-05-19 09:15:28

标签: sas

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   .      .

可能的解决方案

  1. 按相反顺序排序 - >获得先前的k记录 - >把它们整理回来。
  2. 当没有。观察量很大,这不应该是一种理想的方式。

    1. proc expand。我不熟悉它,因为它从未在我的电脑上获得许可。

    2. 在数据步骤中使用point

    3. 数据步骤中的
    4. retain语句。我不确定这是如何运作的。

2 个答案:

答案 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;