Converting Data
Представим, что вам нужно решить следующую задачу. У вас имеется следующий dataset

Ваша задача создать переменную, которая будет принимать значение SUCCESS 1 в случае, если разница scores между визитами Visit 1 Day 1 Baseline и Visit 4 Day 84 +/-4 OR Early Discontinuation >=2 и 0, если это не так. Иными словами, если симптомы улучшились на 2 scores (например, с Grade 3 до Grade 1) то мы считаем это успехом, если ухудшились, не изменились или улучшились на 1 score, то мы не считаем это успехом. Интуитивно понятно, что для сравнения результатов Erythema Score было бы удобно их перевести в numeric, где Grade 3 будет соответствовать numeric значению 3, Grade 2 – 2 и т.д.

Это – все возможные значение для переменной ERTSCORE (Erythema Score) согласно CRF.
Воспользовавшись некоторыми функциями для работы с char (например scan, substr, strip и др.), мы можем получить значения ‘3’, ‘2’ (запишем их в переменную mod_score), однако они по-прежнему будут char значениями, т.е. мы не можем воспользоваться функциями для numeric переменных (воспользовавшись lag4, посчитать разницу). lag4 мы применить, конечно, можем, однако разницу мы по-прежнему не можем вычислить, т.к. для SAS эти значения все еще char.
Рассмотрим следующий код
data test; set test; scoren=input(mod_score,1.); run;
Наверное, вы уже догадались, что мы должны получить.

Мы получили переменную scoren, которая уже numeric. Что ж, давайте теперь поговорим о том, что мы сделали и как.
Очень часто вы будете сталкиваться с тем, что numeric переменные вам нужно будет конвертировать в char и наоборот. Для этого используют функции put и input.
Func | Code | Converting |
---|---|---|
PUT | ||
put_n_to_c=put(scoren,5.); | num->char (A) | |
put_c_to_c=put(mod_score,$5.); | char->char (B) | |
put_c_to_c_ud=put(mod_score,$gradename.); | char->char (C)
|
|
INPUT | ||
input_c_to_n=input(put_n_to_c,5.); | char->num (D) | |
input_c_to_c=input(put_c_to_c,$5.); | char->char (E) | |
input_c_to_n_ud=input(put_c_to_c_ud,gradescore.); | char->num (F)
|

Немного пояснений к написанному выше:
- Для того, чтобы SAS распознал написанное как формат, всегда в конце названия формата ставится точка.
-
Почему в форматах мы использовали 5?
В случаях A, B, E, когда мы создали новую char переменную, 5 – это ее длина (т.е. мы точно знаем, что значения будут длины 5 или короче) В случае D, когда мы создали numeric переменную из char, мы говорим, что значения в новой numeric переменной будут иметь не больше 5 символов.
В этих конкретных примерах мы могли бы использовать и длину 1 – ее бы хватило.
Обратите внимание, что в примере А, значения не прижаты влево. Перед значением стоит еще 4 пробела, т.е. по умолчанию значения будут прижиматься к правому краю «указанной длины».
На самом деле, если вам не важна длина новой переменной и вам не нужно ее специально куда-то прижимать (к правому краю или левому), мы можем воспользоваться следующим приемом:
put_n_to_c=put(scoren,best.-l);
где,
- best. – формат, который SAS использует по умолчанию для numeric переменных (по умолчанию с длиной 12, т.е. best12.)
- –l – говорим SAS прижать значение влево (аналогично можем использовать -r -c ).
-
user-defined format
Как видно в примерах C и F, мы использовали специальный формат для того, чтобы видеть результат в таком виде как нам хотелось бы. О том, как нам это получилось сделать, мы поговорим немногим ниже в разделе Proc format.
Теперь давайте рассмотрим пример, когда в качестве исходных данных у нас не целые значения, например, температура (temp)

где SubjectID и Temperature – исходные raw данные, а остальные получены следующим образом:
temp_best=put(temp,best.); temp_bestL=put(temp,best.-l); temp_41=put(temp,4.1); temp_51=put(temp,5.1); temp_52=put(temp,5.2);
Первые две переменные – еще одна демонстрация формата best.
Остальные – пример того, как работать с float значениями. В этих трех примерах, как мы видим, создаются char переменные temp_41, temp_51 и temp_52, где указывая формат с точкой мы говорим SAS сколько будет всего символов (в формате – это цифра до точки) и сколько из них будет после точки (как разделитель целой части от десятичной).
NOTE:
- число, задающее общее количество символов, должно включать в себя и разделитель (в нашем случае точку).
- если нет десятых, сотых и т.д., такие форматы заполнят их нулями.
Отдельно нужно поговорить о датах и о date formats. Как мы уже с вами знаем, даты хранятся в SAS как numeric значения. Давайте посмотрим на переменную LIADT (Local Irritation Assessment Date) из первого примера.

Как мы видим, переменная – numeric, однако на нее наложен формат mmddyy10., из-за чего мы видим ее такой, как в первом примере. Если в ячейке Format поменять наложенный формат, или в data step наложить на эту переменную другой формат, то значение ее останется прежней, но отображаться она будет иначе (в зависимости от того, какой формат мы наложим). Однако сейчас нам интересно не просто наложить на нее какой-то формат, а на основе этой переменной создать новую char переменную, чем мы сейчас и займемся.
Рассмотрим такой код, где во входном dataset test0 имеем переменные SubjectId, Visit, LIADT:
data test_dates; set test0; format liadt; /*"снимаем" наложенный формат*/ date_iso=put(liadt,is8601da.); date_9=put(liadt,date9.); date_11=put(liadt,date11.); run;
и посмотрим на dataset test_dates

Как видно, теперь мы видим настоящее значение в переменной liadt. Давайте теперь посмотрим на атрибуты переменной date_iso

Как видно, переменная char и никаких специальных форматов на нее не наложено (только тот, что по умолчанию накладывается SAS). На самом деле, для SAS это теперь не дата, это просто char переменная с какими-то символами. И если вы попробуете воспользоваться для переменной date_iso какой-либо функцией для работы с датой, например month, то увидите только ругательства в Log. Если у вас имеется char переменная, в которой, как вы видите, хранится дата, вы всегда можете сделать ее такой и для SAS, воспользовавшись input и соответствующим форматом.
Proc format
Ну вот, наконец-то, мы добрались до того, как же можно самим создавать formats и informats. SAS предоставляет немало встроенных форматов, однако под каждый проект, под каждого заказчика вам нужно будет создавать user-defined formats. Для того, чтобы создать свой формат, необходимо воспользоваться процедурой proc format. Мы уже дважды воспользовались user-defined форматами, теперь давайте разберемся как именно они были созданы.
proc format library=work; value $gradename "0"="None" "1"="Very Mild" "2"="Mild" "3"="Moderate" "4"="Severe"; invalue gradescore "None"=0 "Very Mild"=1 "Mild"=2 "Moderate"=3 "Severe"=4; value gradescore /*new*/ 0="None" 1="Very Mild" 2="Mild" 3="Moderate" 4="Severe"; run;
- proc format – сама процедура.
- library – библиотека для сохранения форматов (по умолчанию work).
- value – ключевое слово, обозначающее, что вы создаете именно format (т.е. результат будет char). При этом если исходные данные тоже char в названии формата необходимо добавить $.
- invalue – ключевое слово, обозначающее что вы создаете именно informat (т.е. результат будет numeric).
Рассмотрим еще несколько интересных примеров использования proc format:
proc format; value $gender "M" = "Male" "F" = "Female" " " = "Not entered" /*форматирование пустых значений*/ other = "Miscoded"; /*форматирование значений, отличных от перечисленных*/ value age low-29 = "Less than 30" /*форматирование диапазонов значений*/ 30-50 = "30 to 50" 51-high = "51+"; value $three "1","2" = "Disagreement" /*форматирование группы значений*/ "3" = "No opinion" "4","5" = "Agreement"; value $gradefmt "A" – "C" = "Passing" /*форматирование строчного диапазона значений*/ "D" = "Borderline" "F" = "Failing" "I","W" = "Incomplete or withdrew" " " = "Not recorded" other = "Miscoded"; run;
Кроме этого SAS еще умеет создавать форматы из datasets и наоборот. Бывают случаи, когда эти возможности SAS становятся для вас просто палочкой-выручалочкой.
proc format cntlin=fmtdataset;
run;
- cntlin – опция, где указываем dataset, из которого создаем формат или несколько форматов.
Однако dataset fmtdataset должен иметь особую структуру. Как минимум он должен иметь три необходимых
Переменная | Для чего используется |
---|---|
fmtname | Название формата |
start | Исходное значение |
label | Форматированное значение |
Иными словами, эти переменные можно себе представить следующим образом:
proc format; value $fmtname "start"="label" ...; run;
В обратную сторону (создать dataset из формата), пользуемся следующим кодом:
proc format cntlout=df_gradefmt; select $gradefmt; run;
Как вы уже, наверное, догадались, в dataset df_gradefmt мы увидим представление формата $gradefmt.
Дополнительные материалы: