Extending IML - Defining a Function Module

The SAS/IML run-time library contains hundreds of functions and subroutines that you can call to perform statistical analysis. There are also many functions in Base SAS software that you can call from SAS/IML programs. However, one day you might need to compute some quantity for which there is no prewritten function.

Fortunately, the SAS/IML language enables you to define modules.

A module is a user-defined function or subroutine that you can call from an IML program. A module that returns a value is called a function module; a module that does not return a value is called a subroutine module. A subroutine module usually modifies one or more matrices that are passed in as arguments. You can call a subroutine module by using the CALL or RUN statement.

This post gives an example of defining a function module. A module enables you to encapsulate, reuse, and maintain related SAS/IML statements in a convenient way. You can pass matrices from your program into the module to provide input data and to control the way that the module behaves.

You define a module by using the START and FINISH statements. The START statement defines the name of the module and the arguments. You can use the RETURN statement to return a value from a function module.

For example, suppose you want to compute sample quantiles for a vector of values. You know that the UNIVARIATE procedure calculates sample quantiles, so you look up how to compute quantiles in the UNIVARIATE documentation. Several definitions are listed, but the default method for PROC UNIVARIATE is Definition #5. The following module definition is taken from the book Statistical Programming with SAS/IML Software:

proc iml;
/** Qntl: compute quantiles (Defn. 5 from the UNIVARIATE doc) **/
/** Arguments:
   q   upon return, q contains the specified sample quantiles of
       the data.
   x   is a matrix. The module computes quantiles for each column.
   p   specifies the quantiles. For example, 0.5 specifies the
       median, whereas {0.25 0.75} specifies the first and
       third quartiles.
   This module does not handle missing values in the data.  **/
start Qntl(q, x, p);       /** definition 5 from UNIVARIATE doc **/
   n = nrow(x);            /** assume nonmissing data **/
   q = j(ncol(p), ncol(x));/** allocate space for return values **/
   do j = 1 to ncol(x);    /** for each column of x... **/
      y = x[,j];
      call sort(y,1);      /** sort the values **/
      do i = 1 to ncol(p); /** for each quantile **/
         k = n*p[i];       /** find position in ordered data **/
         k1 = int(k);      /** find indices into ordered data **/
         k2 = k1 + 1;
         g = k - k1;
         if g>0 then
            q[i,j] = y[k2];/** return a data value **/
         else              /** average adjacent data **/
            q[i,j] = (y[k1]+y[k2])/2;
      end;
   end;
finish;

After the module is defined, you can call it from your program. For example, the following statements compute the 50th, 90th, and 95th percentile of a vector of values sampled from the standard normal distribution:

x = j(1000, 1);           /** allocate 1000 rows and 1 column **/
call randseed(4321);      /** set the random number seed **/
call randgen(x, "Normal");/** random sample from standard normal **/
p = {0.5 0.9 0.95};       /** specifies quantiles **/
call qntl(q, x, p);       /** call module to compute sample quantiles **/
print q[rowname=(char(p))];

For comparison, you can use the QUANTILE function in Base SAS software to compute the quantiles of the standard normal distribution:

/** quantiles of standard normal distribution **/
qDistrib = quantile("Normal", p); 
print qDistrib[format=6.3];

Because the data were sampled from a normal distribution, there is close agreement between the quantiles of the sample data (as computed by the QNTL module) and the quantiles of the standard normal distribution (as computed by the QUANTILE function).

Editor's Note: The QNTL function was included in SAS/IML 9.22 as built-in subroutine.

tags: Getting Started, Statistical Programming

4 Comments

  1. Robert Pearson
    Posted July 26, 2011 at 12:47 pm | Permalink

    Will you give me some feedback on a related module I made? I needed to obtain percentiles of each column. The code below is what I came up with. Do you have any suggestions/improvements? Thanks,

    start colPctls(k, x);
    p = ncol(x);
    n = nrow(x);
    prob = k/100;
    j = INT(n*prob);
    g = n*prob - j;

    out = j(p,1);
    DO i=1 TO p;
    CALL SORTNDX(ndx, x[,i], 1);
    IF g=0 THEN
    out[i] = (x[ndx[j], i] + x[ndx[j+1], i]) / 2;
    ELSE
    out[i] = x[ndx[j+1], i];
    END;

    RETURN(out);
    finish;

  2. Rick Wicklin
    Posted July 26, 2011 at 1:02 pm | Permalink

    Percentiles and quantiles are essentially the same thing, except that percentiles are measured on [0,100], and quantiles are measured on [0,1]. The 5th percentile is the 0.05 quantile, the 10th percentile is the 0.10 quantile, and so on. So just take your percentiles, divide then by 100, and then call the QNTL module like this:
    pctl = {50 90 95};
    call qntl(q, x, pctl/100);

  3. Rubel
    Posted September 12, 2012 at 3:29 am | Permalink

    Hi, I am having trouble with the sas/iml subroutine module. here is my code:

    proc iml;
    start corrp(a,b,c,d);
    i= {1 2 3 4};
    if p=i[1,a] & q=i[1,b] & s=i[1,c] & t=i[1,d] then

    A=(y[p,q]-y[p,t]*y[q,t])/sqrt((1-y[p,t]*y[p,t])*(1-y[q,t]*y[q,t]));
    B=(y[p,s]-y[p,t]*y[s,t])/sqrt((1-y[p,t]*y[p,t])*(1-y[s,t]*y[s,t]));
    C=(y[q,s]-y[q,t]*y[s,t])/sqrt((1-y[q,t]*y[q,t])*(1-y[s,t]*y[s,t]));
    rho=(A-B*C)/sqrt((1-B*B)*(1-C*C));

    finish;

    y={1 0.73456 0.71075 0.70398,0.73456 1.00000 0.69316 0.70855, 0.71075 0.69316 1.00000 0.83925, 0.70398 0.70855 0.83925 1.00000};
    a=3;
    b=4;
    c=1;
    d=2;
    call corrp(3,4,1,2);
    print rho;

    my function is corrp(a,b,c,d), and I am trying to call the function with inputvalues a=3;b=4;c=1;d=2; however I keep getting the error message "Matrix has not been set to a value"

    Any feedback would be highly appreciated. Thanks in advance!

16 Trackbacks

  1. By A Simple Signum Function - The DO Loop on August 12, 2011 at 6:02 am

    [...] wrote a SAS/IML module that contains a compact little expression: proc iml; start sgn(x); return( (x>=0) - (x<=0) [...]

  2. [...] "julday8.")); The DAYOFYEAR variable contains values 1–366. I can use the QNTL subroutine to find dates q1 and q2 such that "over 97% of tropical activity" occurs between q1 and q2. I’m [...]

  3. By The module that vanished - The DO Loop on August 21, 2011 at 11:22 am

    [...] was quite proud of myself because I had written a single function module that handles both numeric and character matrices. The beauty of the module, I thought, was that it [...]

  4. [...] If you use tridiagonal matrices often, you can encapsulate these statements into a SAS/IML module. [...]

  5. [...] a DO loop and compute each value within the loop. For example, the following SAS/IML statements define a SAS/IML module and call it eight times within a DO loop: proc iml; start Func(x); /** compute any quantity **/ [...]

  6. By Storing and loading modules - The DO Loop on September 12, 2011 at 5:40 am

    [...] can extend the capability of the SAS/IML language by writing modules. A module is a user-defined function. You can define a module by using the START and FINISH [...]

  7. [...] language. Prior to SAS/IML 9.22 (released in 2010) statistical programmers could call a SAS/IML module that computes sample quantiles. With the release of SAS/IML 9.22, there is now a built-in QNTL call for computing sample [...]

  8. By Row vectors versus column vectors - The DO Loop on March 19, 2012 at 5:24 am

    [...] vectors. This is useful for performing linear algebra, but it can cause headaches when you are writing a SAS/IML module. I want my modules to be able to handle both row vectors and column vectors. I don't want the user [...]

  9. [...] p. 69 of my book, Statistical Programming with SAS/IML Software. The following statements define a SAS/IML module named AsFactor. The third argument is the input argument, x. Upon return, the first argument [...]

  10. [...] Modules are used to extend the capability of the SAS/IML language. Usually you need to explicitly load modules before you use them, but there are two cases where PROC IML loads a module automatically [...]

  11. [...] In the SAS/IML language, a user-defined function or subroutine is called a module. Modules are used to extend the capability of the SAS/IML language. [...]

  12. By Oh, those pesky temporary variables! - The DO Loop on January 30, 2013 at 12:42 pm

    [...] pass parameters to functions and subroutines. This enables you to overwrite a parameter inside of a user-defined module. For example, the following subroutine doubles the values of all elements in the matrix passed into [...]

  13. [...] of the features of the SAS/IML language is that you can create your own user-defined functions or subroutines that extend the capabilities of SAS. For brevity, this article discusses functions, but the same ideas apply to user-defined [...]

  14. [...] are many special-purpose products that are not covered in this short article, but remember that you can always define your own SAS/IML function that compute any conceivable product. For example, in physics classes students use the "cross [...]

  15. [...] the SAS/IML language, it is easy to write user-defined functions (called modules) that extend the functionality of the language. If you need a function that safely takes the natural [...]

  16. [...] techniques that make your SAS/IML functions accessible to others. As background, remember that you can define new functions and subroutines in the SAS/IML language, and that these functions are generically called modules. You can use the STORE statement to store [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <p> <pre lang="" line="" escaped=""> <q cite=""> <strike> <strong>