0

如何删除 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

4 回答 4

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;
于 2018-09-20T11:27:00.290 回答
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;

跑;

祝你好运!

于 2018-09-20T18:29:51.340 回答
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 方法来编写解决方案以删除具有所有相同值的列- 搜索它们!

于 2018-09-20T11:19:31.317 回答
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;
于 2018-09-20T15:42:44.987 回答