2015-03-20 1 views
0

У меня есть вопрос относительно SAS и анализ продолжительности определенного состояния переменной. Я хочу найти, как долго каждый человек в моем наборе данных постоянно находится в состоянии, пока не наступит состояние b. Если состояние c происходит после состояния a, продолжительность должна быть установлена ​​равной нулю. Обратите внимание, что я также установил бы длительность в ноль, если pre_period находится в состоянии a, но если я получу другое состояние, то впоследствии это должно быть подсчитано.Продолжительность состояния в SAS

Данные выглядит kindof так:

pre_period week1 week2 week3 week4 week5 week6 week7 ... 
id1 b    b  a  a  a  b  c  c  ... 
id2 a    a  a  a  b  a  b  b  ... 
id3 b    b  a  a  b  a  a  b  ... 
id4 c    c  c  a  a  a  a  a  ... 
id5 a    b  a  b  b  a  a  b  ... 
id6 b    a  a  a  a  a  a  a  ... 

Набор образцов в с.а.с код:

data work.sample_data; 
input id $ pre_period $ (week1-week7) ($); 
datalines; 
id1 b b a a a b c c 
id2 a a a a b a b b 
id3 b b a a b a a b 
id4 c c c a a a a a 
id5 a b a b b a a b 
id6 b a a a a a a a 
; 

Так что для id1, который должен дать мне продолжительность 3, для id2 1, для id3 3 и 1, для ID4 5 для ID5 1 и 2 и ID6 7.

Так что результат должен выглядеть примерно так:

dur1 dur2 dur3 dur4 ... 
id1 3 . . . ... 
id2 1 . . . ... 
id3 3 1 . . ... 
id4 5 . . . ... 
id5 1 2 . . ... 
id6 7 . . . ... 

Я новичок в SAS и не нашел способ решить эту проблему. Обратите внимание, что набор данных содержит несколько тысяч строк и примерно тысячу столбцов, так что для одного человека у меня может быть несколько интервалов состояния, которые я все хочу захватить (поэтому несколько переменных продолжительности на выходе).

Я благодарен за любые советы. Благодаря!

+0

Ваши желаемые результаты кажутся несовместимыми с вашими требованиями. Состояние c встречается для id 1 на неделе 6 - не должно ли это означать, что id 1 имеет продолжительность 0? А для id 2 pre_period имеет состояние a, поэтому не должно быть id id 2 длительностью 0? – user667489

+0

Может быть, я был немного неясен: если pre_period - это то, то следует не учитывать следующее a, но если индивид покидает состояние, он должен обрабатываться, как и любой другой человек. Случай с с должен быть уместным, если c следует после a. Спасибо за намек на мое описание! – banan

+0

Неясно, какой тип вывода вы хотите в тех случаях, когда есть несколько пробегов состояния, разделенных состояниями b или c. Вы хотите, чтобы 1 строка на один идентификатор с несколькими столбцами удерживала длину каждого прогона или несколько строк? Попробуйте ввести то, что вы хотите, чтобы выходной набор данных выглядел в том же виде, что и входной набор данных. – user667489

ответ

0

В этих случаях это может быть разумным и думать в терминах конечного автомата. Таким образом, довольно легко продлить конечный автомат позже, если ваши требования изменятся.

Продолжительность действует в трех случаях (в том числе inplicit одного данного из результирующего набора):

  • непрерывная продолжительность состояния a следует учитывать, если
    • это заканчивается состояние b,
    • все еще находится в состоянии a, когда набор данных заканчивается,
    • и до тех пор, пока он не стартует в первую неделю, когда состояние предварительного периода a.

Прежде всего, мы должны позаботиться о предварительной требования периода, мы можем назвать это состояние для pre_period_locked_state:

do week = 1 to last_week; 
     if current_state = pre_period_locked_state then do; 
      if 'a' not = pre_period or 'a' not = week_state then do; 
      current_state = duration_state; 
     end; 

Следующая вещь disect это когда государство не a , здесь называется no_duration_state:

 if current_state = no_duration_state then do; 
      if 'a' = week_state then do; 
       current_state = duration_state; 
      end; 
     end; 

Это наше неактивное состояние и будет меняться только тогда, когда начинается новый срок. Это следующее состояние называется duration_state и определяется как:

 if current_state = duration_state then do; 
      if 'a' = week_state then do; 
       duration_count = duration_count + 1; 
      end; 
      if ('a' not = week_state or week = last_week) and 0 < duration_count then do; 
       current_state = dispatch_state; 
      end; 
     end; 

Первая часть, вероятно, довольно сам объявляющий, длительность счетчика. Вторая часть позаботится о завершении продолжительности.

Сейчас на к dispatch_state:

 if current_state = dispatch_state then do; 
      if 'b' = week_state or 'a' = week_state and week = last_week then do; 
       duration{duration_index} = duration_count; 
       duration_index = duration_index + 1; 
      end; 
      duration_count = 0; 
      current_state = no_duration_state; 
     end; 

Это заботится о индексации выходной таблицы и также убедитесь, что хранить только действительные длительности.

Я добавил id7 ниже, поскольку данные образца не имели длительности, которая заканчивалась статусом, отличным от b.

data work.sample_data; 
input id $ pre_period $ (week1-week7) ($); 
datalines; 
id1 b b a a a b c c 
id2 a a a a b a b b 
id3 b b a a b a a b 
id4 c c c a a a a a 
id5 a b a b b a a b 
id6 b a a a a a a a 
id7 b a a c a a a a 
; 

Полный код SAS состояние машины:

data work.duration_fsm; 
    set work.sample_data; 
    array weeks{*} week1-week7; 
    array duration{*} dur1-dur7; 

    *states; 
    initial_reset_state = 'initial_reset_state'; 
    pre_period_locked_state = 'pre_period_locked_state'; 
    duration_state = 'duration_state'; 
    no_duration_state = 'no_duration_state'; 
    dispatch_state = 'dispatch_state'; 
    length current_state $ 50; 

    *initial values; 
    current_state = initial_reset_state; 
    last_week = dim(weeks); 

    keep id dur1-dur7; 

    do week = 1 to last_week; 
     if current_state = initial_reset_state then do; 
      duration_count = 0; 
      duration_index = 1; 
     current_state = pre_period_locked_state; 
     end; 
     week_state = weeks{week}; 
     if current_state = pre_period_locked_state then do; 
      if 'a' not = pre_period and 'a' = week_state then do; 
        current_state = duration_state; 
       end; 
      else if 'a' = pre_period and 'a' not = week_state then do; 
       current_state = no_duration_state; 
      end; 
     end; 
     if current_state = no_duration_state then do; 
      if 'a' = week_state then do; 
       current_state = duration_state; 
      end; 
     end; 
     if current_state = duration_state then do; 
      if 'a' = week_state then do; 
       duration_count = duration_count + 1; 
      end; 
      if ('a' not = week_state or week = last_week) and 0 < duration_count then do; 
       current_state = dispatch_state; 
      end; 
     end; 
     if current_state = dispatch_state then do; 
      if 'b' = week_state or 'a' = week_state and week = last_week then do; 
       duration{duration_index} = duration_count; 
       duration_index = duration_index + 1; 
      end; 
      duration_count = 0; 
      current_state = no_duration_state; 
     end; 
    end; 
    run; 

Это выведет work.duration_fsm:

+-----+------+------+------+------+------+------+------+ 
| id | dur1 | dur2 | dur3 | dur4 | dur5 | dur6 | dur7 | 
+-----+------+------+------+------+------+------+------+ 
| id1 | 3 |  |  |  |  |  |  | 
| id2 | 1 |  |  |  |  |  |  | 
| id3 | 2 | 2 |  |  |  |  |  | 
| id4 | 5 |  |  |  |  |  |  | 
| id5 | 1 | 2 |  |  |  |  |  | 
| id6 | 7 |  |  |  |  |  |  | 
| id7 | 4 |  |  |  |  |  |  | 
+-----+------+------+------+------+------+------+------+