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