部分保留价值并有条件地取代观察价值

时间:2015-06-21 14:04:01

标签: hash sas retain

数据集如下所示:

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并在第二次浏览同一服务器时返回新的Session_id。 (例如第3次观察:Session_id仍为A,并在第4次观察时更改为B。如果服务器发生了变化(即1 ----> 2 -----> 1 ----> 1),它将返回A -----> A - - - - > B ---> C,其中B由服务器2生成,C由第二个1生成

我的目标是确定记录中是否有子组。规则是:

  

给定相同的IP,如果当前记录与最后一条记录之间的时差不超过30分钟,   然后该记录属于同一用户。

我有一个指标变量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]

我在考虑使用Hash Object来完成这项工作的可能性。我写了一些代码(显然它们不起作用,可能会导致语法错误)。

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;

输出数据集只有两个观察结果。有人可以帮忙解释一下吗?

1 个答案:

答案 0 :(得分:1)

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

data have;
    input (Server  IP          Indicator Session_ID) (:$20.)   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;