Выберите символьные переменные, которые имеют все пропущенные значения - PullRequest
4 голосов
/ 16 июля 2010

У меня есть набор данных SAS с около 3000 переменных, и я хотел бы избавиться от символьных переменных, для которых отсутствуют все значения. Я знаю, как это сделать для числовых переменных. Меня интересует именно символьные переменные. Мне нужно выполнить работу с использованием базового SAS, но это может включать в себя proc SQL, поэтому я также пометил этот «SQL».
Спасибо!

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

Ответы [ 3 ]

4 голосов
/ 19 июля 2010

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

Используетсяproc freq с опцией уровней и пользовательским форматом для определения пустых символьных столбцов.Затем proc sql используется для создания списка столбцов, которые необходимо удалить, и сохранения их в макропеременной.

Вот макрос:

%macro delemptycol(ds=_last_, suffix=_noempty);

option nonotes;
proc format;
  value $charmiss
    ' '= ' '
    other='1';
run;
%if "&ds"="_last_" %then %let ds=&syslast.;

ods select nlevels;
ods output nlevels=nlev;
proc freq data=&ds.(keep=_character_) levels ;
  format _character_ $charmiss.;
run;
ods output close;

/* create macro var with list of cols to remove */
%local emptycols;
proc sql noprint;
  select tablevar into: emptycols separated by ' '
  from nlev
  where NNonMissLevels=0;
quit;

%if &emptycols.=  %then %do;
  %put DELEMPTYCOL: No empty character columns were found in data set &ds.;
  %end;
%else %do;
  %put DELEMPTYCOL: The following empty character columns were found in data set &ds. : &emptycols.;
  %put DELEMPTYCOL: Data set &ds.&suffix created with empty columns removed;
  data &ds.&suffix. ;
    set &ds(drop=&emptycols);
  run;
%end;
options notes;

%mend;

Примеры использования:

/* create some fake data: Here char5 will be empty */
data chardata(drop= j randnum);
length char1-char5 $8.;
array chars(5) char1-char5;
  do i=1 to 100;
    call missing(of char:);
    randnum=floor(10*ranuni(i));
    do j=2 to 5;
      if (j-1)<randnum<=(j+1) then chars(j-1)="FOO";
    end;
    output;
  end;
run;

%delemptycol();  /* uses default _last_ for the data and "_noempty" as the suffix */
%delemptycol(ds=chardata, suffix=); /* removes the empty columns from the original */
2 голосов
/ 19 июля 2010

Возможно, есть более простой способ, но это то, что я придумал.

Приветствие Rob

РЕДАКТИРОВАТЬ: Обратите внимание, что это работает как для символьных, так и для числовых переменных.

**
** TEST DATASET
*;
data x;
  col1 = "a"; col2 = ""; col3 = "c"; output;
  col1 = "" ; col2 = ""; col3 = "c"; output;
  col1 = "a"; col2 = ""; col3 = "" ; output;
run;

**
** GET A LIST OF VARIABLE NAMES
*;
proc sql noprint;
  select name into :varlist separated by " " 
  from sashelp.vcolumn
  where upcase(libname) eq "WORK" 
    and upcase(memname) eq "X";
quit;

%put &varlist;


**
** USE A MACRO TO CREATE A DATASTEP.  FOR EACH COLUMN THE 
** THE DATASTEP WILL CREATE A NEW COLUMN WITH THE SAME NAME
** BUT PREFIXED WITH "DELETE_".  IF THERE IS AT LEAST 1 
** NON-MISSING VALUE FOR THE COLUMN THEN THE "DELETE" COLUMN
** WILL FINISH WITH A VALUE OF 0, ELSE 1.  WE WILL ONLY
** KEEP THE COLUMNS CALLED "DELETE_" AND OUTPUT ONLY A SINGLE
** OBSERVATION TO THE FINAL DATASET.
*;
%macro find_unused_cols(iDs=);
  %local cnt;

    data vars_to_delete;
      set &iDs end=eof;

      %let cnt = 1;
      %let varname = %scan(&varlist, &cnt);
      %do %while ("&varname" ne "");
        retain delete_&varname;
        delete_&varname = min(delete_&varname, missing(&varname));
        drop &varname;
        %let cnt = %eval(&cnt + 1);
        %let varname = %scan(&varlist, &cnt);
      %end;

      if eof then do;
        output;
      end;

    run;

%mend;
%find_unused_cols(iDs=x);

**
** GET A LIST OF VARIABLE NAMES FROM THE NEW DATASET
** THAT WE WANT TO DELETE AND STORE TO A MACRO VAR.
*;
proc transpose data=vars_to_delete out=vars_to_delete;
run;

proc sql noprint;
  select substr(_name_,8) into :vars_to_delete separated by " " 
  from vars_to_delete
  where col1;
quit;

%put &vars_to_delete;


**
** CREATE A NEW DATASET CONTAINING JUST THOSE VARS
** THAT WE WANT TO KEEP
*;
data new_x;
  set x;
  drop &vars_to_delete;
run;
1 голос
/ 19 июля 2010

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

%macro removeEmptyCols(origDset, outDset);
    * get the number of obs in the original dset;
    %let dsid  = %sysfunc(open(&origDset));
    %let origN = %sysfunc(attrn(&dsid, nlobs));
    %let rc    = %sysfunc(close(&dsid));

    proc transpose data= &origDset out= transpDset;
        var _all_;
    run;

    data transpDset;
        set transpDset;
        * proc transpose converted all old vars to character,
          so the . from old numeric vars no longer means 'missing';
        array oldVar_ _character_;
        do over oldVar_;
            if strip(oldVar_) = "." then oldVar_ = "";
        end;

        * each row from the old dset is now a column with varname starting with 'col';
        numMiss = cmiss(of col:);

        numCols = &origN;
    run;

    proc sql noprint;
      select _NAME_ into: varsToKeep separated by ' '
      from transpDset
      where numMiss < numCols;
    quit;

    data &outDset;
        set &origDset (keep = &varsToKeep);
    run;
%mend removeEmptyCols;

Я попробую все 3 способа и сообщу, какой из них самый быстрый ...

PS добавлен 23 декабря 2010 г. для дальнейшего использования: SGF Paper 048-2010: автоматическое удаление переменных только с отсутствующими значениями

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