3.1 Converting Data, Proc format

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) (user-defined format)
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) (user-defined 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:

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;

Однако dataset fmtdataset должен иметь особую структуру. Как минимум он должен иметь три необходимых переменных – fmtname, start, label

Переменная Для чего используется
fmtname Название формата
start Исходное значение
label Форматированное значение

Иными словами, эти переменные можно себе представить следующим образом:

proc format;
    value $fmtname
        "start"="label"
        ...;
run;

В обратную сторону (создать dataset из формата), пользуемся следующим кодом:

proc format cntlout=df_gradefmt;
    select $gradefmt;
run;

Как вы уже, наверное, догадались, в dataset df_gradefmt мы увидим представление формата $gradefmt.

Дополнительные материалы: