如何删除SAS中仅声明为“ Null”但不为空的多个列变量?

时间:2018-09-20 10:48:29

标签: sas

如何删除SAS中仅声明为“ Null”但不为空的多个列变量?我已经创建了下表;

DATA test;
INPUT name$ favourite_food$ occupation$ favourite_sport$;
CARDS;
John Null Nurse Null 
Michelle Null Lawyer Null
Peter Null Teacher Null 
Kai Null Doctor Null 
run;

由于具有Null值的列不是空白,所以我不确定如何删除这些列。我不需要它们进行分析。

我也知道我可以使用drop命令删除列。但是,当我有大约90个变量时,还有一种更有效的方法来删除多个“空”变量

4 个答案:

答案 0 :(得分:3)

nlevels中的proc freq选项返回每列中不同值的数量。因此,所有值都相同的列的nlevel值将为1。

如果您确信此规则仅适用于“空”列,则可以使用此方法(即,至少有2个不同的名称,职业等值)。

nlevel的值不会自动包含在proc freq中的输出表中,因此您需要使用ods output将列名放入表中。然后,您可以将它们分配给宏变量,以便在所使用的任何分析过程中的drop语句中使用。或者,您可以按照数据步骤中的要求将其删除。 (我通常更喜欢前一种选择,以防万一错误删除了有效数据)。

DATA test;
INPUT name$ favourite_food$ occupation$ favourite_sport$;
CARDS;
John Null Nurse Null 
Michelle Null Lawyer Null
Peter Null Teacher Null 
Kai Null Doctor Null 
run;

/* identify columns with only 1 distinct value and output to a table */
ods output nlevels = distinct_values (where=(nlevels=1));
proc freq data=test nlevels;
run;

/* store column names in macro variable */
proc sql noprint;
select tablevar into :drop_cols separated by ' '
from distinct_values;
quit;

%put &drop_cols;

/* exclude columns from analysis */
proc freq data=test (drop=&drop_cols.);
run;

答案 1 :(得分:1)

需要对数据进行全面扫描,以检查所有列中的所有值。在扫描期间,如果出现"Null"以外的值,则该列将不作为删除候选对象。

您可以使用一个临时数组来跟踪字符列名称是什么,并将另一个数组设置为_CHARACTER_,以便可以在每一行中迭代这些列。该过程将构建可以根据您的条件删除的列的列表-该列表位于宏符号表中,并且可以在后续代码中使用,以重写不包含这些列的数据,或者只是删除在处理过程中使用数据集选项。

DATA test;
INPUT name$ favourite_food$ occupation$ favourite_sport$;
CARDS;
John Null Nurse Null 
Michelle Null Lawyer Null
Peter Null Teacher Null 
Kai Null Doctor Null 
Zonker Null Null Null
run;

%let DROP_VARS=;

data _null_;
  set test end=end;

  array char_vars _CHARACTER_;               * for iterating over values;
  array null_vars (1000) $32 _temporary_ ;   * for tracking column names;

  * populate column name tracking array;
  if _n_ = 1 then do;
    do index = 1 to dim(char_vars);
      null_vars(index) = vname(char_vars(index));
    end;
  end;

  * scan each row, iterating over character variables;
  * remove a column name from drop consideration when non "Null" occurs;
  do index = 1 to dim(char_vars);
    if not missing(null_vars(index)) then
      if char_vars(index) ne "Null" then
        null_vars(index) = '';
  end;

  * place space separated list of columns containing only "Null" in macro symbol table;
  if end then
    call symput('DROP_VARS', catx(' ', of null_vars(*)));
run;

* use macro variable as desired;

%put NOTE: &=DROP_VARS;

proc print data=test(drop=&DROP_VARS);
  title "Non-null columns of TEST";
run;

data TEST2(label="Copy of Test, excluding null columns");
  set TEST;
  drop &DROP_VARS;
run;

还有许多其他SAS方式来为删除具有相同值的列编码解决方案–向上搜索它们!

答案 2 :(得分:1)

在这种情况下,您有两种选择。

1,使用保持。 keep函数保留您想要的变量,因此,如果您已经知道变量不是NULL的话,只需放入keep,例如:

数据测试(保持=最喜欢的食物职业);

INPUT name$ favourite_food$ occupation$ favourite_sport$;
CARDS;
John Null Nurse Null 
Michelle Null Lawyer Null
Peter Null Teacher Null 
Kai Null Doctor Null 

运行;

如果您知道favorite_food并且职业不是NULL。

2,使用删除功能示例:

数据测试;

INPUT name$ favourite_food$ occupation$ favourite_sport$;
CARDS;
   if name eq NULL then delete;

运行;

祝你好运!

答案 3 :(得分:0)

在宏中使用sql的另一种方法。添加详细注释。  @longfish解决方案简单有效。

   %macro abc;
/* picking up the variables on which Null check is needed*/
   proc sql;
    /*finding total number of obervations*/
      select count(*) into :cnt from test;
       select name into :name separated by '|' from dictionary.columns
            where upcase(memname) = 'TEST'
            and lowcase(name) like '%favourite_%';

    /*creting temporary table to hold the values which should be dropped*/
    create table temptable(col char(50),val num);;

    /* looping through variables for which null check is needed*/
    %do i = 1 %to %sysfunc(countw(&name, |));
        %let col_val =%scan(&name,&i,|);

        /* total obervations minus count for variables with null values gives 0
        indicates that all are null values and are inseted in a temptable*/
proc sql;
    insert into temptable
        select col, val from
        (select "&col_val" as col , &cnt- count(&col_val) as val
            from test
                where &col_val = "Null")
                where val = 0;
    %end;

    /*picking up all the columns to be dropped*/
proc sql;
    select col into  :drop_columns separated by ' '
        from temptable;
    %put &drop_columns;

    /* dropping the columns*/
data want;
    set test(drop=&drop_columns);
run;

%mend;

%abc;