Суммирование столбцов по общему суффиксу в SAS - PullRequest
1 голос
/ 10 мая 2019

У меня есть серия столбцов с названиями Income_2015, Interest 2015, Dividends 2015, Income_2018, Interest 2018, Dividends 2018 и т. Д., И я хочу создать общее количество столбцов для каждого года.

Есть ли способ сделать это в SAS без необходимости индивидуального перечисления всех столбцов в сумме

В настоящее время я использую следующее для получения итогов по типу:

data keep;
set from;

income_total = sum(of Income_:);
run;

Я не могу найтиспособ суммировать по годам, если я не использую:

year_2015_total = sum(Income_2015, Interest_2015, Dividends_2015)

.... year_2018_total = sum(Income_2018, Interest_2018, Dividends_2018)

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

Ответы [ 3 ]

0 голосов
/ 10 мая 2019

Вы можете попробовать использовать макропеременные, такие как:

proc sql;
    select name into:list_2015 separated by ',' from dictionary.columns where libname='YOURLIB' and memname='YOURDATA' and name contains '2015';
quit;

data want;
  set have;
  sum_2015=sum(of &list_2015);
run;
0 голосов
/ 10 мая 2019

Ваш дизайн данных, к сожалению, сохранил элемент данных как часть метаданных (часть имени (имен) переменных), и вы получаете набор данных, который становится широким.

Категориальная форма подходит для броскаагрегирование и использование процедур отчетности, таких как TABULATE или REPORT, для генерации «широкого» представления данных.

id topic     year  amount
a  income    2015  
a  interest  2015  
a  dividends 2015
a  losses    2015
b  income    2015  
b  interest  2015  
b  dividends 2015
                    … no losses row for id=b corresponds to 'missing' value in wide form
c  income    2015  
c  interest  2015  
                    … c had no dividends, no losses, no fubars

Сохранение структуры без изменений (иногда вам просто нужно, например,данные мэйнфрейма из десяти миллионов учетных записей, охватывающих 60 лет), вам необходимо предварительно обработать набор данных с помощью шага, который идентифицирует столбцы, содержащие значение года, и использовать эту информацию в последующем коде шага, который содержит генерацию кода (т. е. макрос), которыйохватывает годы, как указано в названиях столбцов.Например:

%macro make_data(data=);
  %local year category index varname;

  data &data;
    do accountid = 1 to 20;
      %do index = 65 %to 90;
      %do year=1995 %to 2019;
        %let varname = %sysfunc(byte(&index))_&year;
        amount+1;
        &varname = amount;
      %end;
      %end;
      output;
    end;
    drop amount;
  run;
%mend;

%macro generate_year_total_code(data=);
  proc contents noprint data=&data out=havemeta(keep=name);
  run;

  data havemeta2;
    set havemeta;
    if prxmatch ("/[^0-9]\d{4}/", trim(name));
    year = input(substr(name,length(name)-3), 4.);
  run;

  proc sort data=havemeta2;
    by year;
  run;

  data _null_;
    length varlist $32000;

    do until (last.year);
      set havemeta2;
      by year;

      varlist = catx(',', varlist, name);
    end;

    call symputx('year_count', _n_);
    call symput ( cats('total_statement_', _n_)
                , cats('total_',year,'=sum(',varlist,')'));
  run;
%mend;

%macro totals(data=);

  %generate_year_total_code(data=&data);

  %local index; 

  data &data;
    set &data;
    %do index = 1 %to &year_count;
      &&total_statement_&index;
    %end;
  run;

%mend;

%make_data(data=have);

options mprint;
%totals(data=have);

Альтернативой является преобразование данных в категориальную форму для извлечения значения года для соответствующего свертывания или использования в категориальной отчетности.Например:

proc transpose data=have out=haveTall;
  by accountid;
run;

data haveTall;
    set haveTall;
    if prxmatch ("/_\d{4}$/", trim(_name_));  * data value in col1 is from a year suffixed variable name;
    year = input(substr(_name_,length(_name_)-3), 4.);
    category = substr(_name_,1, length(_name_)-5);
    amount = col1;
    drop _name_ col1;
run;

proc tabulate data=haveTall;
  class accountid category year;
  var amount;
  table 
    accountid * category
    , 
    year=''*amount=''*sum=''
    /
    nocellmerge
    ;
run;

Третий, более сложный, но лаконичный способ.Динамическое вычисление итогов с использованием хеш-объекта, вывод итогов и слияние с исходными данными.Для этого требуется больше процессора, чем для способа №1, поскольку имена переменных PDV оцениваются в каждой строке.

data _null_;
  if 0 then set have(keep=accountid);

  length year amount 8;
  declare hash totals(ordered:'a');
  totals.defineKey('accountid', 'year');
  totals.defineData('accountid', 'year', 'total');
  totals.defineDone();
  call missing (year, amount, accountid);

  do until (end);
    set have end=end;
    array numbers _numeric_;

    do over numbers;
      length name $32;
      name = vname(numbers);
      if prxmatch ("/_\d{4}$/", trim(name)) then do;
        year = input(substr(name,length(name)-3), 4.);
        if totals.find() = 0
          then total + numbers;
          else total = numbers;
        totals.replace();
      end;
    end;
  end;

  totals.output(dataset:'totals');

  stop;
run;

proc transpose data=totals prefix=total_ out=totals_across_year(drop=_name_);
  by accountid;
  var total;
  id year;
run;
0 голосов
/ 10 мая 2019

Нет простого / автоматического способа определения списка переменных по суффиксу. То есть нет ничего прямо эквивалентного sum (of :2018).

Тем не менее, у вас есть варианты. Одним из них является использование массивов. Они позволяют ссылаться на список переменных по имени массива.

Другой способ - использовать язык макросов. Это позволит вам создать макропеременную, содержащую список всех имен переменных, имеющих определенный суффикс.

Но я думаю, что лучшее решение - это реструктурировать ваши данные.

Если ваши данные теперь выглядят так:

Person Income_2015 Interest_2015 Income_2016 Interest_2016
1      100,000     1,000         200,000     2,000
2      500,000     5,000         600,000     6,000

Транспонировать в:

Person Year        Income      Interest
1      2015        100,000     1,000
1      2016        200,000     2,000
2      2015        500,000     5,000
2      2016        600,000     6,000

Эта вертикальная структура упрощает работу с данными намного , и вы можете легко агрегировать данные по годам (столбцы) или источникам дохода (строки). Ключевым моментом является то, что год действительно является ценностью данных. Таким образом, вертикальная («нормализованная») структура приносит вам пользу, сохраняя год как значение в переменной, вместо того, чтобы хранить год как часть имени переменной.

...