【问题标题】:PROC MEANS Output MIN MAX MEDIAN for ALL numeric variablesPROC MEANS 输出所有数值变量的 MIN MAX MEDIAN
【发布时间】:2014-05-13 17:32:01
【问题描述】:

我的情况与here 提出的问题类似。但是,我不想在 var 语句中列出我的 300 个变量名,因为它们都是唯一的。有没有办法使用proc meansproc summary 为一个数据集中的所有数值变量输出汇总统计信息?

我试过了:

proc means data=my_data min median max;
    output out=summary_data min=min median=median max=max;
run;

但这仅输出第一个变量的汇总统计信息。我也在ods trace的帮助下尝试过:

proc means data=my_data min median max;
    ods output Summary=summary_data;
run;

这给了我所有变量的汇总统计数据,但仍然在一行中:

VName_VAR1 VAR1_Minimum VAR1_Median VAR1_Maximum VName_VAR2 VAR2_Minimum etc...
VAR1       3            3           3            VAR2       3         

我的 VAR 名称都是独一无二的。有没有其他方法可以使用proc meansproc summary 输出一个数据集中所有数值变量的汇总统计信息?

更新:

当我删除min=min median=median max=max:

proc means data=my_data min median max;
    output out=summary_data;
run;

代码然后产生输出:

 Obs  _TYPE_ _FREQ_ _STAT_   VAR_1    VAR_2 ... etc

 1    0      91     N          91.00  91    ... etc
 2    0      91     MIN      2005.00  13         .
 3    0      91     MAX      2014.00  13         .
 4    0      91     MEAN     2009.34  13         .
 5    0      91     STD         3.02   0

但是,它仍然没有给我 MEDIAN。

【问题讨论】:

    标签: sas


    【解决方案1】:

    当我在使用 proc means 之前转置数据时,我得到了所需的输出。

    proc sort data=sashelp.cars out=cars; by _character_;run;
    
    proc transpose data=cars out=cars_t;
      var _numeric_;
      by _character_;
    run;
    
    proc sort data=cars_t;by _name_;run;
    
    proc means data=cars_t noprint;
      output out=cars_summary(drop = _type_ _freq_) min=min median=median max=max;
      by _name_;
    run;
    

    代码然后产生输出:

    Obs    _NAME_             min     median         max
    
     1    Cylinders          3.0        6.0        12.0
     2    EngineSize         1.3        3.0         8.3
     3    Horsepower        73.0      210.0       500.0
     4    Invoice         9875.0    25294.5    173560.0
     5    Length           143.0      187.0       238.0
     6    MPG_City          10.0       19.0        60.0
     7    MPG_Highway       12.0       26.0        66.0
     8    MSRP           10280.0    27635.0    192465.0
     9    Weight          1850.0     3474.5      7190.0
    10    Wheelbase         89.0      107.0       144.0
    

    如果您的原始数据中的每一行都有唯一的 ID,则此方法有效。

    【讨论】:

    • +1 这太棒了,我希望我能把它标记为答案而不是我的!我一直在寻找减少对宏的过度依赖的方法。例如,我不知道 _CHARACTER__NUMERIC_ 特殊变量。我会在聊天室里闲逛一会儿,以防你想多说。
    • +1 比我的回答要好,因为您可以请求其他单变量统计数据,例如平均值、标准差等。不过应该不会这么难...
    【解决方案2】:

    如果您只是在 min / med / max 之后,那么以下内容将起作用(这样您就不必命名变量):-

    ods output quantiles = quantiles;
    proc univariate data = sashelp.cars;
      var _numeric_;
    proc sort;
      by varname;
    run;
    
    proc transpose data = quantiles out = quan_tran (drop=_name_ rename=(_100__max = max _50__median = median _0__min = min));
      by varname;
      var estimate;
      id quantile;
      where quantile in: ('100', '50', '0');
    run;
    

    如果您想要其他类型的度量 - mean、std 等 - proc 单变量将它们输出到单独的数据集中,这意味着您将拥有合并表等 - 它再次变得很痛苦。

    SAS 的输出数据集可能真的很糟糕,proc 方法对我来说是最令人震惊的例子。

    【讨论】:

    • 我同意。我发现它的另一种工作方式是先转置数据,以便变量名在一列中。按变量名排序,然后使用MEANS procedure中的by语句。
    • 也同意 SAS 输出数据集。 +1 展示了一个使用 ODS 以编程方式存储数据的好例子。
    【解决方案3】:

    为什么不在 mean 语句中使用 stackods 选项?

    ods listing close;
    ods output summary=s;
    proc means data=mydata stackods min median max;
    run;
    ods output close;
    ods listing;
    proc print;
    run;
    

    【讨论】:

    • OP 早已不复存在,但这可能是这里最好的解决方案。
    【解决方案4】:

    更新

    这是一个基于宏的解决方案,添加了新的分步 cmets。它使用来自 SAS dictionary.columns 的元数据来发现数据集中的所有数值变量。基本上,我采用所有数值变量的MINMEDIANMAX,在三个单独的数据集中输出结果。然后我连接数据集,使用IN 变量来确定每一行的来源,从而用适当的统计名称对其进行标记。然后输出是三行和n 列。

    正如 OP 在他的回答中所展示的,获取数字变量的整个宏/元数据都可以通过简单地使用特殊的 _NUMERIC_ 变量来替换。如果有人有兴趣将其用于其他事情,我将保留当前的方法。

    此外,OP 的答案是一种无宏解决方案,它使用PROC TRANSPOSE 到达与此相同的位置,而无需任何单独的结果集的串联。我敦促所有读者审阅它,因为它更像“SAS”。

    %GLOBAL 
        var_names 
        dsn_temp_min
        dsn_temp_median
        dsn_temp_max
    ; 
    %LET dsn_temp_min = min_summary ;
    %LET dsn_temp_median= med_summary;
    %LET dsn_temp_max= max_summary;
    
    /* Identify dataset */
    %LET lib_name = WORK ;  /* change to your library */
    %LET dsn = my_data ;
    
    /* Retrieve numeric variable names from SAS metadata and store in `var_name` */
    /* macro variable. Library and dataset name must be upper-case since that is */
    /* how they are stored in `dictionary.columns`. */
    /* UPDATE: this all can be avoided by just using the _NUMERIC_ special variable */
    /* but I am leaving this in here in case anyone is interested in querying */
    /* meta-data for other purposes. */
    
    %LET lib_name = %UPCASE (&lib_name);
    %LET dsn = %UPCASE (&dsn);
    
    PROC SQL NOPRINT;
        SELECT name
        INTO :var_names SEPARATED BY ' '
        FROM dictionary.columns
        WHERE libname = "&lib_name"
        AND memname = "&dsn"
        AND type ^= "char"
    ;
    QUIT;
    RUN;
    
    /* Take the MIN of all numeric variables and store in a separate dataset */
    PROC MEANS DATA = &lib_name..&dsn NOPRINT ;
        OUTPUT OUT=&dsn_temp_min (DROP = _TYPE_ _FREQ_)
            MIN (&var_names) = 
        ;
    RUN;
    
    /* Take the MEDIAN of all numeric variables and store in a separate dataset */    
    PROC MEANS DATA = &lib_name..&dsn NOPRINT ;
        OUTPUT OUT=&dsn_temp_median (DROP = _TYPE_ _FREQ_)
            MEDIAN (&var_names) = 
        ;
    RUN;
    
    /* Take the MAX of all numeric variables and store in a separate dataset */        
    PROC MEANS DATA = &lib_name..&dsn NOPRINT ;
        OUTPUT OUT=&dsn_temp_max (DROP = _TYPE_ _FREQ_)
            MAX (&var_names) = 
        ;
    RUN;
    
    
    /* Concatenate the three separate datasets into one.  Use IN to figure out */
    /* where each row is coming from, and label appropriately */
    DATA summary_data;
        LENGTH stat $6 ;
    
        RETAIN
            stat &var_names
        ;
    
        SET 
            &dsn_temp_min (IN=s1)
            &dsn_temp_median (IN=s2)
            &dsn_temp_max (IN=s3)
        ;
    
        IF (s1) THEN DO;
            stat = "MIN" ;
        END;
        ELSE IF (s2) THEN DO;
            stat = "MEDIAN" ;
        END;
        ELSE IF (s3) THEN DO;
            stat = "MAX" ;
        END;
    
        LABEL stat = "Statistic";
    RUN;
    

    【讨论】:

    • 有道理。我一直在寻找不使用var 语句的解决方案。我第一次尝试的列表输出确实打印了我想要的内容,但只会将第一行输出到我的数据集,这似乎很奇怪。第二个......谁知道为什么 SAS 将数据全部输出到一行中。
    • 首先,由于您没有var,SAS 会在OUTPUT 语句中查找要指定的分析变量,例如OUTPUT . . . MIN (var_1 var_2 ....) =。没有发现,它只是默认为第一个变量。我不太确定第二个,因为我不经常使用 ODS 来选择输出片段,但我猜 ODS Summary 元素是这样格式化的。
    • 我刚刚通过查看您的代码意识到如果我这样做:proc means data=my_data min median max; output out=summary_data; run; 删除 min=min median=median max=max 然后它会按我的预期工作。
    • 我的代码和你的代码都不输出中位数。我可能会卡在我的一行输出中,并使用proc transpose 将输出放入更用户友好的表格中。
    • 您正在寻找的格式 - 变量是 3 行(MIN、MEDIAN、MAX)和n 列吗?或者它是 n x 3 列的唯一名称的一行?
    猜你喜欢
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 2013-04-24
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多