SAS:如何将多列数据分组为单列?

时间:2016-02-03 07:10:29

标签: csv sas

我从数据中获得了以下结果,如下所示:

Obtained

但我想根据下面给出的图像对数据进行子集化:

Want

执行相同的任何最简单的方法。此外,我想找出每个变量的曝光百分比。对于'A',百分比暴露将是331 /(331 + 941 + 820 + 444 + 658),并且对于每个'级别',必须找到百分比。任何人都可以告诉我这样做的正确方法。

使用数据找出Table1的代码如下:

数据:

Policy_Number,var1,var2,var3,Exposure
1,B,H,J,191
2,B,F,Unknown,174
3,C,Unknown,I,153
4,B,G,L,192
5,Unknown,E,Unknown,184
6,D,E,K,113
7,C,Unknown,I,140
8,A,H,I,133
9,C,F,I,194
10,Unknown,G,Unknown,105
11,B,H,L,172
12,A,Unknown,I,198
13,D,E,K,155
14,Unknown,G,K,177
15,B,H,Unknown,100
16,D,Unknown,J,176
17,B,E,I,112
18,Unknown,E,J,192
19,C,Unknown,K,146
20,C,G,Unknown,187

代码:

    data try2;
infile 'complex.csv' dsd dlm = ',' FIRSTOBS = 2;
Length Policy_Number Var1 $ 10 Var2 $ 10 Var3 $ 10 Exposure 3;
input Policy_Number $ Var1 $ Var2 $ Var3 $ Exposure;
run;

/*When the variables are known*/
proc summary data=try2;
   class Var1 Var2 Var3;
   ways 1;
   freq Exposure;
   output out=test(rename=(_freq_=TotExposures));
   run;

3 个答案:

答案 0 :(得分:2)

从您的csv文件开始,您可以通过proc freq + 1数据步骤获得相同的输出,而不是proc summary + data step + proc sql

data mycsv;
    infile cards dsd dlm=',';
    Length Policy_Number Var1 $ 10 Var2 $ 10 Var3 $ 10 Exposure 3;
    input Policy_Number $ Var1 $ Var2 $ Var3 $ Exposure;
    cards;
1,B,H,J,191
2,B,F,Unknown,174
3,C,Unknown,I,153
4,B,G,L,192
5,Unknown,E,Unknown,184
6,D,E,K,113
7,C,Unknown,I,140
8,A,H,I,133
9,C,F,I,194
10,Unknown,G,Unknown,105
11,B,H,L,172
12,A,Unknown,I,198
13,D,E,K,155
14,Unknown,G,K,177
15,B,H,Unknown,100
16,D,Unknown,J,176
17,B,E,I,112
18,Unknown,E,J,192
19,C,Unknown,K,146
20,C,G,Unknown,187
;
run;

/*Optional - prevent output being displayed in the results area*/
ods _all_ close;

/*Divert proc freq output to a sas dataset test1*/
ods output onewayfreqs = test1(keep = var1-var3 frequency percent);

/*Produce weighted frequency tables*/
proc freq data = mycsv;
    weight exposure;
    table var1-var3;
run;

/*Turn listing output back on again so that subsequent code works as normal*/
ods listing; 

/*Tidy up*/
data want;
    length varname $32 varlevel $8;
    array myvars $ var1-var3;
    set test1;
    varlevel = coalescec(of myvars[*]);
    do i = 1 to dim(myvars);
        if not(missing(myvars[i])) then varname = vname(myvars[i]);
    end;
    drop var1-var3 i;
run;

如果所有变量属于同一类型(字符/数字)并且它们在数据集的列顺序中彼此相邻,则可以使用双破折号列表来定义数组,而无需重命名它们顺序。例如而不是var1-var3你可以输入
firstNumericVar--lastNumericVar。如有必要,您可以使用适当的列顺序创建原始数据集的视图。

说明

默认情况下,proc freq将输出写入结果区域,其中包括所请求的频率表中每个变量的每个级别的观察次数和百分比。这已经非常接近你要做的事了,proc summary没有任何直接的等价选项。

第一个调整是指定weight exposure;,以便我们将曝光值相加而不是计算每个级别中的行。现在数字是正确的,我们只需要获得某种输出数据集......

默认情况下,proc freq不会生成输出sas数据集,因此执行此操作的“常用”方法是在/out=mytable语句中指定tables。但是,如果您尝试这样的事情:

proc freq data = mycsv;
    table var1-var3 /out = mytable;
run;

mytable将仅包含列表中最后一个变量的频率,在本例中为var3。因此,我们有两个选项 - 使用不同的table数据集为每个变量写出一个/out=语句,并将它们全部附加在一起(非常混乱),或者使用ods output

这里的技巧是知道你可以在运行任何proc之前设置ods trace on;,然后当你检查日志时,SAS会告诉你它用于打印到结果区域的所有表的内部名称。在这种情况下,输出如下所示:

 57         ods trace on;
 58         proc freq data = mycsv;
 59         weight exposure;
 60         table var1-var3;
 61         run;


 Output Added:
 -------------
 Name:       OneWayFreqs
 Label:      One-Way Frequencies
 Template:   Base.Freq.OneWayFreqs
 Path:       Freq.Table1.OneWayFreqs
 -------------

 Output Added:
 -------------
 Name:       OneWayFreqs
 Label:      One-Way Frequencies
 Template:   Base.Freq.OneWayFreqs
 Path:       Freq.Table2.OneWayFreqs
 -------------

 Output Added:
 -------------
 Name:       OneWayFreqs
 Label:      One-Way Frequencies
 Template:   Base.Freq.OneWayFreqs
 Path:       Freq.Table3.OneWayFreqs
 -------------
 NOTE: There were 20 observations read from the data set WORK.MYCSV.
 NOTE: PROCEDURE FREQ used (Total process time):
       real time           0.05 seconds
       cpu time            0.06 seconds

有趣的是表名OneWayFreqs,它出现3次,对应于var1-var3结果区域中绘制的3个单向频率表。现在我们知道了这个表名,我们可以告诉sas在我们下次运行proc时将相同的输出发送到我们选择的SAS数据集,这就是这个语句正在做的事情:

ods output onewayfreqs = test1(keep = var1-var3 frequency percent);

恰好会产生同一个表的多个实例,它们都会输出到目标数据集,而不仅仅是最后一个。在我刚刚尝试这个之前,我实际上并不知道它的工作原理!

还有一点值得一提 - 通常情况下,如果你不想在使用像
noprint语句中设置proc freq >  table var1 / out = mytable;包含大量数据集。但是,这也会阻止将任何内容发送到ODS,从而阻止创建通过ods output指定的任何数据集。因此,您必须告诉ODS本身不要通过ods _all_ closeods select none生成任何其他输出。

答案 1 :(得分:1)

数据步骤涉及使用数组将所有非缺失的var-var3加入到一个中。我循环遍历数组,一旦找到非空元素,我就使用vname数组函数输出非缺失元素及其名称。重要的是,只有一个非缺失值,就像您的数据一样。

通过分组曝光来对proc SQL进行汇总,然后将汇总统计数据合并回来计算出百分比比例。

我希望这是有道理的。

请参阅下面的代码:

data want (drop=i var1-var3);
    set test;
    array var_array[*] var:;
    do i=1 to dim(var_array);
        if var_array[i] ne "" then
            do;
                levels = var_array[i];
                variable = vname(var_array[i]);
                output;
            end;
    end;
run;


PROC SQL;
   CREATE TABLE WORK.QUERY_FOR_WANT AS 
   SELECT t1._TYPE_, 
          t1.levels, 
          t1.variable, 
          /* SUM_of_TotExposures */
            (SUM(t1.TotExposures)) AS SUM_of_TotExposures, 
          t1.TotExposures, 
          /* Calculation */
            (t1.TotExposures / (SUM(t1.TotExposures))) FORMAT=PERCENTN6. AS Calculation
      FROM WORK.WANT t1
      GROUP BY t1.variable;
QUIT;

答案 2 :(得分:0)

title;
data exp;
   infile cards dsd firstobs=2;
   input Policy_Number (var1-var3) ($) Exposure;
   arbitraryname243 = rank(first(var1));
   arbitraryname4 = rantbl(123,.4);
   arbitraryname36 = rank(first(var3));
   cards;
Policy_Number,var1,var2,var3,Exposure
1,B,H,J,191
2,B,F,Unknown,174
3,C,Unknown,I,153
4,B,G,L,192
5,Unknown,E,Unknown,184
6,D,E,K,113
7,C,Unknown,I,140
8,A,H,I,133
9,C,F,I,194
10,Unknown,G,Unknown,105
11,B,H,L,172
12,A,Unknown,I,198
13,D,E,K,155
14,Unknown,G,K,177
15,B,H,Unknown,100
16,D,Unknown,J,176
17,B,E,I,112
18,Unknown,E,J,192
19,C,Unknown,K,146
20,C,G,Unknown,187
;;;;
   run;
proc print;
   run;
proc transpose data=exp(obs=0 drop=policy_number exposure) out=varlist;
   var _all_;
   run;
Proc sql noprint; 
   select nliteral(_name_) into :classvars separated by ' ' from varlist;
   quit;
%put NOTE: &=classvars;
ods select none;
proc freq data=exp;
   tables &classvars / nocum;
   weight exposure;
   ods output onewayfreqs=freqs;
   run;
ods select all;

data freqs(keep=Variable Levels Frequency Percent);
   length Variable $32 Levels $64;
   set freqs;
   variable = substr(table,6);
   levels = coalesceC(of F_:);
   drop f_:;
   drop &classvars;
   run;
proc print;
   run;

enter image description here

enter image description here