Sas 删除包含太多无效/缺少值的变量

Sas 删除包含太多无效/缺少值的变量,sas,Sas,假设我的数据集有很多缺失/无效值,如果它包含太多无效值,我想删除或删除整个变量或列 以下面的示例为例,变量'gender'有相当多的N/As。如果其中某个百分比的数据点为N/a,比如超过50%,超过30%,我想删除该变量 此外,我希望将百分比设置为可配置的值,即,如果变量下超过x%的观察值为N/a,我愿意删除整个变量。我还希望能够定义什么是无效值,可能是N/a,可能是无效值,可能是,可能是我预先定义的任何其他值 data dat; input id score gender $; car

假设我的数据集有很多缺失/无效值,如果它包含太多无效值,我想删除或删除整个变量或列

以下面的示例为例,变量'gender'有相当多的N/As。如果其中某个百分比的数据点为N/a,比如超过50%,超过30%,我想删除该变量

此外,我希望将百分比设置为可配置的值,即,如果变量下超过x%的观察值为N/a,我愿意删除整个变量。我还希望能够定义什么是无效值,可能是N/a,可能是无效值,可能是,可能是我预先定义的任何其他值

data dat;
  input id score gender $;
  cards;
  1 10 1
  1 10 1
  1 9 #N/A
  1 9 #N/A
  1 9 #N/A
  1 8 #N/A
  2 9 #N/A
  2 8 #N/A
  2 9 #N/A
  2 9 2
  2 10 2
  ;
run;
请尽可能把这个解决方案概括化。例如,如果真实数据集包含数千个变量,我需要能够循环遍历所有这些变量,而不是逐个引用它们的变量名。此外,数据集可能不仅仅包含N/A,因为坏值,其他东西,例如,无效Obs,N.A.也可能同时存在

PS:事实上,我想了一个让这个问题更容易解决的方法。我们可以把所有的数据点读入为数值,这样所有的N/A,N.A.,都变成了。,这使得下降标准更容易。希望能帮你帮我解决这个问题

更新:下面是我正在处理的代码。在最后一个街区被卡住了

data dat;
  input id $ score $ gender $;
  cards;
  1 10 1
  1 10 1
  1 9 #N/A
  1 9 #N/A
  1 9 #N/A
  1 8 #N/A
  2 9 #N/A
  2 8 #N/A
  2 9 #N/A
  2 9 2
  2 10 2
  ;
run;

proc contents data=dat out=test0(keep=name type) noprint; 

/*A DATA step is used to subset the test0 data set to keep only the character */
/*variables and exclude the one ID character variable.  A new list of numeric*/ 
/*variable names is created from the character variable name with a "_n"     */
/*appended to the end of each name.                                          */                                                        

data test0;                                                
set test0;                                                 
if type=2;                  
newname=trim(left(name))||"_n";                                                                               

/*The macro system option SYMBOLGEN is set to be able to see what the macro*/
/*variables resolved to in the SAS log.                                    */                                                       

options symbolgen;                                        

/*PROC SQL is used to create three macro variables with the INTO clause.  One  */
/*macro variable named c_list will contain a list of each character variable   */
/*separated by a blank space.  The next macro variable named n_list will       */
/*contain a list of each new numeric variable separated by a blank space.  The */
/*last macro variable named renam_list will contain a list of each new numeric */
/*variable and each character variable separated by an equal sign to be used on*/ 
/*the RENAME statement.                                                        */                                                        

proc sql noprint;                                         
select trim(left(name)), trim(left(newname)),             
       trim(left(newname))||'='||trim(left(name))         
into :c_list separated by ' ', :n_list separated by ' ',  
     :renam_list separated by ' '                         
from test0;
quit;                                                                                                               


/*The DATA step is used to convert the numeric values to character.  An ARRAY  */
/*statement is used for the list of character variables and another ARRAY for  */
/*the list of numeric variables.  A DO loop is used to process each variable   */
/*to convert the value from character to numeric with the INPUT function.  The */
/*DROP statement is used to prevent the character variables from being written */
/*to the output data set, and the RENAME statement is used to rename the new   */
/*numeric variable names back to the original character variable names.        */                                                        

data test2;                                               
set dat;                                                 
array ch(*) $ &c_list;                                    
array nu(*) &n_list;                                      
do i = 1 to dim(ch);                                      
  nu(i)=input(ch(i),8.);                                  
end;                                                      
drop i &c_list;                                           
rename &renam_list;                                                                                      
run; 




data test3;                                               
set test2;                                                 
array myVars(*) &c_list;                               
countTotal=1;
do i = 1 to dim(myVars);
    myCounter = count(.,myVars(i));
/*  if sum(countMissing)/sum(countTotal) lt 0.5 then drop VNAME(myVars(i)); */
end;

run;

问题是,我陷入困境的地方是,我无法删除我想要删除的变量。原因是我不想在drop函数中使用变量名。相反,我希望它在一个循环中完成,在这个循环中,我可以用looper I引用变量名。我尝试使用数组myVarsi,但它似乎无法与drop函数配合使用

我的理解是,SAS在数据步骤编译期间(即在查看任何输入数据集的任何数据之前)处理drop语句。因此,不能像那样使用vname函数来选择要删除的变量,因为在数据步骤完成编译并继续执行之前,它不会计算变量名

您需要输出一个包含所有变量(包括您不想要的变量)的临时数据集或视图,在宏变量中建立要删除的变量列表,然后在后续数据步骤中删除它们

请参阅本文,特别是第3页,了解编译期间而非执行期间运行的更多详细信息:


一般来说,您会发现使用内置程序简化了这类事情-这是SAS的面包和黄油。你只需要重申一下这个问题

您想要的是删除丢失/坏数据百分比高于50%的变量,所以您需要一个变量频率表,对吗

因此-使用PROC FREQ。这是一个简化版本,只查找N/A,但应该很容易修改最后一步,使其查找其他值并汇总它们的百分比。或者,正如您在我对问题的评论中的链接问题中所看到的,您可以使用一种特殊格式,将所有无效值放入一个格式化值,将所有有效值放入另一个格式化值。您必须构造此格式

概念:使用PROC FREQ获取频率表,然后查看该数据集,找到行数>50%且F_u列中的值无效的行

这将不适用于实际的丢失或丢失。;如果您也有/MISSING选项,则需要将其添加到PROC FREQ

data dat;
  input id $ score $ gender $;
  cards;
  1 10 1
  1 10 1
  1 9 #N/A
  1 9 #N/A
  1 9 #N/A
  1 8 #N/A
  2 9 #N/A
  2 8 #N/A
  2 9 #N/A
  2 9 2
  2 10 2
  ;
run;

*shut off ODS for the moment, and only use ODS OUTPUT, so we do not get a mess in our results window;
ods exclude all;
ods output onewayfreqs=freq_tables;
proc freq data=dat;
  tables id score gender;
run;
ods output close;
ods exclude none;

*now we check for variables that match our criteria;    
data has_missing;
  set freq_tables;
  if coalescec(of f_:) ='#N/A' and percent>50;
  varname = substr(table,7);
run;

*now we put those into a macro variable to drop;
proc sql;
  select varname 
    into :droplist separated by ' '
    from has_missing;
quit;

*and we drop them;
data dat_fixed;
  set dat;
  drop &droplist.;
run;

堆栈溢出不是代码生成服务。你应该尝试解决这个问题,然后带着关于你的解决方案的问题回来——而不仅仅是问一个重大问题的解决方案。我同意乔的观点——你似乎已经对你想要做的事情有了相当清楚的想法,所以先自己动手做吧。如果您在某个特定步骤中遇到困难,请务必发布您的代码并寻求帮助。现在我提供了更多详细信息和我正在处理的代码,请删除您的大拇指,因为我不再要求代码生成服务,@JoeThank you改进您的问题。改进了很多。谢谢。谢谢你的评论。这是有道理的。我正在看你所附的链接,我会回来看看我的发现:谢谢你,乔,你肯定是个专业人士。我第一次看到这个问题时就想到了freq,但后来我在不知道substr、Coalescc等函数的情况下,努力从freq输出表中提取出我需要的确切信息,等等,一个简单的问题,在代码的最后一行的第二行,为什么在&droplist的末尾添加一个小点?如果我将百分比设置得很高,最终输出可能仍然会删除带有N/A的列
en varname变为空,这将导致无法解析droplist。您可以从%let droplist=;就在proc-sql之前,确保它能够解决。再次感谢你,乔。