As the first step in the decommissioning of sasCommunity.org the site has been converted to read-only mode.


Here are some tips for How to share your SAS knowledge with your professional network.


Create an Informat from a User-Defined Function

From sasCommunity
Jump to: navigation, search

Say you have raw data that contains numbers that are sometimes expressed as fractions. Your task is to convert these fractions (e.g. 5 1/2) into a decimal form that can be used as a numeric variable in a SAS data set (e.g 5.5). Since there are no SAS-supplied INFORMATS that will read fractions, you might resort to reading the fraction as a character variable, then use one or more data step statements to determine the value of the fraction.

data x; 
input x & : $8. @@; 
y = sum( input(scan(x,1),best.) , input(scan(x,2),best.) / input(scan(x,3),best.));
datalines; 
5 1/2   8   100 1/4   99   18 2/7
; 
run;

Data set X looks as follows ...

x             y
5 1/2        5.500
8            8.000
100 1/4    100.250
99          99.000
18 2/7      18.286

As of version 9.3, you can create user-written INFORMATS that will perform some of the tasks normally reserved for data steps. The first step in the process is using PROC FCMP to create a function. Once that function is created, you use PROC FORMAT to create an INFORMAT that uses the function when reading your data. The following shows how to take the data step statements used above and create a function named FRACT that will read fractions and make them usable as numeric variables.

* create a FUNCTION named FRACT in the work library;
proc fcmp outlib=work.functions.math; 
function fract(x $); 
return( sum( input(scan(x,1),best.) , input(scan(x,2),best.) / input(scan(x,3),best.) ));
endsub; 
run; 
quit; 
 
options cmplib=work.functions; 
 
* create an INFORMAT from the FUNCTION;
proc format; 
invalue fract other=[fract()]; 
run; 
 
* try the INFORMAT;
data x; 
input x : & fract. @@; 
put x= @@;
datalines; 
5 1/2   8   100 1/4   99   18 2/7
; 
run; 
 
in the LOG ...
 
x=5.5 x=8 x=100.25 x=99 x=18.285714286

Admittedly, this is more SAS code than is used in the first data step. However, if you have encounter fractions in raw data on a regular basis, it would be useful to have the INFORMAT stored in a format library. Since the INFORMAT FRAC calls a user-defined function, you would also have the function FRAC() stored in a library, for example ...

options cmplib=z.functions; 
 
data x; 
input x : & fract. @@; 
datalines; 
5 1/2   8   100 1/4   99   18 2/7
; 
run;

The following uses the information from SAS documentation on Creating a Function to Use as a Format to create INFORMATS for temperature conversion (and shows you the one temperature that is the same in both Fahrenheit and Centigrade, -40).

proc fcmp outlib=work.functions.temps;
function ctof(c) $;
 return(cats(((9*c)/5)+32));
endsub;
 
function ftoc(f) $;
 return(cats((f-32)*5/9));
endsub;
run;
 
options cmplib=work.functions; 
 
proc format;
invalue ctof other=[ctof()];
invalue ftoc other=[ftoc()];
 run;
 
data f_to_c;
input temp : ftoc. @@ ;
put temp= @@;
datalines;
-40 32 212
;
run;
 
data c_to_f;
input temp : ctof. @@ ;
put temp= @@;
datalines;
-40 0 100
;
run; 
 
LOG of f_to_c ...
temp=-40 temp=0 temp=100
 
LOG of c_to_f ...
temp=-40 temp=32 temp=212

The most difficult part of the this process is understanding step number one ... using PROC FCMP. In addition to the SAS documentation, there are a numerous papers that you can read, for example: User Written Data Step Functions; The new SAS 9.2 FCMP Procedure, what functions are in your future?.

If you have any questions about this posting, you are welcome to send me a note by clicking here ... email Mike. To see my other SAS Community postings, click here.