создать переменную для уникальных сессий

У меня есть некоторые данные о том, когда, как долго и по какому каналу люди слушают радио. Мне нужно создать переменную с именем sessions, которая группирует все записи, происходящие при включенном радио. Поскольку данные могут содержать некоторые ошибки, я хотел бы сказать, что если от конца одного периода канала до следующего проходит менее пяти минут, то это все еще тот же сеанс. Надеюсь, краткий пример прояснит ситуацию.

  obs  Entry_date   Entry_time  duration(in secs) channel
   1    01/01/12      23:25:21    6000               2
   2    01/03/12      01:05:64     300               5
   3    01/05/12      12:12:35     456               5
   4    01/05/12      16:45:21     657               8

Я хочу создать переменные сеансы, чтобы

obs  Entry_date   Entry_time  duration(in secs) channel   session
   1    01/01/12      23:25:21    6000               2    1
   2    01/03/12      01:05:64     300               5    1
   3    01/05/12      12:12:35     456               5    2
   4    01/05/12      16:45:21     657               8    3

для определения 1 сеанса мне нужно использовать entry_timedate, если он идет с 23:00 до следующего утра), чтобы, если entry_time+duration + (5minutes) < entry_time(next channel), сеанс изменился. Это убивает меня, и простые массивы не помогут, или моя попытка использовать массивы не сработала. заранее спасибо


person user2448666    schedule 10.09.2013    source источник
comment
Я не понимаю, почему сеанс остается неизменным для первых двух строк, когда дата входа изменяется с 01/01 на 03/01?   -  person Longfish    schedule 11.09.2013
comment
Также только что заметил, что время входа для строки 2 составляет 01:05:64, что это должно быть? (Я предполагаю, что 64 секунды неверны....)   -  person Longfish    schedule 11.09.2013
comment
это опечатка в примере   -  person user2448666    schedule 13.09.2013


Ответы (2)


Помимо комментариев, которые я сделал в OP, вот как бы я это сделал, используя шаг данных SAS. Я изменил значения даты и времени для строки 2 на то, что, как я подозреваю, они должны быть (чтобы получить тот же результат, что и в OP). Это позволяет избежать необходимости выполнять самосоединение, которое, вероятно, приведет к увеличению производительности при работе с большим набором данных.
Я использовал функции DIF и LAG, поэтому следует соблюдать осторожность, если вы добавляете дополнительный код (особенно операторы ЕСЛИ).

data have;
input entry_date :mmddyy10. entry_time :time. duration channel;
format entry_date date9. entry_time time.;
datalines;
01/01/2012 23:25:21 6000 2
01/02/2012 01:05:54 300 5
01/05/2012 12:12:35 456 5
01/05/2012 16:45:21 657 8
;
run;

data want;
set have;
by entry_date entry_time; /* put in to check data is sorted correctly */
retain session 1; /* initialise session with value 1 */
session+(dif(dhms(entry_date,0,0,entry_time))-lag(duration)>300); /* increment session by 1 if time difference > 5 minutes */
run;
person Longfish    schedule 11.09.2013
comment
В данных есть некоторые несоответствия, поэтому я хочу дать им пятиминутное окно. Я не упоминал об этом ранее, потому что я думал, что это будет простой оператор by, но я хочу, чтобы это было сделано для каждого уникального идентификатора, и поскольку сеансы никогда не перезапускаются с 1 для каждого идентификатора. Должен ли я редактировать и делать репосты - person user2448666; 13.09.2013

Надеюсь, я правильно понял ваши требования! Поскольку вам нужно основывать результат на соседних строках, необходимо соединить таблицу с самой собой. Номера сессий не являются последовательными, но вы должны уловить суть.

 create table #temp
 (obs int not null,
entry_date datetime not null,
duration int not null,
channel int not null)


--obs  Entry_date   Entry_time  duration(in secs) channel
insert #temp
select   1, '01/01/12 23:25:21', 6000, 2
 union all select 2, '01/03/12 01:05:54', 300, 5
 union all select 3, '01/05/12 12:12:35', 456, 5
 union all select 4, '01/05/12 16:45:21', 657, 8

select a.obs,
       a.entry_date,
       a.duration,
endSession = dateadd(mi,5,dateadd(mi,a.duration,a.entry_date)),
a.channel,
b.entry_date,
minOverlapping = datediff(mi,b.entry_date,
                          dateadd(mi,5,dateadd(mi,a.duration,a.entry_date))),
anotherSession = case 
          when dateadd(mi,5,dateadd(mi,a.duration,a.entry_date))<b.entry_date
    then b.obs
    else a.obs end
from #temp a
  left join #temp b on a.obs = b.obs - 1

Надеюсь это немного поможет

person user2065377    schedule 10.09.2013
comment
это должно быть выполнено для массивного набора данных, 1 миллион + строки, поэтому первый оператор выбора подразумевает, что мне нужно будет ввести всю информацию там - person user2448666; 10.09.2013
comment
нет. Я создал временную таблицу и вставил образцы данных только для проверки запроса. Замените #temp любым именем таблицы, которое вы имеете в виду. Мельница или около того строк не должны быть большой проблемой, если предположить, что применяется правильное индексирование. просто проверьте план выполнения для этого. - person user2065377; 10.09.2013