Sarah Reinke
Sarah Reinke

Reputation: 57

SAS find non-zero minimum in row

Does anybody know how to find the non-zero minimum in a row using the min function in SAS? Or any other option in SAS code?

Current code:

PIP_factor = `min(PIPAllAutos, PIPNotCovByWC, PIPCovByWC, PIPNotPrincOpByEmpls);

Upvotes: 2

Views: 5563

Answers (4)

Phill
Phill

Reputation: 545

/* For each row, find the variable name corresponding to the minimum value */
proc iml;
use DATASET; /* DATASET is your dataset name of interest */
read all var _NUM_ into X[colname=VarNames]; /* read in only numerical columns */
close DATASET;

idxMin = X[, >:<];         /* find columns for min of each row */
varMin = varNames[idxMin]; /* corresponding var names */
print idxMin varMin;

For Max:

idxMax = X[, <:>]; 

I wasn't familiar with the operator above, SAS provides a helpful table for IML operators:

IML Operators

In PROC IML you can also create new datasets/append the results to your old one if you need them later on.

Full blog post: source, all credit goes to Rick Wicklin at SAS

edit: For the non-zero part, I would just do a PROC SQL using a WHERE variable is not 0 to filter before feeding it in the PROC IML. I am sure it can be done within PROC IML, but I just started using it myself. So, please comment if you know a way around it in PROC IML and I will include the fix.

Upvotes: 0

uzbad
uzbad

Reputation: 124

This one doesn't suffer from 9999 limitation of the approved answer.

%macro minnonzero/parmbuff;
  %local _argn _args _arg;
  /* get rid of external parenthesis */
  %let _args=%substr(%bquote(&syspbuff),2,%length(%bquote(&syspbuff))-2);
  %let _argn=1;
  min(
  %do %while (%length(%scan(%bquote(&_args),&_argn,%str(|))) ne 0);
    %let _arg=%scan(%bquote(&_args),&_argn,%str(|));
    %if &_argn>1 %then %do;
      ,
    %end;
    ifn(&_arg=0,.,&_arg)
    %let _argn=%eval(&_argn+1);
  %end;
  );
%mend;

You call it with pipe-separated list of arguments, e.g.

data piesek;
  a=3;
  b="kotek";
  c=%minnonzero(a|findc(b,"z");
  put c; /* 3, "kotek" has no "z" in it, so findc returns 0 */
run;

Upvotes: 0

BellevueBob
BellevueBob

Reputation: 9618

Here is another way, using the IFN function:

data null_;

   PIPAllAutos = 2;
   PIPNotCovByWC = .;
   PIPCovByWC = 0;
   PIPNotPrincOpByEmpls = 1;

   PIP_factor = min(ifn(PIPAllAutos=0,          . ,PIPAllAutos)
                  , ifn(PIPNotCovByWC=0,        . ,PIPNotCovByWC)
                  , ifn(PIPCovByWC=0,           . ,PIPCovByWC)
                  , ifn(PIPNotPrincOpByEmpls=0, . ,PIPNotPrincOpByEmpls)
                );
   put PIP_factor=;
run;

Note the min function ignores missing values; the ifn function sets zero values to missing.

Might be more typing than it's worth; offered only as an alternative. There are many ways to skin the cat.

Upvotes: 1

Joe
Joe

Reputation: 63424

I think you need to use an array solution, ie

array pipArray pip:; *or whatever;
PIP_factor=9999;
do _n = 1 to dim(pipArray);
  if pipArray[_n] > 0 then 
   PIP_factor = min(PIP_factor,pipArray[_n]);
end;

Or somesuch.

Upvotes: 2

Related Questions