В этих случаях это может быть разумным и думать в терминах конечного автомата. Таким образом, довольно легко продлить конечный автомат позже, если ваши требования изменятся.
Продолжительность действует в трех случаях (в том числе 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 | | | | | | |
+-----+------+------+------+------+------+------+------+
Ваши желаемые результаты кажутся несовместимыми с вашими требованиями. Состояние c встречается для id 1 на неделе 6 - не должно ли это означать, что id 1 имеет продолжительность 0? А для id 2 pre_period имеет состояние a, поэтому не должно быть id id 2 длительностью 0? – user667489
Может быть, я был немного неясен: если pre_period - это то, то следует не учитывать следующее a, но если индивид покидает состояние, он должен обрабатываться, как и любой другой человек. Случай с с должен быть уместным, если c следует после a. Спасибо за намек на мое описание! – banan
Неясно, какой тип вывода вы хотите в тех случаях, когда есть несколько пробегов состояния, разделенных состояниями b или c. Вы хотите, чтобы 1 строка на один идентификатор с несколькими столбцами удерживала длину каждого прогона или несколько строк? Попробуйте ввести то, что вы хотите, чтобы выходной набор данных выглядел в том же виде, что и входной набор данных. – user667489