将值与变量的最大值进行比较

时间:2018-02-01 10:41:13

标签: sas

我有一个包含很多行的数据集,我正在研究一组变量。

对于每一行和每个变量,我想知道该值是否等于此变量的最大值或大于或等于10.

预期输出(输入为所有变量而不是_B):
(您可以根据需要将T/FTRUE/FALSE替换为1/0

+----+------+--------+------+--------+------+--------+
| ID | Var1 | Var1_B | Var2 | Var2_B | Var3 | Var3_B |
+----+------+--------+------+--------+------+--------+
| A  | 1    | F      | 5    | F      | 15   | T      |
| B  | 1    | F      | 5    | F      | 7    | F      |
| C  | 2    | T      | 5    | F      | 15   | T      |
| D  | 2    | T      | 6    | T      | 10   | T      |
+----+------+--------+------+--------+------+--------+

请注意,对于Var3,最高为15,但自15>=10起,任何值>=10都将计为TRUE

这是我到目前为止所做的事情(怀疑它会有任何帮助,但仍然):

%macro pleaseWorkLittleMacro(table, var, suffix);
    proc means NOPRINT data=&table;
        var &var; 
        output out=Varmax(drop=_TYPE_ _FREQ_) max=;
    run;

    proc transpose data=Varmax out=Varmax(rename=(COL1=varmax));
    run;

    data Varmax;
        set Varmax;
        varmax = ifn(varmax<10, varmax, 10);
    run; /* this outputs the max for every column, but how to use it afterward ? */
%mend;

%pleaseWorkLittleMacro(MY_TABLE, VAR1 VAR2 VAR3 VAR4, _B);

我在R中有代码,就像魅力一样,但我真的要把它翻译成SAS:

#in a for loop over variable names, db is my data.frame, x is the 
#current variable name and x2 is the new variable name
x.max = max(db[[x]], na.rm=T)
x.max = ifelse(x.max<10, x.max, 10)
db[[x2]] = (db[[x]] >= x.max) %>% mean(na.rm=T) %>% percent(2)

4 个答案:

答案 0 :(得分:2)

旧学校解决方案是在一个数据步骤中读取数据两次;

data expect ;
 input ID $ Var1 Var1_B $ Var2 Var2_B $ Var3 Var3_B $ ;
cards;
A 1 F 5 F 15 T
B 1 F 5 F  7 F
C 2 T 5 F 15 T
D 2 T 6 T 10 T 
;
run;

data my_input;
    set expect;
    keep ID Var1 Var2 Var3 ;
proc print;
run;

将代码中最易变的东西声明为宏变量是个好习惯。;

%let varList = Var1 Var2 Var3;
%let markList = Var1_B Var2_B Var3_B;
%let varCount = 3;

两次读取数据;

data my_result;
    set my_input (in=maximizing)
        my_input (in=marking);

Decklare和Initialize数组;

     format &markList $1.;
    array _vars [&&varCount] &varList;
    array _maxs [&&varCount] _temporary_;
    array _B [&&varCount] &markList;
    if _N_ eq 1 then do _varNr = 1 to &varCount;
        _maxs(_varNr) = -1E15;
    end;

第一次阅读时,计算最大值;

    if maximizing then do _varNr = 1 to &varCount;
        if _vars(_varNr) gt _maxs(_varNr) then _maxs(_varNr) = _vars(_varNr);
    end;

第二次阅读时,标记为&amp; maxMarks maxima ;

   if marking then do _varNr = 1 to &varCount;
        if _vars(_varNr) eq _maxs(_varNr) or _vars(_varNr) ge 10
            then _B(_varNr) = 'T';
            else _B(_varNr) = 'F';
   end;

删除以下划线开头的所有变量,即所有工作变量;

    drop _:;

仅在第二次阅读时保留结果;

    if marking;
run;

检查结果;

proc print;
    var  ID Var1 Var1_B Var2 Var2_B Var3 Var3_B; 
proc compare base=expect compare=my_result;
run;

答案 1 :(得分:0)

这在sql

中很容易解决
proc sql;
    create table my_result as 
        select *
             , Var1_B = (Var1 eq max_Var1)
             , Var1_B = (Var2 eq max_Var2)
             , Var1_B = (Var3 eq max_Var3)
        from my_input
           , (select max(Var1) as max_Var1
                   , max(Var2) as max_Var2
                   , max(Var3) as max_Var3)
    ;
quit;

(未经测试,因为我们的SAS服务器当前已关闭,这就是我在Stack Overflow上花费时间的原因)

如果您需要更多变量,请参阅SAS的系统视图VCOLUMN

proc sql;
    select ''|| name ||'_B = ('|| name ||' eq max_'|| name ||')'
         , 'max('|| name ||') as max_'|| name
    from sasHelp.vcolumn
    where libName eq 'WORK'
      and memName eq 'MY_RESULT' 
      and type eq 'num'
      and upcase(name) like 'VAR%'
    ;
    into : create_B   separated by ', '
       , : select_max separated by ', '
    create table my_result as 
        select *, &create_B
             , Var1_B = (Var1 eq max_Var1)
             , Var1_B = (Var2 eq max_Var2)
             , Var1_B = (Var3 eq max_Var3)
        from my_input
           , (select max(Var1) as max_Var1
                   , max(Var2) as max_Var2
                   , max(Var3) as max_Var3)
    ;
quit;

(再次未经测试)

答案 2 :(得分:0)

Proc MEANS计算每列的最大值后,您可以运行将原始数据与最大值组合在一起的数据步骤。

data want;
length 
 ID $1 Var1 8 Var1_B $1. Var2 8 Var2_B $1. Var3 8 Var3_B $1. var4 8 var4_B $1;
input 
 ID  Var1  Var1_B  Var2  Var2_B  Var3  Var3_B ; datalines;
 A    1     F       5     F       15    T      
 B    1     F       5     F       7     F      
 C    2     T       5     F       15    T      
 D    2     T       6     T       10    T      
run;

data have;
  set want;
  drop var1_b var2_b var3_b var4_b;
run;

proc means NOPRINT data=have;
    var var1-var4; 
    output out=Varmax(drop=_TYPE_ _FREQ_) max= / autoname;
run;

VAR语句的巧妙之处在于您可以轻松列出带数字后缀的变量名称。 autoname选项会自动将_附加到输出中的变量名称。

现在将maxes与原始(has)结合起来。 set varmax自动保留* _max变量,并且它们不会被原始数据中的值覆盖,因为varmax变量名称不同。

数组用于迭代值并应用标记行的业务逻辑,最大值或大于10。

data want;
  if _n_ = 1 then set varmax; * read maxes once from MEANS output;
  set have;
  array values var1-var4;
  array maxes  var1_max var2_max var3_max var4_max;
  array flags $1 var1_b var2_b var3_b var4_b;
  do i = 1 to dim(values); drop i;
    flags(i) = ifc(min(10,maxes(i)) <= values(i),'T','F');
  end;
run;

上面的困难部分是MEANS输出创建了无法使用var1 - varN语法列出的变量。

当您调整命名约定以使所有概念上分组的变量名以数字后缀结尾时,代码更简单。

* number suffixed variable names;

* no autoname, group rename on output;
proc means NOPRINT data=have;
    var var1-var4; 
    output out=Varmax(drop=_TYPE_ _FREQ_ rename=var1-var4=max_var1-max_var4) max=  ;
run;

* all arrays simpler and use var1-varN;

data want;
  if _n_ = 1 then set varmax;
  set have;
  array values var1-var4;
  array maxes  max_var1-max_var4;
  array flags $1 flag_var1-flag_var4;
  do i = 1 to dim(values); drop i;
    flags(i) = ifc(min(10,maxes(i)) <= values(i),'T','F');
  end;
run;

答案 3 :(得分:0)

您可以使用宏代码或数组,但可能更容易将数据转换为高变量/值结构。

因此,让我们将您的测试数据输入为实际的SAS数据集。

data expect ;
 input ID $ Var1 Var1_B $ Var2 Var2_B $ Var3 Var3_B $ ;
cards;
A 1 F 5 F 15 T
B 1 F 5 F  7 F
C 2 T 5 F 15 T
D 2 T 6 T 10 T
;

首先,您可以使用PROC TRANSPOSE来制作高大的结构。

proc transpose data=expect out=tall ;
  by id ;
  var var1-var3 ;
run;

现在,您的规则很容易在PROC SQL步骤中应用。您可以通过在原始变量的名称后附加后缀来为该标志变量派生新名称。

proc sql ;
 create table want_tall as
   select id 
        , cats(_name_,'_Flag') as new_name 
        , case when col1 >= min(max(col1),10) then 'T' else 'F' end as value
   from tall
   group by 2
   order by 1,2
 ;
quit;

然后将其翻转回水平并与原始数据合并。

proc transpose data=want_tall out=flags (drop=_name_);
  by id;
  id new_name ;
  var value ;
run;

data want ;
  merge expect flags;
  by id;
run;

enter image description here

相关问题