Переименовать заявление с подстановочными знаками - PullRequest
0 голосов
/ 22 января 2020

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

NAME |Quantity Value at 31/12/2019|Value at 31/12/2019|Yield Exp 31/12/2019
FIDO |12                          |F                  |1
ALFA |20                          |2                  |4
BETA |3                           |5                  |2
ETA  |2                           |B65                |0
THETA|14                          |A40                |10

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

NAME |Quantity Value|Value|Yield Exp
FIDO |12            |F    |1
ALFA |20            |2    |4
BETA |3             |5    |2
ETA  |2             |B65  |0
THETA|14            |A40  |10

Я хотел бы использовать функцию переименования, но мне нужно использовать подстановочные знаки, потому что каждый раз, когда вводятся данные, метка времени отличается. Можно ли использовать функцию переименования с виджетами? Более того, некоторые переменные имеют пробелы и специальные символы, поэтому я должен использовать нотацию '' n при обращении к ним.

Я разработал код для получения набора данных со всеми именами переменных:

data base;
infile cards missover;
input 
NAME $ 'Quantity Value at 31/12/2019'n $ 'Value at 31/12/2019'n $ 'Yield Exp 31/12/2019'n $; datalines;
FIDO 12                          F                  1
ALFA 20                          2                  4
BETA 3                           5                  2
ETA  2                           B65                0
THETA 14                         A40                10
run;

proc sql ;
    create table BASE_COLUMN as
    select name 
    from sashelp.vcolumn
    where memname = "BASE"
  ;
quit ;

proc sql;
    update BASE_COLUMN
        set name = 
            case
                when name like "Quantity Value%" then "Quantity Value"
                when name like "Value at%" then "Value"
                when name like "Yield Exp%" then "Yield Exp"
            else name
end;
quit;

Но я все еще изо всех сил пытаюсь использовать набор данных BASE_COLUMN для переименования исходного набора данных BASE.

Какой лучший способ переименовать все имя столбца с использованием набора данных с правильными именами?

Ответы [ 3 ]

0 голосов
/ 22 января 2020

Благодаря Стю Штуковски у меня есть решение со следующим кодом:

data base;
infile cards missover;
input 
NAME $ 'Quantity Value at 31/12/2019'n $ 'Value at 31/12/2019'n $ 'Yield Exp 31/12/2019'n $; datalines;
FIDO 12                          F                  1
ALFA 20                          2                  4
BETA 3                           5                  2
ETA  2                           B65                0
THETA 14                         A40                10
run;

proc sql ;
    create table BASE_COLUMN as
    select name 
    from sashelp.vcolumn
    where memname = "BASE"
  ;
quit ;

proc sql;
    update BASE_COLUMN
        set name = 
            case
                when name like "Quantity Value%" then "Quantity Value"
                when name like "Value at%" then "Value"
                when name like "Yield Exp%" then "Yield Exp"
            else name
end;
quit;


proc sql noprint;
    select name
         , CASE
              when name like "Quantity Value%" then "Quantity Value"
              when name like "Value at%" then "Value"
              when name like "Yield Exp%" then "Yield Exp"
              else name
           END
           as new_name
    into :names separated by '|'
       , :new_names separated by '|'
    from dictionary.columns
    where     libname = 'WORK'
          AND memname = 'BASE'
          AND name NE calculated new_name
    ;
quit;

%macro rename;
    %do i = 1 %to %sysfunc(countw(&names, |));
        %let name     = %scan(&names, &i, |);
        %let new_name = %scan(&new_names, &i, |);

        rename "&name"n = "&new_name"n;
    %end;
%mend;

data BASE_CORRECT;
    set BASE;

    %rename;
run;

Еще раз спасибо!

0 голосов
/ 30 января 2020

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

Некоторые примеры переименования управляющих данных

Пример 1

Набор данных: Like_name_map

LIKE               NEW_NAME
---------------------------------
Quantity Value%    Quantity Value
Value at%          Value
Yield Exp%         Yield Exp

Пример 2 Набор данных: Regex_name_map

PATTERN                                NEW_NAME
-----------------------------------------------
^(.+)( at)? *\d{1,2}\/\d{1,2}\/\d{4}$     $1

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

Пример 1 - управляющими данными являются карты схожих шаблонов

data base1 base2;
infile cards missover;
input 
  NAME $ 
  'Quantity Value at 31/12/2019'n $ 
  'Value at 31/12/2019'n $ 
  'Yield Exp 31/12/2019'n $
  z
; datalines;
FIDO  12   F    1  3
ALFA  20   2    4  1
BETA   3   5    2  4
ETA    2  B65   0  1
THETA 14  A40  10  5
run;

data work.like_name_map; length like $32 new_name $32;input
LIKE&              NEW_NAME&; datalines;
Quantity Value%    Quantity Value
Value at%          Value
Yield Exp%         Yield Exp
;

%macro rename_by_like(data, control=work.like_name_map);
  %local lib mem index;

  %let syslast = &data;
  %let lib = %scan(&syslast,1);
  %let mem = %scan(&syslast,2);

  %if %sysfunc(exist(work.__contents)) %then %do;
    proc sql; drop table __contents;
  %end;

  proc contents noprint data=&data out=__contents(keep=name);

  /* utilize the control data for locating matches and applying naming map */
  proc sql;
    select quote(trim(__contents.name))||'n='||quote(trim(control.new_name))||'n' as rename
    into :__rename1-
    from __contents 
    join &control as control
    on upcase(__contents.name) like upcase(trim(control.like))
    ;
  quit;

  %if &sqlobs %then %do;
    proc datasets nolist lib=&lib;
      modify &mem;
      rename
      %do index = 1 %to &sqlobs;
        &&__rename&index
      %end;
      ;
    quit;
  %end;
%mend;

%rename_by_like(base1)

будет записывать

NOTE: The execution of this query involves performing one or more Cartesian product joins that
      can not be optimized.
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


NOTE: Renaming variable 'Quantity Value at 31/12/2019'n to 'Quantity Value'n.
NOTE: Renaming variable 'Value at 31/12/2019'n to Value.
NOTE: Renaming variable 'Yield Exp 31/12/2019'n to 'Yield Exp'n.

NOTE: MODIFY was successful for WORK.BASE1.DATA.
NOTE: PROCEDURE DATASETS used (Total process time):

Пример 2 - управляющими данными являются карты Perl шаблонов регулярных выражений

data work.regex_name_map; length pattern $100 new_name $32; input
pattern&                             new_name&; datalines;
^(.+?)( at)? *\d{1,2}\/\d{1,2}\/\d{4}$  $1
;

%macro rename_by_regex(data, control=work.regex_name_map);
  %local lib mem index;

  %let syslast = &data;
  %let lib = %scan(&syslast,1);
  %let mem = %scan(&syslast,2);

  %if %sysfunc(exist(work.__contents)) %then %do;
    proc sql; drop table __contents;
  %end;

  proc contents noprint data=&data out=__contents(keep=name);
  proc sql;
    select
      quote(trim(__contents.name))||'n' ||
      '=' || 
      quote(prxchange('s/'||trim(control.pattern)||'/'||trim(control.new_name)||'/',
                      1,
                      trim(__contents.name)
      ))||'n'
    into :__rename1-
    from __contents 
    join &control as control
    on prxmatch('/'||trim(control.pattern)||'/i', trim(__contents.name));
  quit;

  %if &sqlobs %then %do;
    proc datasets nolist lib=&lib;
      modify &mem;
      rename
      %do index = 1 %to &sqlobs;
        &&__rename&index
      %end;
      ;
    quit;
  %end;
%mend;

%rename_by_regex(base2)
0 голосов
/ 22 января 2020

Предполагая, что ваши данные поступают как существующий набор данных, вы можете использовать dictionary.columns и макрос для генерации кода, который переименует все в конце вашего шага данных. В вашем случае есть два сценария ios:

  1. Слово «в» находится в строке, и есть дата
  2. Слово «в» отсутствует в строка и дата

Извлеките соответствующие слова из строки, используя эти сценарии ios:

  1. Найдите, где начинается 'at', и возьмите все буквы в имя столбца до этой точки
  2. Найдите, где начинается любая ди git и захватите все буквы в имени столбца до этой точки

Сохраните имена переменных и имена столбцов в трубе -ограниченные списки макропеременных. Это полезно, потому что вы можете l oop через эти списки и легко получить каждое слово в отдельности. Они действуют как массив в очень свободном смысле.

proc sql noprint;
    select name
         , CASE
              when(findw(name, 'at')) then substr(name, 1, findw(name, 'at')-1)
              else substr(name, 1, anydigit(name)-1)
           END
           as new_name
    into :names separated by '|'
       , :new_names separated by '|'
    from dictionary.columns
    where     libname = 'WORK'
          AND memname = 'HAVE'
          AND name NE calculated new_name
    ;
quit;

/* Generate code to rename the variables */
%macro rename;
    %do i = 1 %to %sysfunc(countw(&names, |));
        %let name     = %scan(&names, &i, |);
        %let new_name = %scan(&new_names, &i, |);

        rename "&name"n = "&new_name"n;
    %end;
%mend;

data want;
    set have;

    %rename;
run;

Если ваши данные велики, вы можете сэкономить время, используя proc datasets и переименовывая на месте, а не создавая новый набор данных для переименования переменных.

proc datasets nolist;
    modify have;
    %rename;
quit;
...