部分保留价值并有条件地替换观察值

Partially retaining value and conditionally replacing observation's value

数据集如下所示:

Server  IP          Indicator Session_ID   Time
2      1.20.54.221              A           00:00:01
2      1.20.54.221              A           00:01:00
1      1.20.54.221  Site        A           00:02:00
1      1.20.54.221              B           00:05:00
2      1.20.54.221  Site        B           00:08:00
2      1.20.54.221              C           00:10:00
2      1.20.54.221              C           00:15:00
1      1.20.54.221              F           01:00:00
1      1.20.54.221              F           01:05:00
2      1.20.54.221  Site        F           01:08:00

以上数据集是从日志文件中读取的。 Session_id 将在服务器更改时更改(即 1 -> 22 -> 1 )。在某些情况下,服务器会在更改发生后立即更改(即 1---->2----->1)。每当更改服务器时,服务器将在第二次浏览同一服务器时记录最后的 Session_id 和 return 一个新的 Session_id。 (例如第 3 次观察:Session_id 仍然是 A,第 4 次观察改为 B)。如果服务器改变了方式(即1---->2----->1---->1),它将return A-----> A----->B---> C,其中生成了B由服务器 2C 由第二个 1

生成

我的objective是判断记录中是否有子组。规则是:

Given the same IP, If the time difference between the current record and last record does not exceed 30 minutes, then the record belongs to the same user.

我有一个指标变量site来判断网站是否发生了变化。以是否发生服务器变更且时差小于30分钟为准。

想要的数据集:

Server  IP          Indicator Session_ID   Time           Difference  Last_site 
2      1.20.54.221              A           00:00:01       .            .
2      1.20.54.221              A           00:01:00       59s          .
1      1.20.54.221  Site        A           00:02:00       1 Min        .
1      1.20.54.221              A           00:05:00       3 Min        Site
2      1.20.54.221  Site        A           00:08:00       3 Min        Site
2      1.20.54.221              A           00:10:00       2 Min        Site
2      1.20.54.221              A           00:15:00       5 Min        Site
1      1.20.54.221              F           01:00:00       45min         . 
1      1.20.54.221              F           01:05:00       5 Min         .
2      1.20.54.221  Site        F           01:08:00       3 Min         .

我的实现:

data log_file;
set log;
retain _Session_id Last_site;,

* Assign value to retain ; 
if indicator = "Site" then _Session_id = Session_id;

* if last_site = Site, its value has to be changed;
last_site=lag(site); 

* Record that should be in another group ;
if difference >30 then Last_Site = "";  

* Replace;
if last_site  not eq "" then session_id = _session_id 

run;

问题是,retained variable 会在第五次观察时从 A 变为 B,而我想让它保持值 A 直到找到时差大于30分钟的记录。 (该过程会循环数十万个IP,因此效率也很重要。)

有没有办法优雅地处理这个问题? 先感谢您。

[22/6 编辑]

我正在考虑使用哈希对象来完成这项工作的可能性。我写了一些代码(显然它们不起作用并且可能会导致语法错误)。

data test11a;
length mark $ 12 ip $ 32 Session_id $ 200 agent last_agent $ 200; <== the system said there is error with the type of variable and therefore I add this
Declare hash hid;   
hid = _new_ hash( ordered : ' ascending');
hid.definekey('ip');
hid.definedata('Session_id');
hid.definedone();
call missing ( ip, Session_id);
   do while ( not done);
    set test11 end=done; <==== I have the original data-set called test11
    by ip notsorted ; <==== hash object by group;
    if not first.ip or not last.ip then do;
       if mark = "Site" then rc=  hid.add();
      *if mark = "Next_Group" then hid.remove(key : ip); <=== Error
    end;
    if mark not eq "Site" or "Next_Group" then do;
      rc=hid.find();  <==== Find matching iP and if matching ( rc=0)
      * use variable _ session_id to test;
      if rc = 0 then _session_id = Session_id;
    end;
  end;
run;

并且输出数据集只有两个观测值。谁能帮忙解释一下?

这是一个部分答案,因为我无法弄清楚您是如何构建 'Last_site'。在我看来你想要的是检查差异是否超过 30 mins/1800 秒,如果 'no',session_id 保持不变,如果 'yes',它采用新的session_id。我可能把你的问题简单化了,但结果似乎很接近:

data have;
    input (Server  IP          Indicator Session_ID) (:.)   Time :time8.;
    format time time8.;
    cards;
2      1.20.54.221  .            A           00:00:01
2      1.20.54.221   .           A           00:01:00
1      1.20.54.221  Site        A           00:02:00
1      1.20.54.221    .          B           00:05:00
2      1.20.54.221  Site        B           00:08:00
2      1.20.54.221     .         C           00:10:00
2      1.20.54.221      .        C           00:15:00
1      1.20.54.221       .       F           01:00:00
1      1.20.54.221        .      F           01:05:00
2      1.20.54.221  Site        F           01:08:00
;
run;

data want;
    set have;
    by ip notsorted;
    retain _session ' ';

    if first.ip then
        _session=session_id;
    difference=dif(time);

    if  difference > 1800 then
        _session=session_id;
    drop session_id;
    rename _session=session_id;
run;