Jedi SAS Tricks: FUNC(y) Formats

In the previous episode, we built our own custom SAS function - a masterful trick indeed. Gordon Keener, a developer here at SAS, responded exuberantly "You think that's cool? - try THIS!" and proceeded to demonstrate prodigious powers with the SAS by using a custom function in a custom informat to elegantly resolve a programming problem. And another episode of Jedi SAS Tricks was launched...

First, if you haven't experienced the joy of bringing order to chaotic data using your own custom formats and informats, an excellent place to start is with Jonas Bilenas' SGF paper titled "I Can Do That With PROC FORMAT". But Gordon was talking about a new (SAS9.3) capability - the ability create a custom format that performs a function on a value. And because we know how to build our own user-defined functions with PROC FCMP, can't we build a custom format leveraging a custom function? Yes, we can! So let's dive in. If you want to click along, download the code here and fire up your SAS session. Just FYI, the code includes segments we don't discuss here (like producing the data sets, etc.)

The problem:
Our data is read in from a raw text file. US data has temperatures recorded in °F, World data in °C. How can we compare these values? After reading it in, the original SAS data looks like this:
Listing of the two original data sets

First, we'll build custom functions to convert °F to °C and °C to °F:

proc fcmp outlib=sasuser.MyFunc.MyPack;
function c2f(Tc);
   return(((Tc*9)/5)+32);
endsub;
function f2c(Tf);
   return((5/9)*(Tf-32));
endsub;
run;

Next, we could use these functions to "enrich" the data, adding a temp_c variable to the US data and a temp_f variable to the World data:

options cmplib=sasuser.Myfunc;
data us_both;
   set us;
   Temp_c=f2c(temp_f);
run;
 
data world_both;
   set world;
   Temp_F=c2f(temp_c);
run;

Results:
Listing of the two modified data sets

But - wouldn't it be cool to just print our °F temperatures in °C without having to modify the data? For that, let's write a custom format using our temperature conversion functions and use it in PROC PRINT:

proc format;
  value   c2f (default=5) other=[c2f()]; 
  value   f2c (default=5) other=[f2c()]; 
run;
title 'Printing with Formats';
proc print data=us label noobs;
  label temp_f='Temp (°C)';
  format temp_f f2c5.1;
run;

Results:
Listing of the US data set with the Farenheit temperature column formatted to display as Celsius

Even more intriguing, as Gordon originally suggested, we could build custom informats based on our temperature conversion functions and use them to read the temperature data from the raw data file directly into the units we desired. We could have read the Fahrenheit data in as Celsius or vice-versa, right from the start. For example:

data US_F_and_C;
   input @1 Place $14. @19 Date date7. @15 Temp_f @15 Temp_c f2c3.;
   format date date9.;
   datalines;
Alaska        -80 23jan71
Colorado      -60 01jan79
Idaho         -60 18jan43
North Dakota  -60 15feb36
Wyoming       -63 09feb33
;
run;
 
data World_F_and_C;
   input @1 Place $14. @15 Date date7. @23 Temp_f c2f3. @23 Temp_c ;
   format date date9.;
   datalines;
Antarctica    21jul83 -89
Siberia       06feb33 -68
Greenland     09jan54 -66
Yukon         03feb47 -63
Alaska        23jan71 -67
;
run;

And the results:
Listing of the data sets produced by reading in the raw data using custom informats

And that's a wrap! Until next time, may the SAS be with you!
Mark

tags: custom, data step, programming, sas, SAS Jedi, tips and tricks

5 Comments

  1. Charu Shankar Charu Shankar
    Posted May 15, 2012 at 8:56 am | Permalink

    Informats are my personal favourite to read in unusual data! Love your example, well thought out & well done!

    • Mark Jordan Mark Jordan
      Posted May 15, 2012 at 9:35 am | Permalink

      Thanks! :-)

  2. Chris
    Posted May 21, 2012 at 1:38 am | Permalink

    Anywhere this square-bracket syntax is documented?

    • Mark Jordan Mark Jordan
      Posted May 21, 2012 at 12:11 pm | Permalink

      Sure - check out the PROC FORMAT documentation for the VALUE statement under the topic "value-range-set(s)". It's specified in the "existing-format" section.
      Regards,
      Mark

  3. Posted May 27, 2013 at 7:14 pm | Permalink

    hanks for the plug. Check out my SAS Press book, "The Power of PROC FORMAT" for more FORMAT/INFORMAT tricks. Maybe it is time for a new edition to include PROC FCMP.

One Trackback

  1. By Homepage on November 9, 2012 at 8:00 pm

    ... [Trackback]...

    [...] Read More: blogs.sas.com/content/sastraining/2012/05/10/jedi-sas-tricks-funcy-formats/ [...]...

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>