You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SAS中用条件求和检测移动观测窗口数据是否符合规则

SAS分组生成移动窗口规则列解决方案

需求说明

按ID分组,为每个观测生成名为RuleHit的新列:若当前观测的datetime往前8个月的移动窗口内,所有滞后观测(即时间早于当前观测的记录)中event列值为"B"的数量≥2,则RuleHit=1,否则为0。

输入数据集(have)

data have;
  input id datetime :datetime. event $;
  format datetime datetime.;
  datalines;
1 01JAN2022:00:00:00 A
1 15APR2022:11:46:34 B
1 23JUN2022:01:02:10 A
1 22JAN2023:14:32:58 A
1 08JUN2023:16:10:32 B
1 11JUL2023:20:39:51 A
1 28JAN2023:21:41:35 A
1 09APR2023:11:22:17 A
1 16MAY2023:22:14:23 B
1 13NOV2022:08:08:56 B
2 06FEB2022:09:23:43 B
2 12MAY2022:07:55:09 A
2 25JUN2022:08:26:44 B
2 03OCT2022:09:54:03 A
2 05DEC2022:01:51:06 A
2 12JUL2022:10:14:44 B
2 20SEP2022:16:39:51 A
2 01JAN2023:01:18:57 A
2 28MAR2023:12:46:34 B
2 05JUN2023:07:32:10 A
3 28FEB2022:23:08:58 A
3 02APR2022:05:22:17 B
3 21JUN2022:22:01:43 B
3 10AUG2022:18:36:23 A
3 13NOV2022:20:45:19 A
3 24DEC2022:17:37:57 B
3 18MAR2023:19:41:35 A
3 06MAY2023:15:22:17 A
3 09JUL2023:02:14:23 B
3 21OCT2023:14:08:56 B
;
run;

预期输出数据集(want)

data want;
  input id datetime :datetime. event $ RuleHit;
  format datetime datetime.;
  datalines;
1 01JAN2022:00:00:00 A 0
1 15APR2022:11:46:34 B 0
1 23JUN2022:01:02:10 A 0
1 13NOV2022:08:08:56 B 1
1 22JAN2023:14:32:58 A 0
1 28JAN2023:21:41:35 A 0
1 09APR2023:11:22:17 A 0
1 16MAY2023:22:14:23 B 1
1 08JUN2023:16:10:32 B 0
1 11JUL2023:20:39:51 A 0
2 06FEB2022:09:23:43 B 0
2 12MAY2022:07:55:09 A 0
2 25JUN2022:08:26:44 B 1
2 12JUL2022:10:14:44 B 0
2 20SEP2022:16:39:51 A 0
2 03OCT2022:09:54:03 A 1
2 05DEC2022:01:51:06 A 0
2 01JAN2023:01:18:57 A 0
2 28MAR2023:12:46:34 B 0
2 05JUN2023:07:32:10 A 0
3 28FEB2022:23:08:58 A 0
3 02APR2022:05:22:17 B 0
3 21JUN2022:22:01:43 B 1
3 10AUG2022:18:36:23 A 1
3 13NOV2022:20:45:19 A 1
3 24DEC2022:17:37:57 B 1
3 18MAR2023:19:41:35 A 0
3 06MAY2023:15:22:17 A 0
3 09JUL2023:02:14:23 B 1
3 21OCT2023:14:08:56 B 1
;
run;

解决方案

方法一:DATA步滑动窗口(高效适合大数据集)

此方法通过排序后维护临时数组队列,动态管理滑动窗口内的B计数,效率较高,适合大规模数据集:

/* 1. 先按ID和datetime排序,确保时间序列有序 */
data have_sorted;
    set have;
    by id datetime;
run;

/* 2. 计算移动窗口内的滞后B数量,生成RuleHit */
data want;
    set have_sorted;
    by id;
    /* 计算窗口起始时间:当前时间往前推8个月,'s'参数表示起始点为月初 */
    window_start = intnx('month', datetime, -8, 's');
    /* 用临时数组存储观测时间和B标记,数组大小可按需调整 */
    array dt[1000] _temporary_;
    array b_flag[1000] _temporary_;
    retain dt b_flag cnt_b ptr;
    
    /* 每个ID分组初始化 */
    if first.id then do;
        call missing(of dt[*], of b_flag[*]);
        cnt_b = 0;
        ptr = 0;
    end;
    
    /* 将当前观测加入队列 */
    ptr + 1;
    dt[ptr] = datetime;
    b_flag[ptr] = (event = 'B');
    if b_flag[ptr] then cnt_b + 1;
    
    /* 移除窗口外的旧观测,更新B计数 */
    do while(dt[1] < window_start);
        if b_flag[1] then cnt_b - 1;
        /* 队列元素左移 */
        do i = 1 to ptr - 1;
            dt[i] = dt[i+1];
            b_flag[i] = b_flag[i+1];
        end;
        ptr - 1;
        if ptr = 0 then cnt_b = 0;
    end;
    
    /* 排除当前观测,判断是否满足条件 */
    RuleHit = (cnt_b - b_flag[ptr] >= 2);
    
    /* 删除临时变量 */
    drop window_start ptr i cnt_b dt: b_flag:;
run;

方法二:PROC SQL自连接(简洁适合小数据集)

此方法通过自连接匹配窗口内的滞后观测,统计B的数量,代码简洁直观,适合小规模数据集:

proc sql;
    create table want as
    select 
        a.id,
        a.datetime,
        a.event,
        /* 统计窗口内滞后观测中B的数量,判断是否≥2 */
        case when sum(case when b.event = 'B' then 1 else 0 end) >= 2 then 1 else 0 end as RuleHit
    from have as a
    left join have as b
        on a.id = b.id
        /* 匹配当前观测往前8个月到当前观测之前的记录 */
        and b.datetime >= intnx('month', a.datetime, -8, 's')
        and b.datetime < a.datetime
    group by a.id, a.datetime, a.event
    /* 按ID和时间排序,与预期输出一致 */
    order by a.id, a.datetime;
quit;

关键说明

  • 必须先对数据集按ID和datetime排序,确保时间窗口的计算基于有序的时间序列。
  • 两种方法均严格排除当前观测,只统计滞后观测中的B数量,符合需求定义。

内容的提问来源于stack exchange,提问作者hmhensen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:24:54