2010-07-16 3 views
4

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

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

+0

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

+0

Hi Louisa - не могли бы вы рассказать о том, как вы это сделали для числовых столбцов? Благодаря! –

+0

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

ответ

3

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

Он использует параметр 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

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

Приветствия Роб

EDIT: Обратите внимание, что это работает как для символа и числовых переменных.

** 
** 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

Роб и cmjohns, спасибо вам большое за вашу помощь. В зависимости от ваших решений и идеи я имел за выходные, вот что я придумал:

%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 способа и сообщить, на которых один является самым быстрым ...

P.S. добавлено 23 декабря 2010 для справок: SGF Paper 048-2010: Dropping Automatically Variables with Only Missing Values

+1

Rob and cmjohns- Еще раз спасибо - все 3 решения работали, а cmjohns был самым быстрым, –