SAS for the sassy and not so sassy

The Statistical Analysis System SAS is a very powerful for data analysis, though rather awkward to program.  It requires you to shape your problem to the way SAS does things and is not nearly as flexible as other programming languages.  Good beginning references are:

"The Little SAS Book" by Lora Delwiche and Susan Slaughter, SAS Institute, ISBN 1-55544-215-3   ***Highly recommended***

"Quick Start to Data Analysis with SAS" by Frank DiIorio and Kenneth Hardy, Duxbury press ISBN 0-534-23760-6

"The Little SAS Book" gives a better introduction to manipulating data while the "Quick Start .. " spends more time analyzing data using SAS PROC commands.

SAS programs and data sets can be found in N:\SAScourse.  Feel free to experiment with these.

For online documentation log on to lan106.  Type ‘sas’ at the prompt which opens the SAS display manager, and choose the Help menu.
or point your browser to DOIT online documentation for SAS:  http://shelf.doit.wisc.edu/SASOnlineDocs/onldoc.htm

SAS web site:    www.sas.com


Basic programming rules (must be obeyed):

    Every SAS statement ends with a semicolon.

    Variable and data set names can be up to 32 characters in length

    Variable values can be numeric or character (up to 32768 characters)

    Names must start with a letter or an underscore ( _ ).

    Names can contain only letters, numerals and underscore.  No $#!@& etc.

    Always save programs and data files in "Unix" format (can use 'pc2unix' program).

 

Programming suggestions (strongly recommended):

    COMMENT, COMMENT, COMMENT  (* comments  ;  or /* comments ; */ )
     programmer's name, date written, any modifications, what the programs does, input data sets, output data sets, descriptions of  data
     steps throughout the program

    Name permanent SAS data sets so that they can be linked to the SAS program which created them
    (e.g.  SASPGM.INPUT created by program input.sas)

   Consistently upper or lower case - usually SAS commands in upper case.  Below, I've used upper case for SAS commands, lower case for
    variables and lower case with 'dat' appended for data sets.

    Continue on next line (as long as words are not split in two) - good for readability

    Although you can have many statements on same line best kept to one.

    Statements can start in any column - use indentation to separate parts of program

    creative use of:

    Lists of variable names: 
   numbered: chan1 chan2 ... chan128 can be written as chan1 - chan128
   (must be consecutive but can start and end anywhere)
   named:   y a c h r b,    y -- b   (depends on order of variables in SAS data set)

     SAS special name lists:  _ALL_,   _CHARACTER_,  _NUMERIC_
            for example MEAN(OF _NUMERIC_);   PUT _CHARACTER_;


SAS data sets

    The basic work unit in SAS  is a DATA set consisting of variables and observations - much like a spreadsheet with variables arranged by columns and observations of these variables by rows.  There are two types of variables Numeric and Character.

                              Variables

ID NAME HEIGHT WEIGHT
1 53 Susan 42 41
2 54 Charlie 46 55
3 55 Calvin 40 35
4 56 Lucy 46 52
5 57 Dennis 44 .
6 58   43 50

Missing character data is represented by blanks and missing numeric data by period (.).


Simple SAS program

SAS programs consist of two parts: DATA steps and PROC steps.

Let's multiply 24 times 3 in SAS.  Even for this trivial task it is necessary to create a data set.  The following code was typed into TextPad and saved in Unix format in multiply.sas.  The program was run on lan104 by typing "sasb multiply.sas".

/* Simple program to multiply 24 times 3
    written by LG for SAS course 4/8/03 */
DATA multdat;
    num1 = 24;
    num2 = 3;
    prod12 = num1*num2;

PROC PRINT   DATA = multdat;
 

A log file is created, multiply.log, which contains notes, error messages, number of observations and variables, number of output pages in list (.lst) file:

1 The SAS System 11:11 Tuesday, April 8, 2003

NOTE: Copyright (c) 1999 by SAS Institute Inc., Cary, NC, USA.
NOTE: SAS (r) Proprietary Software Version 8 (TS M0)
Licensed to UNIVERSITY OF WISCONSIN, Site 0002176032.
NOTE: This session is executing on the SunOS 5.6 platform.

This message is contained in the SAS news file, and is presented upon
initialization. Edit the files "news" in the "misc/base" directory to
display site-specific news and information in the program log.
The command line option "-nonews" will prevent this display.

NOTE: SAS initialization used:
real time 0.17 seconds
cpu time 0.13 seconds

1 /* Simple program to multiply 24 times 3
2 written by LG for SAS course 4/8/03 */
3 DATA multiplydat;
4 num1 = 24;
5 num2 = 3;
6 prod12 = num1*num2;
7

NOTE: The data set WORK.MULTIPLYDAT has 1 observations and 3 variables.
NOTE: DATA statement used:
real time 0.03 seconds
cpu time 0.03 seconds


8 PROC PRINT DATA = multiplydat;
NOTE: There were 1 observations read from the dataset WORK.MULTIPLYDAT.
NOTE: The PROCEDURE PRINT printed page 1.
NOTE: PROCEDURE PRINT used:
real time 0.05 seconds
cpu time 0.05 seconds


NOTE: SAS Institute Inc., SAS Campus Drive, Cary, NC USA 27513-2414
NOTE: The SAS System used:
real time 0.27 seconds
cpu time 0.21 seconds

 

output written to multiply.lst shown below:

 The SAS System 11:11 Tuesday, April 8, 2003           1

Obs    num1    num2        prod12
1          24          3              72
 


Now multiply a series of numbers (multiply1.sas):

/* Simple program to multiply several sets of numbers
   and illustrate a numbered variable list
    written by LG for SAS course 4/8/03 */
DATA multiply1dat;
   INPUT num1 - num4;
   prod1234 = num1*num2*num3*num4;
   CARDS;
   24 3 7 13
   17 12 81 6
   38 18 2 5
   29 13 63 76
   ;

PROC PRINT DATA = multiply1dat;
 

output in multiply1.lst

 The SAS System 09:25 Tuesday, April 8, 2003 1

Obs    num1    num2    num3    num4    prod1234
1          24          3         7          13             6552
2          17        12       81            6           99144
3          38        18         2            5             6840
4          29        13       63          76       1805076
 


DATA step's built-in loop:

DATA steps execute line by line and observation by observation.

The data step includes a built-in loop which executes data step lines for each input observation:

The lines in the DATA step can contain most of the usual procedural programming constructs and commands such as:

ARRAY channel(128) ch1-ch128
Comparison operators: EQ (=), GT (>), LT (<), GE (>=), LE (<=), NE (~=), IN, NOTIN (~IN)
Logical operators: AND (&), OR ( | )
IF THEN ELSE
FOR I=1 TO 128;   DO; IF channel(I) LT 0 THEN channel(I) = .;   END;
logpwr = LOG(rawpwr);

See pages 70-71 of Little SAS Book for more complete list.


Getting data into SAS

CARDS; DATALINES;   As shown above these must be the last lines in the data statement with a semicolon following the last line of data.

INFILE '/dc/larry/SAScourse/test.txt'   DLM=',';
    If data is tab-delimited can use DLM='09'x   or  EXPANDTABS which replaces tab characters with spaces.
    For long lines you may need LRECL=500;
    To skip two lines use FIRSTOBS = 3;
    To stop at line ten use OBS = 10;
    If more than one observation per line use @@
    By default SAS goes to next line of input file if not all variables have been read. Use MISSOVER to prevent
        this and have SAS put missing values in unread variables for each line of input data.
    From TextPad always save SAS programs or data files in Unix format.

%wildcard(LOTSOFFILES, /dc/larry/SAScourse/test_*.txt);
INFILE LOTSOFFILES;
where LOTSOFFILES is a name given to represent all the files in the wildcard list.  SAS puts all the files together as though you had created one big file by pasting the individual files together in a text editor like TextPad

The SET statement is used to input existing SAS data sets:

DATA new-data-set;
    SET existing-data-set;


Temporary versus Permanent SAS data sets

For the simple multiplication program:

DATA multiplydat;
    num1 = 24;
    num2 = 3;
    product = num1*num2;

PROC PRINT DATA = multiplydat;
RUN;

SAS saves the data in a temporary file called WORK.multiplydat which exists only as long as SAS spends running this program.  In order to save this data in a permanent file you need to define a LIBNAME which can be done as follows:

LIBNAME sasbook 'c:\mysaslib'
DATA sasbook.multiplydat;
    num1 = 24;
    num2 = 3;
    product = num1*num2;

PROC PRINT DATA = sasbook.multiplydat;
 

where  sasbook is the name you have chosen for your permanent SAS data set and 'c:\mysaslib' is the directory for your SAS data library.  Note that you must give permanent SAS data sets a two part name consisting of the LIBNAME followed by a period then the data set name.   Generally, we do our work in a saspgm directory created in a study folder so that our command looks like:

LIBNAME saspgm '.';

Note that we are currently running SAS version 8.  If you have old version 6 permanent SAS data sets they must be in a separate folder:

LIBNAME saspgm '.';
LIBNAME saspgmv6 './sasv6dat';

PROC PRINT DATA = saspgm.input;

PROC PRINT DATA = saspgmv6dat.oldinput;


Juggling data sets with SAS

This simple example illustrates creating two permanent SAS data sets and using the SET statement to input them successively (concatenate)  into temporary data set for printing.   Fun Park data from page 120 "The Little SAS Book" .

Program entry.sas:

/* This program creates two permanent SAS data sets
and illustrates concatenating them using the SET statement
written by LG for SAS course 4/8/03 */

/* set up permanent data library folder as current directory*/
LIBNAME saspgm '.';

/* create South entry data set */
DATA saspgm.sentrydat;
    INPUT entrance $ passnum prtysize age;
   CARDS;
    S 43 3 27
    S 44 3 24
    S 45 3 2
    ;

/* create North entry data set */
DATA saspgm.nentrydat;
    INPUT entrance $ passnum prtysize age lot;
    CARDS;
    N 21 5 41 1
    N 87 4 33 3
    N 65 2 67 1
    N 66 2 7 1
    ;

/* combine data sets for printing */
DATA bothdat;
    SET saspgm.sentrydat saspgm.nentrydat;

PROC PRINT;
    TITLE 'Both files';
 

Output entry.lst:

                     Both files
Obs entrance passnum prtysize age lot
1           S          43           3      27   .
2           S          44           3      24   .
3           S          45           3        2   .
4           N         21           5      41   1
5           N         87           4      33   3
6           N         65           2      67   1
7           N         66           2        7   1

 


Now let's use some other SAS commands to output part of this data set.  The commands are:
KEEP = variable list                   tells SAS which variables to keep
DROP = variable list                  tells SAS which variables to drop
RENAME = (oldvar = newvar)  tells SAS to rename certain variables
FIRSTOBS = n                         tells SAS to start reading at observation n
OBS = n                                   tells SAS to stop reading at observation n

by replacing the last section of code shown above (entry1.sas):

Program entry1.sas:

/* program to subset the North and South entrance data
created by entry.sas. Written by LG for SAS course 4/8/03 */

LIBNAME saspgm '.';

/* combine data set with fewer variables and observations */
DATA nsentrydat (KEEP= entrance passnum prtysize);
    SET saspgm.sentrydat (FIRSTOBS = 2) saspgm.nentrydat (OBS= 3);

DATA subsetdat (RENAME=(entrance = entr passnum=pnum);
    SET nsentrydat;

PROC PRINT;
    TITLE 'Both files subset';

Output entry1.lst:

 Both files subset

Obs entr pnum prtysize
1       S      44       3
2       S      45       3
3      N      21       5
4      N      87       4
5      N      65       2

 


If we want to group observations by entrance for printing use the SAS BY command (entry2.sas):
 

Program entry2.sas:


/* program to print the North and South entrance data
created by entry.sas sorted BY entrance
Written by LG for SAS course 4/8/03 */

LIBNAME saspgm '.';

DATA bothdat;
    SET saspgm.sentrydat saspgm.nentrydat;

PROC SORT;
    BY entrance;

PROC PRINT;
    BY entrance;
    TITLE 'Both files subset printed by entrance';
 

Output entry2.lst:


 Both files subset printed by entrance

------------------ entrance=N ------------------

Obs passnum prtysize   age    lot
1        21            5         41     1
2        87            4         33     3
3        65            2         67     1
4        66            2           7     1


------------------ entrance=S ------------------

Obs passnum prtysize   age     lot
5        43            3         27       .
6        44            3         24       .
7        45            3           2       .

 


Entrance data and additional data collected after entering the Fun park (pages 122-123, LSB) can be combined using the SAS  MERGE statement :

Program entry3.sas:

/* program to MERGE the North and South entrance data
created by entry.sas with new scream data
Written by LG for SAS course 4/8/03 */

LIBNAME saspgm '.';

DATA bothdat (DROP = lot);
    SET saspgm.sentrydat saspgm.nentrydat;

/* need to sort by passnum for later MERGE */
PROC SORT;
    BY passnum;

DATA screamsdat;
    INPUT passnum scream;
    DATALINES;
43 0
21 1
44 1
87 0
66 0
;

/* need to sort by passnum for later MERGE */
PROC SORT;
    BY passnum;

DATA alldat;
    MERGE bothdat screamsdat;
    BY passnum;

PROC PRINT;
    TITLE 'SAS Data Set All';
    TITLE1 'Merge of Entrance and Screaming data';
 

Output entry3.lst:

              SAS Data Set All
Merge of Entrance and Screaming data

Obs entrance passnum prtysize age scream
1         N            21          5      41       1
2         S             43          3      27       0
3         S             44          3      24       1
4         S             45          3        2        .
5         N            65          2      67        .
6         N            66          2        7        0
7         N            87          4      33        0

 


SAS's SUM and RETAIN statements can be used to access values from the previous observation (pages 82-83, LSB).  Suppose a store  wants to keep track of a running total and max/min values for daily sales:

Program sales.sas:

/* use RETAIN and SUM statements to access data from previous observations
to keep track of daily sales totals and overall max and min sales
written by LG for SAS course 4/8/03 */

DATA salesdat;
    INPUT dailysales @@;
    RETAIN dailysalesmax -99999 dailysalesmin 9999999 salestotal 0;
    dailysalesmax = MAX(dailysalesmax,dailysales);
    dailysalesmin = MIN(dailysalesmin,dailysales);
    salestotal = sum(salestotal,dailysales);
    CARDS;
    350 460 230 375 525 200 400 350 175 280 600 340 230 175 450 330 540
    ;

PROC PRINT DATA = salesdat;


Note that the @@ in the INPUT command tells SAS that there are multiple observations per line.

Output sales.lst:

Obs   dailysales     dailysalesmax    dailysalesmin     salestotal
1          350                 350                   350                 350
2          460                 460                   350                 810
3          230                 460                   230                 1040
4          375                 460                   230                 1415
5          525                 525                   230                 1940
6          200                 525                   200                 2140
7          400                 525                   200                 2540
8         350                 525                    200                 2890
9         175                 525                    175                 3065
10       280                 525                    175                 3345
11       600                 600                    175                 3945
12       340                 600                    175                 4285
13       230                 600                    175                 4515
14       175                 600                    175                 4690
15       450                 600                    175                 5140
16       330                 600                    175                 5470
17       540                 600                    175                 6010
 


SAS's automatic variable _N_  is always available during the DATA step, and FIRST.variable and LAST.variable  are available if there is a BY statement (pages 141-142, LSB).  Below is an example of how these work (walkers.sas):

program walkers.sas:

/* program to demonstrate FIRST.variable and LAST.variable
written by LG for SAS course 4/8/03 */

DATA walkers;
    INPUT entry agegrp $ time @@;
    CARDS;
    54 youth 35.5 21 adult 21.6 6 adult 25.8 13 senior 29.0 38 senior 40.3 19 youth 39.6
    3 adult 19.0 25 youth 47.3 11 adult 21.9 8 senior 54.3 41 adult 43.0 32 youth 38.6
    ;

/* sort by time so that placings can be determined */
PROC SORT;
    BY time;

/* add placings using automatic variable _N_  */
DATA ordered;
    SET walkers;
    place = _N_;

PROC PRINT;
    TITLE 'Results of walk';

/* now sort data by agegrp and time so that the first occurrence in each age group
is the winner for that group */
PROC SORT;
   BY agegrp time;

/* print this sorted data with FIRST.agegrp and LAST.agegrp values */
DATA printdat;
    SET ordered;
    BY agegrp;
    firstvar = FIRST.agegrp;
    lastvar = LAST.agegrp;

PROC PRINT DATA = printdat;
    TITLE 'Show FIRST.variable LAST.variable';

DATA winners losers;
    SET ordered;
    BY agegrp;
    IF FIRST.agegrp THEN OUTPUT winners;
    IF LAST.agegrp THEN OUTPUT losers;

PROC PRINT DATA = winners;
    TITLE 'Winners in each age group';

PROC PRINT DATA = losers;
    TITLE 'Losers in each age group';

output  walkers.sas:

Results of walk
Obs  entry     agegrp     time     place
1          3         adult      19.0         1
2          21       adult      21.6         2
3          11       adult      21.9         3
4          6         adult      25.8         4
5          13       senior    29.0         5
6          54       youth     35.5         6
7          32       youth     38.6         7
8          19       youth     39.6         8
9          38       senior    40.3         9
10          41     adult      43.0         10
11          25     youth     47.3         11
12          8       senior     54.3        12

Show FIRST.variable LAST.variable
Obs entry agegrp    time     place   firstvar   lastvar
1        3     adult     19.0        1          1          0
2      21     adult     21.6        2          0          0
3      11     adult     21.9        3          0          0
4        6     adult     25.8        4          0          0
5      41     adult     43.0      10          0          1
6      13     senior   29.0        5          1          0
7      38     senior   40.3        9          0          0
8        8     senior   54.3      12          0          1
9      54     youth    35.5       6          1           0
10    32     youth    38.6       7          0           0
11    19     youth    39.6       8          0           0
12    25     youth    47.3     11          0           1

Winners in each age group
Obs   entry     agegrp     time     place
1           3         adult      19.0         1
2         13       senior      29.0         5
3         54        youth      35.5         6


Losers in each age group
Obs   entry     agegrp    time     place
1         41         adult    43.0        10
2           8       senior    54.3        12
3         25        youth    47.3        11

 


Let's look at changing observations to variables with PROC TRANSPOSE (pages 140-141, LSB).  This procedure may be useful for working with the BND files which are created by dopower.  First a simple example to illustrate how to set up.

DATA baseball;
    INPUT team $ player type $ entry;
    CARDS;
    Garlics 10 salary 43000
    Peaches 8 salary 38000
    Garlics 21 salary 51000
    Peaches 10 salary 47500
    Garlics 10 batavg .281
    Peaches 8 batavg .252
    Garlics 21 batavg .265
    Peaches 10 batavg .301
    ;

PROC SORT;
    BY team player;

PROC PRINT;
    TITLE 'Baseball data after sorting and before transposing';

* Transpose data so salary and batavg are variables;
PROC TRANSPOSE;
    BY team player;
    ID type;
    VAR entry;

PROC PRINT;
    TITLE 'Baseball data after transposing';
RUN;
 

 Baseball data after sorting and before transposing

Obs   team     player   type     entry
1       Garlics    10      salary    43000.00
2       Garlics    10      batavg   0.28
3       Garlics    21      salary     51000.00
4       Garlics    21      batavg    0.27
5       Peaches    8      salary     38000.00
6       Peaches    8      batavg    0.25
7       Peaches  10      salary     47500.00
8       Peaches  10      batavg    0.30


Baseball data after transposing

Obs   team     player   _NAME_   salary   batavg
1       Garlics     10         entry       43000    0.281
2       Garlics     21         entry       51000    0.265
3       Peaches     8         entry       38000    0.252
4       Peaches   10         entry       47500    0.301

 

Now let's look at some real real data from the BND files for LNT358 (a subject which showed lots of electrolyte bridging effects).  First the following program (inputBND.sas)  reads in the eight baseline BND files and creates a permanent SAS data set for further work:

LIBNAME SASPGM ".";

%wildcard(NETEEG, /dc/larry/SAScourse/LNT*/LNT*_NO60.BND) ;

DATA SASPGM.BND (DROP = LOBAND HIBAND);
    INFILE NETEEG;
    INPUT SESSION CHANNEL REF $ BAND $ CONDTN $ TRIAL LOBAND HIBAND
                  RAWPWR LOGPWR EEGDUR CHUNKS ;
 

 

One of the challenges of working with SAS is that data sets are generally much too large to inspect visually as we've been doing for these simple examples.  Checking inputBND.log indicates that the resulting data file is the right size:


NOTE: 30720 records were read from the infile NETEEG.
The minimum record length was 49.
The maximum record length was 83.
NOTE: The data set SASPGM.BND has 30720 observations and 10 variables.
 

We dropped two variables from the twelve in the input statement so 10 variables is correct. The input BND files contained 128 channels x 10 frequency bands x 3 references x 8 baseline files = 30720 observations.

One way to simplify working with this data is to put the values for all 128 channels on a single line (i.e. in a single observation).  The transpose procedure just described looks like an easy way to accomplish this (transposeBND.sas):

LIBNAME SASPGM ".";

DATA tmpbnd;
    /* use the permanent SAS data set created above */
    SET SASPGM.BND;
    /* keep only Alpha band values for this example*/
    IF BAND = "Alpha";

/* sort in preparation for transposing "BY" these variables*/
PROC SORT;
    BY SESSION REF CONDTN TRIAL;


PROC TRANSPOSE;
    BY SESSION REF CONDTN TRIAL;
    ID CHANNEL;
    VAR RAWPWR LOGPWR EEGDUR CHUNKS;

PROC PRINT;
    TITLE 'Transposed BND file for LNT358';
RUN;

The output looks like:

 Transposed BND file for LNT358

Obs  SESSION  REF  CONDTN  TRIAL  _NAME_           _1             _2              _3             _4              _5
1       358    AVEALL        EC           1       RAWPWR         111.564    104.675     81.455      37.736       24.759
2       358    AVEALL        EC           1       LOGPWR          2.048        2.020         1.911         1.577        1.394
3       358    AVEALL        EC           1       EEGDUR           59.308      60.000       60.000       60.000       60.000
4       358    AVEALL        EC           1       CHUNKS         115.000    119.000      119.000     119.000     119.000
5       358    AVEALL        EC           2       RAWPWR        103.897    94.566        74.901       36.337       23.257
6       358    AVEALL        EC           2       LOGPWR         2.017        1.976          1.875         1.560         1.367
7       358    AVEALL        EC           2       EEGDUR          60.000      60.000         60.000       60.000       60.000
8       358    AVEALL        EC           2       CHUNKS         119.000    119.000       119.000     119.000    119.000
9       358    AVEALL        EC           3       RAWPWR        119.509    102.975        85.056       39.348      25.573
10     358    AVEALL        EC           3       LOGPWR         2.077        2.013            1.930         1.595        1.408
11     358    AVEALL        EC           3       EEGDUR          60.000      60.000          60.000       60.000       60.000
12     358    AVEALL        EC           3       CHUNKS        119.000    119.000         119.000     119.000     119.000
13     358    AVEALL        EC           4       RAWPWR       107.209    96.479           82.778       36.885       24.515
14     358    AVEALL        EC           4       LOGPWR         2.030       1.984             1.918          1.567        1.389
...

NOTE: There were 3072 observations read from the dataset WORK.TMPBND.
NOTE: The data set WORK.TRNPBND has 96 observations and 133 variables

Since only Alpha band (1 of 10) was kept 3072 of the original 30720 were read.  Transposing the data by RAWPWR, LOGPWR, EEGDUR, and CHUNKS reduced 128 observations to 4  so the output file has 3072 x 4/128 = 96 observations


 We still need to do some juggling and renaming to get the values for RAWPWR, LOGPWR, EEGDUR, and CHUNKS on the same line.  The following code was added after the PROC TRANSPOSE  (transposeBND1.sas):

DATA rawpwr (RENAME = (_1-_128 = RAWPWR1-RAWPWR128))
           logpwr (RENAME = (_1-_128 = LOGPWR1-LOGPWR128))
           eegdur (RENAME = (_1-_128 = EEGDUR1-EEGDUR128))
          chunks (RENAME = (_1-_128 = CHUNKS1-CHUNKS128));
          SET trnpbnd;
          IF _NAME_ = "RAWPWR" THEN OUTPUT rawpwr;
          IF _NAME_ = "LOGPWR" THEN OUTPUT logpwr;
          IF _NAME_ = "EEGDUR" THEN OUTPUT eegdur;
          IF _NAME_ = "CHUNKS" THEN OUTPUT chunks;

DATA SASPGM.INPUT   (DROP=_NAME_);
    MERGE rawpwr logpwr eegdur chunks;

PROC PRINT;
    TITLE 'Transposed and extended BND file for LNT358';
RUN;
 

 Transposed and extended BND file for LNT358

Obs SESSION REF CONDTN TRIAL   RAWPWR1    RAWPWR2     RAWPWR3    RAWPWR4     RAWPWR5    RAWPWR6
1         358  AVEALL    EC            1        111.564          104.675            81.455            37.736              24.759            16.094
2         358  AVEALL    EC            2        103.897          94.566              74.901            36.337              23.257            17.447
3         358  AVEALL    EC            3        119.509          102.975            85.056            39.348              25.573            15.834
4         358  AVEALL    EC            4        107.209          96.479              82.778            36.885              24.515            12.774
5         358  AVEALL    EO            1        14.288            15.422              13.890            5.293                3.911              1.727
6         358  AVEALL    EO            2        16.265            15.806              15.911            5.729                4.208              1.669
7         358  AVEALL    EO            3        17.098            12.884              15.091            4.208                3.121              1.731
8         358  AVEALL    EO            4        17.249            16.438              15.081            6.015                4.672               2.098
...

NOTE: The data set SASPGM.INPUT has 24 observations and 516 variables.

There are 8 trials by 3 references (AVEALL, AVEMAST and Cz) equals 24 observations by RAWPWR, LOGPWR, EEGDUR, and CHUNKS 1-128 plus SESSION, REF, CONDTN, TRIAL equals 516 variables.