【问题标题】:Rolling sum for last 3 hour records of just one column in SASSAS 中仅一列的最后 3 小时记录的滚动总和
【发布时间】:2017-11-24 13:28:51
【问题描述】:

大家, 我需要计算按用户和ID_option 分组的最后 3 小时使用总和(使用是数据集中的列之一)的每条记录(每一行)。 每行(行)代表一条记录(一小时有大约百万条记录)。例如,我制作了一个只有几条记录的表(包括所需的列sum_usage_3 hour):

User  ID_option          time             usage        sum_usage_3hr
1         a1        12OCT2017:11:20:32       3             10
1         a1        12OCT2017:10:23:24       7             14
1         b1        12OCT2017:09:34:55       12            12
2         b1        12OCT2017:08:55:06       4              6
1         a1        12OCT2017:07:59:53       7              7
2         b1        12OCT2017:06:59:12       2              2

我尝试过使用类似下面的代码,它返回给我所有时间的总和,而不仅仅是过去 3 小时。我并不感到惊讶,但我不太清楚我将如何在SAS 中做到这一点。

proc sql:
CREATE table my_table
SELECT *, SUM(usage) AS sum_usage_3hr
FROM prev_table WHERE time BETWEEN TIME and intnx('second', time, -3*3600)
GROUP BY User, ID_option;
RUN;

欢迎任何帮助,谢谢。在proc sql 中没有必要这样做,如果可能的话,数据步骤也是可以接受的。我只是假设我需要某种分区。

提前致谢。

【问题讨论】:

标签: sql sas datastep


【解决方案1】:

为什么不直接使用相关子查询来获得总和?

data have ;
  input user id_option $ datetime :datetime. usage expected ;
  format datetime datetime20.;
cards;
1 a1 12OCT2017:11:20:32  3  10
1 a1 12OCT2017:10:23:24  7  14
1 b1 12OCT2017:09:34:55 12  12
2 b1 12OCT2017:08:55:06  4   6
1 a1 12OCT2017:07:59:53  7   7
2 b1 12OCT2017:06:59:12  2   2
;
proc print; run;

proc sql ;
create table want as
  select a.*
       , (select sum(b.usage) 
          from have b
          where a.user=b.user and a.id_option=b.id_option
            and b.datetime between intnx('hour',a.datetime,-3,'s') and a.datetime
         ) as usage_3hr 
  from have a
;
quit;

结果

                                                                         usage_
Obs    user    id_option                datetime    usage    expected      3hr

 1       1        a1          12OCT2017:11:20:32       3        10         10
 2       1        a1          12OCT2017:10:23:24       7        14         14
 3       1        b1          12OCT2017:09:34:55      12        12         12
 4       2        b1          12OCT2017:08:55:06       4         6          6
 5       1        a1          12OCT2017:07:59:53       7         7          7
 6       2        b1          12OCT2017:06:59:12       2         2          2

【讨论】:

  • 我现在正在测试这段代码。看起来不错,但工作了大约一小时,还在数。
  • 聚合(求和)前是否需要按某列排序?也许这会导致问题。
  • 如果您的数据很大,您可能会使用 PROC EXPAND 等 SAS/ETS 过程获得更有效的结果。或者使用数据步骤并利用您对数据排序顺序的了解。
【解决方案2】:

结果并不奇怪,因为 WHERE 子句的条件始终为真(时间必然大于或等于(或小于或等于)时间)。

我相信最简单的方法是加入表格本身,并以这种方式选择相关行:

proc sql;
    create table want as
        select  distinct a.*
                ,sum(b.USAGE) as sum_usage_3hr
            from have as a
            left join have as b
                on a.USER = b.USER
                    and a.ID_OPTION = b.ID_OPTION
                    and b.TIME between intnx('hour', a.TIME, -3) and a.TIME
        group by a.USER, a.ID_OPTION, a.TIME;
quit;

【讨论】:

  • 这需要 GROUP BY 或 SAS 将对整个结果集进行 sum() 并将 sum_usage_3hr 的相同值重新合并到所有观察结果中。
  • 这是一个很好的观点。添加了 DISTINCT 以删除重复的行。不过,您的答案要优雅得多。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
相关资源
最近更新 更多