Новичок в использовании массивов SAS и не может заставить элементы массива заполняться значениями на основе инструкции IF-THEN-ELSE

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

START_BLOCK (возможные целые значения от 0 до 47) END_BLOCK (возможные целочисленные значения от 0 до 47)

Я пытаюсь создать массив, который добавляет поля от TIME_BLOCK_0 до TIME_BLOCK_47 и вставляет 1 или 0 в зависимости от того, попадает ли этот временной блок [i] между (включительно) START_BLOCK и END_BLOCK.

Например, запись с START_BLOCK = 29 и END_BLOCK = 31 будет иметь значение 0 в каждом столбце, кроме столбцов TIME_BLOCK_29, TIME_BLOCK_30 и TIME_BLOCK_31, которые будут заполнены значением 1.

Я впервые прошу здесь помощи, поэтому прошу прощения, если мой вопрос не ясен.

Код, который я пробовал (который создавал поля TIME_BLOCK_[i], но не заполнял их):

data WANT (drop = i);
set HAVE;
array time_blocks[48] time_block_0 - time_block_47;
do i = 0 to 47;

* midnight = time block 0;

* First, account for cases that end on a different day than they start (where the end_block is < the start_block)- not common;
if end_block < start_block then do;
    if end_block >= i or start_block <= i then time_block_i = 1; else time_block_i = 0;
    end;
* then, for cases where start_block < end_block (most cases that start and end on the same day) - most common;
else if start_block <= [i] and end_block >= [i] then time_block_i = 1; else time_block_i = 0;

end;

run;

Покажите значения START_BLOCK и END_BLOCK, которые вы использовали.

Tom 17.07.2024 06:23
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Массив на основе переменных SAS позволяет указать, к каким переменным следует обращаться с помощью синтаксиса массива. Указание имен переменных после имени массива приведет к созданию новых переменных, если они еще не существуют.

Не забывайте, что переменные сбрасываются до отсутствующих в верхней части неявного цикла DATA Step. Если вы пытаетесь «заполнить» элементы массива по группе, то переменные массива также необходимо будет сохранить и сбросить в начале группы по. Если переменные массива являются частью набора данных, считываемого SET, вам может понадобиться «смежный» массив, в котором определенные элементы не будут перезаписывать значение.

Пример:

Поскольку вам нужно 0/1 в каждом слоте, вам нужно будет пройти по всему массиву и установить для элемента результат логической оценки (0-ложь, 1-истина).

Показанное здесь логическое выражение a <= b <= c характерно для SAS и означает a <= b and b <= c

data want ;
  set have ;
  array slot time_block_0-time_block_47 ;  * 48 variables ;
  do index = 1 to dim(slot) ;
    slot[index] = start_block <= index <= end_block ;
  end ;
run ;
Ответ принят как подходящий

Будет меньше путаницы, если вы скажете SAS использовать индексы от 0 до 47 вместо обычных от 1 до 48.

Давайте сначала создадим несколько примеров данных, чтобы у нас было что протестировать.

data have;
  input start_block end_block;
cards;
0 47
2 4
-1 56
56 -1
;

Поскольку SAS оценивает логические выражения как 0 (FALSE) или 1 (TRUE), вы можете пропустить логику IF/THEN и просто использовать оператор присваивания. (Также не беспокойтесь об использовании параметров набора данных для DROP переменной. Все, что вам нужно, — это простой оператор DROP. Оставьте усложнение параметров набора данных на случай, если вам придется их использовать.)

data WANT ;
  set HAVE;
  array time_blocks[0:47] time_block_0 - time_block_47;
  do index = 0 to 47;
    time_blocks[index] = start_block <= index <= end_block;
  end;
  drop index;
run;

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

Инициализируйте массив нулями, затем выполните цикл между началом и концом с шагом в полчаса, а затем увеличьте соответствующую переменную.

data have;
  input start :datetime. end :datetime.;
  format start end datetime19.;
cards;
01JAN2024:00:15 01JAN2024:04:35 
01JAN2024:22:15 02JAN2024:03:00 
;

data WANT ;
  set HAVE;
  array time_blocks[0:47] time_block_0 - time_block_47;
  do index = 0 to 47; time_blocks[index] = 0; end;
  do datetime=start to end by '00:30:00't ;
    time_blocks[int(timepart(datetime)/'00:30:00't)]+1;
  end;
  drop index datetime;
run;

Если у вас есть только время суток, но нет фактических значений даты и времени, просто преобразуйте их. Поэтому используйте DAY=0 при преобразовании START_TIME в значение даты и времени, а когда END_TIME меньше START_TIME, используйте DAY=1 при преобразовании его в значение даты и времени. Пример:

start = dhms(0,0,0,start_time);
end = dhms(end_time<start_time,0,0,end_time);
format start_time end_time tod5. start end datetime19.;

Спасибо, Том, это близко к тому, что мне нужно! Единственное, что он не учитывает, — это случай, когда START_BLOCK < END_BLOCK. Например, если у меня есть запись с START_BLOCK = 47 и END_BLOCK = 4, то я хочу, чтобы следующие поля были заполнены значением 1: TIME_BLOCK_1 - TIME_BLOCK_4 и TIME_BLOCK_47. Для контекста эти начальные и конечные блоки представляют собой время хирургического случая на полчаса. приращения времени в течение 24-часового периода, где TIME_BLOCK_0 = полночь и TIME_BLOCK_47 = 23:30. Таким образом, запись, где START_BLOCK < END_BLOCK, означает, что операция началась в один день и закончилась на следующий день.

Keith Landgrebe 17.07.2024 15:51

Сначала вам нужно преобразовать значения TIME в значения DATETIME. Тогда START будет меньше, чем END, поскольку это будет другой день. Что вы хотите ДЕЛАТЬ, если операция началась в другой день? Какие единицы измерения обозначают цифры от 0 до 47? Получасовые интервалы в день? Вы пытаетесь определить, какие временные блоки используются чаще всего? Я бы установил весь массив в нули, а затем запустил цикл от начала даты и времени до конца даты и времени на полчаса и просто обновил соответствующую переменную. Если операция длилась более 24 часов, некоторые значения блока будут больше 1.

Tom 17.07.2024 16:13

Да, каждый из них представляет собой получасовой интервал в течение дня. 0 = 12:00–12:29, 1 = 12:30–12:59, ... 47 = 23:30–23:59. Для каждой записи (представляющей операцию) мне просто нужно отметить, в каких временных интервалах произошел этот случай. start_block (0-47) представляет, какой time_block (0-47) начался кейс, а end_block (0-47) представляет, какой time_block (0-47) закончился кейс. Именно эти ночные случаи, которые начинаются позже ночью (например, time_block_47) и заканчиваются рано на следующий день (например, time_block_4), не работают с вашим исходным решением (что в остальном здорово!)

Keith Landgrebe 17.07.2024 16:34

Я заставил его работать! Ваши предложения были чрезвычайно полезны, мне просто нужно было сделать одну небольшую настройку, чтобы округлить время начала и окончания до ближайших получаса (в противном случае я иногда пропускал 1 в последнем столбце): data WANT; установить ЕСТЬ; массив time_blocks[0:47] time_block_0 - time_block_47; индекс действия = от 0 до 47; time_blocks[индекс] = 0; конец; do datetime=intnx('MINUT30',start,0,'b') to intnx('MINUT30',END,0,'B') к '00:30:00't ; time_blocks[int(timepart(datetime)/'00:30:00't)]+1; конец; удалить индекс datetime; бегать; Большое вам спасибо за вашу помощь в этом!

Keith Landgrebe 17.07.2024 18:29

Другие вопросы по теме