Sunday, 20 December 2015

Hive

What's HIVE?

Hive is a data warehouse infrastructure tool to process structured data in Hadoop. It resides on top of Hadoop to summarize Big Data, and makes querying and analyzing easy.

Although Pig can be quite a powerful and simple language to use, the downside is that it’s something new to learn and master. Some folks at Facebook developed by a run time Hadoop support structure that allows anyone who is already fluent with SQL (which is commonplace for relational data-base developers) to leverage the Hadoop platform right out of the gate.

Their creation, called Hive, allows SQL developers to write Hive Query Language (HQL) statements that are similar to standard SQL statements; now you should be aware that HQL is limited in the commands it understands, but it is still pretty useful. HQL statements are broken down by the Hive service into MapReduce jobs and executed across a Hadoop cluster.

For anyone with a SQL or relational database background, this section will look very familiar to you. As with any database management system (DBMS), you can run your Hive queries in many ways. You can run them from a command line interface (known as the Hive shell), from a Java Database Connectivity (JDBC) or Open Database Connectivity (ODBC) application leveraging the Hive JDBC/ODBC drivers, or from what is called a Hive Thrift Client. The Hive Thrift Client is much like any database client that gets installed on a user’s client machine (or in a middle tier of a three-tier architecture): it communicates with the Hive services running on the server. You can use the Hive Thrift Client within applications written in C++, Java, PHP, Python, or Ruby (much like you can use these client-side languages with embedded SQL to access a database such as DB2 or Informix).

Hive looks very much like traditional database code with SQL access. However, because Hive is based on Hadoop and MapReduce operations, there are several key differences. The first is that Hadoop is intended for long sequential scans, and because Hive is based on Hadoop, you can expect queries to have a very high latency (many minutes). This means that Hive would not be appropriate for applications that need very fast response times, as you would expect with a database such as DB2. Finally, Hive is read-based and therefore not appropriate for transaction processing that typically involves a high percentage of write operations.


Functions of HIVE:


Hive has three main functions: data summarization, query and analysis. It supports queries expressed in a language called HiveQL, which automatically translates SQL-like queries into MapReduce jobs executed on Hadoop. In addition, HiveQL supports custom MapReduce scripts to be plugged into queries. Hive also enables data serialization/deserialization and increases flexibility in schema design by including a system catalog called Hive-Metastore.

According to the Apache Hive wiki, "Hive is not designed for OLTP workloads and does not offer real-time queries or row-level updates. It is best used for batch jobs over large sets of append-only data (like web logs)."

Hive supports text files (also called flat files), SequenceFiles (flat files consisting of binary key/value pairs) and RCFiles (Record Columnar Files which store columns of a table in a columnar database way.)

Other features of Hive:


>Indexing to provide acceleration, index type including compaction and Bitmap index as of 0.10, more index types are planned.
>Different storage types such as plain text, RCFile, HBase, ORC, and others.
>Metadata storage in an RDBMS, significantly reducing the time to perform semantic checks during query execution.
>Operating on compressed data stored into the Hadoop ecosystem using algorithms including DEFLATE, BWT, snappy, etc.
>Built-in user defined functions (UDFs) to manipulate dates, strings, and other data-mining tools. Hive supports extending the UDF set to handle use-cases not supported by built-in functions.
>SQL-like queries (HiveQL), which are implicitly converted into MapReduce or Tez, or Spark jobs.

HIVE - Hands ON:

1) Download the data from - http://seanlahman.com/files/database/lahman591-csv.zip

2) The HDFS Files view shows you the files in the HDP file store. In this case the file store resides in the Hortonworks Sandbox VM. Clicking on browse will open a dialog box. Upload Batting.csv file and Master.csv file.


3) Open the Hive View by clicking on the Hive button. The Hive view provides a user interface to the Hive data warehouse system for Hadoop. On right is a query editor. A query may span multiple lines. At the bottom there are buttons to Execute the query, Explain the query, Save the query with a name and to open a new Worksheet window for another query.

The first task we will do is create a table to hold the data. We will type the query into the composition area on the right handside. Once you have typed in the query hit the Execute button at the bottom.

 create table temp_batting (col_value STRING);  

The query does not return any results because at this point we just created an empty table and we have not copied any data in it.

Once the query has executed we can refresh the Database Explorer at the left of the composition area and when folding down the default database we will see we have a new table called temp_batting.

 LOAD DATA INPATH '/user/admin/Batting.csv' OVERWRITE INTO TABLE temp_batting;  

4) The next thing we want to do extract the data. So first we will type in a query to create a new table called batting to hold the data. That table will have three columns for player_id, year and the number of runs.

 create table batting (player_id STRING, year INT, runs INT);  

5) Then we extract the data we want from temp_batting and copy it into batting. We will do this with a regexp pattern. To do this we are going to build up a multi-line query. The first line of the query create the table batting. The three regexp_extract calls are going to extract the player_id, year and run fields from the table temp_batting. When you are done typing the query it will look like this. Be careful as there are no spaces in the regular expression pattern.

 insert overwrite table batting   
 SELECT   
  regexp_extract(col_value, '^(?:([^,]*)\,?){1}', 1) player_id,   
  regexp_extract(col_value, '^(?:([^,]*)\,?){2}', 1) year,   
  regexp_extract(col_value, '^(?:([^,]*)\,?){9}', 1) run   
 from temp_batting;  

6) The next step is to group the data by year so we can find the highest score for each year. This query first groups all the records by year and then selects the player with the highest runs from each year.

 SELECT year, max(runs) FROM batting GROUP BY year;  


7) To go back and get the player_id(s) so we know who the player(s) was. We know that for a given year we can use the runs to find the player(s) for that year. So we can take the previous query and join it with the batting records to get the final table.

 SELECT a.year, a.player_id, a.runs from batting a   
 JOIN (SELECT year, max(runs) runs FROM batting GROUP BY year ) b   
 ON (a.year = b.year AND a.runs = b.runs) ;  


Sunday, 6 December 2015

PIG - An Overview

PIG

Pig is a high-level platform for creating MapReduce programs used with Hadoop. The language for this platform is called Pig Latin. Pig Latin abstracts the programming from the Java MapReduce idiom into a notation which makes MapReduce programming high level, similar to that of SQL for RDBMS systems. Pig Latin can be extended using UDF (User Defined Functions) which the user can write in Java, Python, JavaScript, Ruby or Groovy and then call directly from the language.

Pig was originally developed at Yahoo Research around 2006 for researchers to have an ad-hoc way of creating and executing map-reduce jobs on very large data sets. In 2007, it was moved into the Apache Software Foundation.

It is a platform for analyzing large data sets that consists of a high-level language for expressing data analysis programs, coupled with infrastructure for evaluating these programs. The salient property of Pig programs is that their structure is amenable to substantial parallelization, which in turns enables them to handle very large data sets.

Pig is made up of two components: the first is the language itself, which is called PigLatin and the second is a runtime environment where PigLatin programs are executed.

Why Is It Called Pig?

One question that is frequently asked is, “Why is it named Pig?” People also want to know whether Pig is an acronym. It is not. The story goes that the researchers working on the project initially referred to it simply as “the language.” Eventually they needed to call it something. Off the top of his head, one researcher suggested Pig, and the name stuck. It is quirky yet memorable and easy to spell. While some have hinted that the name sounds coy or silly, it has provided us with an entertaining nomenclature, such as Pig Latin for a language, Grunt for a shell, and Piggybank for a CPAN-like shared repository.


The programming language:
1. The first step in a Pig program is to LOAD the data you want to manipulate from HDFS.
2. Then you run the data through a set of transformations (which, under the covers, are translated into a set of mapper and reducer tasks).
3. Finally, you DUMP the data to the screen or you STORE the results in a file somewhere.

LOAD
As is the case with all the Hadoop features, the objects that are being worked on by Hadoop are stored in HDFS. In order for a Pig program to access this data, the program must first tell Pig what file (or files) it will use, and that’s done through the LOAD 'data_file' command (where 'data_file' specifies either an HDFS file or directory). If a directory is specified, all the files in that directory will be loaded into the program. If the data is stored in a file format that is not natively accessible to Pig, you can optionally add the USING function to the LOAD statement to specify a user-defined function that can read in and interpret the data.

TRANSFORM
The transformation logic is where all the data manipulation happens. Here you can FILTER out rows that are not of interest, JOIN two sets of data files, GROUP data to build aggregations, ORDER results, and much more.

DUMP and STORE
If you don’t specify the DUMP or STORE command, the results of a Pig pro¬gram are not generated. You would typically use the DUMP command, which sends the output to the screen, when you are debugging your Pig programs. When you go into production, you simply change the DUMP call to a STORE call so that any resHow Pig differs from MapReduce

Why is Pig necessary?

Pig provides users with several advantages over using MapReduce directly. Pig Latin provides all of the standard data-processing operations, such as join, filter, group by, order by, union, etc. MapReduce provides the group by operation directly (that is what the shuffle plus reduce phases are), and it provides the order by operation indirectly through the way it implements the grouping. Filter and projection can be implemented trivially in the map phase. But other operators, particularly join, are not provided and must instead be written by the user.

Pig provides some complex, nontrivial implementations of these standard data operations. For example, because the number of records per key in a dataset is rarely evenly distributed, the data sent to the reducers is often skewed. That is, one reducer will get 10 or more times the data than other reducers. Pig has join and order by operators that will handle this case and (in some cases) rebalance the reducers. But these took the Pig team months to write, and rewriting these in MapReduce would be time consuming.

In MapReduce, the data processing inside the map and reduce phases is opaque to the system. This means that MapReduce has no opportunity to optimize or check the user’s code. Pig, on the other hand, can analyze a Pig Latin script and understand the data flow that the user is describing. That means it can do early error checking and optimizations.

MapReduce does not have a type system. This is intentional, and it gives users the flexibility to use their own data types and serialization frameworks. But the downside is that this further limits the system’s ability to check users’ code for errors both before and during runtime.

All of these points mean that Pig Latin is much lower cost to write and maintain than Java code for MapReduce. In one very unscientific experiment, I wrote the same operation in Pig Latin and MapReduce. Given one file with user data and one with click data for a website, the Pig Latin script in Example 1-4 will find the five pages most visited by users between the ages of 18 and 25.ults from running your programs are stored in a file for further processing or analysis. Note that you can use the DUMP command anywhere in your program to dump intermediate result sets to the screen, which is very useful for debugging purposes.

Ex 1:

 batting = load 'Batting.csv' using PigStorage(',')  
 raw_runs = FILTER batting BY $1>0;  
 runs = FOREACH raw_runs GENERATE $0 as playerID, $1 as year, $8 as runs;  
 grp_data = GROUP runs by (year);  
 max_runs = FOREACH grp_data GENERATE group as grp,MAX(runs.runs) as max_runs;  
 join_max_run = JOIN max_runs by ($0, max_runs), runs by (year,runs);   
 join_data = FOREACH join_max_run GENERATE $0 as year, $2 as playerID, $1 as runs;   
 DUMP join_data;  

Result



Ex 2:

 Users = load 'users' as (name, age);  
 Fltrd = filter Users by age >= 18 and age <= 25;  
 Pages = load 'pages' as (user, url);  
 Jnd  = join Fltrd by name, Pages by user;  
 Grpd = group Jnd by url;  
 Smmd = foreach Grpd generate group, COUNT(Jnd) as clicks;  
 Srtd = order Smmd by clicks desc;  
 Top5 = limit Srtd 5;  
 store Top5 into 'top5sites';  

Explanation

The first line of this program loads the file users and declares that this data has two fields: name and age. It assigns the name of Users to the input. The second line applies a filter to Users that passes through records with an age between 18 and 25, inclusive. All other records are discarded. Now the data has only records of users in the age range we are interested in. The results of this filter are named Fltrd.

The second load statement loads pages and names it Pages. It declares its schema to have two fields, user and url.

The line Jnd = join joins together Fltrd and Pages using Fltrd.name and Pages.user as the key. After this join we have found all the URLs each user has visited.

The line Grpd = group collects records together by URL. So for each value of url, such as pignews.com/frontpage, there will be one record with a collection of all records that have that value in the url field. The next line then counts how many records are collected together for each URL. So after this line we now know, for each URL, how many times it was visited by users aged 18–25.

The next thing to do is to sort this from most visits to least. The line Srtd = order sorts on the count value from the previous line and places it in desc (descending) order. Thus the largest value will be first. Finally, we need only the top five pages, so the last line limits the sorted results to only five records. The results of this are then stored back to HDFS in the file top5sites.

In Pig Latin this comes to nine lines of code and took about 15 minutes to write and debug. The same code in MapReduce (omitted here for brevity) came out to about 170 lines of code and took me four hours to get working. The Pig Latin will similarly be easier to maintain, as future developers can easily understand and modify this code.

There is, of course, a cost to all this. It is possible to develop algorithms in MapReduce that cannot be done easily in Pig. And the developer gives up a level of control. A good engineer can always, given enough time, write code that will out perform a generic system. So for less common algorithms or extremely performance-sensitive ones, MapReduce is still the right choice. Basically this is the same situation as choosing to code in Java versus a scripting language such as Python. Java has more power, but due to its lower-level nature, it requires more development time than scripting languages. Developers will need to choose the right tool for each job.



REFERNCES:

To Download - https://pig.apache.org/releases.html

Saturday, 21 November 2015

HADOOP

Apache Hadoop is an open-source software framework written in Java for distributed storage and distributed processing of very large data sets on computer clusters built from commodity hardware. All the modules in Hadoop are designed with a fundamental assumption that hardware failures (of individual machines, or racks of machines) are commonplace and thus should be automatically handled in software by the framework. It is designed to scale up from single servers to thousands of machines, each offering local computation and storage. Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer, so delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures. The term "Hadoop" has come to refer not just to the base modules above, but also to the "ecosystem",[8] or collection of additional software packages that can be installed on top of or alongside Hadoop, such as Apache Pig, Apache Hive, Apache HBase, Apache Phoenix, Apache Spark, Apache ZooKeeper, Impala, Apache Flume, Apache Sqoop, Apache Oozie, Apache Storm and others.

The project includes these modules:

Hadoop Common: The common utilities that support the other Hadoop modules.
Hadoop Distributed File System (HDFS): A distributed file system that provides high-throughput access to application data.
Hadoop YARN: A framework for job scheduling and cluster resource management.
Hadoop MapReduce: A YARN-based system for parallel processing of large data sets.

Hadoop Common:

Hadoop Common refers to the collection of common utilities and libraries that support other Hadoop modules. It is an essential part or module of the Apache Hadoop Framework, along with the Hadoop Distributed File System (HDFS), Hadoop YARN and Hadoop MapReduce. Like all other modules, Hadoop Common assumes that hardware failures are common and that these should be automatically handled in software by the Hadoop Framework.

Hadoop Common is also known as Hadoop Core.


Hadoop Distributed File System (HDFS):

HDFS is a distributed file system that provides high-performance access to data across Hadoop clusters. Like other Hadoop-related technologies, HDFS has become a key tool for managing pools of big data and supporting big data analytics applications.

Because HDFS typically is deployed on low-cost commodity hardware, server failures are common. The file system is designed to be highly fault-tolerant, however, by facilitating the rapid transfer of data between compute nodes and enabling Hadoop systems to continue running if a node fails. That decreases the risk of catastrophic failure, even in the event that numerous nodes fail.

When HDFS takes in data, it breaks the information down into separate pieces and distributes them to different nodes in a cluster, allowing for parallel processing. The file system also copies each piece of data multiple times and distributes the copies to individual nodes, placing at least one copy on a different server rack than the others. As a result, the data on nodes that crash can be found elsewhere within a cluster, which allows processing to continue while the failure is resolved.

HDFS is built to support applications with large data sets, including individual files that reach into the terabytes. It uses a master/slave architecture, with each cluster consisting of a single NameNode that manages file system operations and supporting DataNodes that manage data storage on individual compute nodes.


An example of HDFS :

Think of a file that contains the phone numbers for everyone in the United States; the people with a last name starting with A might be stored on server 1, B on server 2, and so on. In a Hadoop world, pieces of this phonebook would be stored across the cluster, and to reconstruct the entire phonebook, your program would need the blocks from every server in the cluster. To achieve availability as components fail, HDFS replicates these smaller pieces onto two additional servers by default. (This redundancy can be increased or decreased on a per-file basis or for a whole environment; for example, a development Hadoop cluster typically doesn’t need any data re­dundancy.) This redundancy offers multiple benefits, the most obvious being higher availability.
In addition, this redundancy allows the Hadoop cluster to break work up into smaller chunks and run those jobs on all the servers in the cluster for better scalability. Finally, you get the benefit of data locality, which is critical when working with large data sets.


Hadoop YARN:

YARN is one of the key features in the second-generation Hadoop 2 version of the Apache Software Foundation's open source distributed processing framework. Originally described by Apache as a redesigned resource manager, YARN is now characterized as a large-scale, distributed operating system for big data applications.

In 2012, YARN became a sub-project of the larger Apache Hadoop project. Sometimes called MapReduce 2.0, YARN is a software rewrite that decouples MapReduce's resource management and scheduling capabilities from the data processing component, enabling Hadoop to support more varied processing approaches and a broader array of applications. For example, Hadoop clusters can now run interactive querying and streaming data applications simultaneously with MapReduce batch jobs. The original incarnation of Hadoop closely paired the Hadoop Distributed File System (HDFS) with the batch-oriented MapReduce programming framework, which handles resource management and job scheduling on Hadoop systems and supports the parsing and condensing of data sets in parallel.

YARN combines a central resource manager that reconciles the way applications use Hadoop system resources with node manager agents that monitor the processing operations of individual cluster nodes. Running on commodity hardware clusters, Hadoop has attracted particular interest as a staging area and data store for large volumes of structured and unstructured data intended for use in analytics applications. Separating HDFS from MapReduce with YARN makes the Hadoop environment more suitable for operational applications that can't wait for batch jobs to finish.

MapReduce:

It is a framework for writing applications that process large amounts of data. MapReduce is the original framework for writing applications that process large amounts of structured and unstructured data stored in the Hadoop Distributed File System (HDFS). Apache Hadoop YARN opened Hadoop to other data processing engines that can now run alongside existing MapReduce jobs to process data in many different ways at the same time.

This section provides a reasonable amount of detail on every user-facing aspect of the MapReduce framework. This should help users implement, configure and tune their jobs in a fine-grained manner. However, please note that the javadoc for each class/interface remains the most comprehensive documentation available; this is only meant to be a tutorial. Let us first take the Mapper and Reducer interfaces. Applications typically implement them to provide the map and reduce methods. We will then discuss other core interfaces including JobConf, JobClient, Partitioner, OutputCollector, Reporter, InputFormat, OutputFormat, OutputCommitter and others.

Finally, we will wrap up by discussing some useful features of the framework such as the DistributedCache, IsolationRunner etc.

Payload:

Applications typically implement the Mapper and Reducer interfaces to provide the map and reduce methods. These form the core of the job.

Mapper:
Mapper maps input key/value pairs to a set of intermediate key/value pairs.

Maps are the individual tasks that transform input records into intermediate records. The transformed intermediate records do not need to be of the same type as the input records. A given input pair may map to zero or many output pairs.

The Hadoop MapReduce framework spawns one map task for each InputSplit generated by the InputFormat for the job.

How Many Maps?
The number of maps is usually driven by the total size of the inputs, that is, the total number of blocks of the input files. The right level of parallelism for maps seems to be around 10-100 maps per-node, although it has been set up to 300 maps for very cpu-light map tasks. Task setup takes awhile, so it is best if the maps take at least a minute to execute. Thus, if you expect 10TB of input data and have a blocksize of 128MB, you'll end up with 82,000 maps, unless setNumMapTasks(int) (which only provides a hint to the framework) is used to set it even higher.

Reducer:

Reducer reduces a set of intermediate values which share a key to a smaller set of values.

The number of reduces for the job is set by the user via JobConf.setNumReduceTasks(int).

Overall, Reducer implementations are passed the JobConf for the job via the JobConfigurable.configure(JobConf) method and can override it to initialize themselves. The framework then calls reduce(WritableComparable, Iterator, OutputCollector, Reporter) method for each pair in the grouped inputs. Applications can then override the Closeable.close() method to perform any required cleanup.

Reducer has 3 primary phases: shuffle, sort and reduce.

Shuffle

Input to the Reducer is the sorted output of the mappers. In this phase the framework fetches the relevant partition of the output of all the mappers, via HTTP.

Sort

The framework groups Reducer inputs by keys (since different mappers may have output the same key) in this stage. The shuffle and sort phases occur simultaneously; while map-outputs are being fetched they are merged.

Secondary Sort

If equivalence rules for grouping the intermediate keys are required to be different from those for grouping keys before reduction, then one may specify a Comparator via JobConf.setOutputValueGroupingComparator(Class). Since JobConf.setOutputKeyComparatorClass(Class) can be used to control how intermediate keys are grouped, these can be used in conjunction to simulate secondary sort on values.

How Many Reduces?
The right number of reduces seems to be 0.95 or 1.75 multiplied by ( * mapred.tasktracker.reduce.tasks.maximum). With 0.95 all of the reduces can launch immediately and start transfering map outputs as the maps finish. With 1.75 the faster nodes will finish their first round of reduces and launch a second wave of reduces doing a much better job of load balancing. Increasing the number of reduces increases the framework overhead, but increases load balancing and lowers the cost of failures. The scaling factors above are slightly less than whole numbers to reserve a few reduce slots in the framework for speculative-tasks and failed tasks.

Why Hadoop is important for Big Data?

Hadoop is changing the perception of handling Big Data especially the unstructured data. Apache Hadoop enables surplus data to be streamlined for any distributed processing system across clusters of computers using simple programming models. It truly is made to scale up from single servers to a large number of machines, each and every offering local computation, and storage space. Instead of depending on hardware to provide high-availability, the library itself is built to detect and handle breakdowns at the application layer, so providing an extremely available service along with a cluster of computers, as both versions might be vulnerable to failures.


Recent News:

28 October, 2015: Release 2.6.2 available
A point release for the 2.6 line.

23 September, 2015: Release 2.6.1 available
A point release for the 2.6 line.
Hadoop 2.6.1 Release Notes for the list of 158 critical bug fixes and since the previous release 2.6.0.

06 July, 2015: Release 2.7.1 (stable) available
A point release for the 2.7 line. This release is now considered stable.
Hadoop 2.7.1 Release Notes for the list of 131 bug fixes and patches since the previous release 2.7.0.

Saturday, 3 October 2015

Welcome to SAS 

Part 2

1. Proc Reports
Although you can customize the output produced by PROC PRINT, there are times when
you need a bit more control over the appearance of your report. PROC REPORT was developed to fit this need. Not only can you control the appearance of every column of your report, you can produce summary reports as well as detail listings.
Two very useful features of PROC REPORT, multiple-panel reports and text wrapping within a column. We will look more about Proc Report by the following example.

#Problem:
Using the SAS data set Blood Pressure we have to create a new variable called Hypertensive which is mentioned as Yes for females (Gender=F) if the SBP is greater than 138 or the DBP is greater than 88 and No otherwise. For males (Gender=M), Hypertensive is defined as Yes if the SBP is over 140 or the DBP is over 90 and No otherwise.

#Data set:

*Creating Bloodpressure dataset;
data A15011.A11_bloodpressure;
   input Gender : $1. 
         Age
         SBP
         DBP;
datalines;
M 23 144 90
F 68 110 62
M 55 130 80
F 28 120 70
M 35 142 82
M 45 150 96
F 48 138 88
F 78 132 76
;

#Solution:

title "Hypertensice Patients";
proc report data=A15011.A11_bloodpressure nowd;
column Gender SBP DBP Hypertensive;
define Gender / Group width=6;
define SBP / display width=5;
define DBP / display width=5;
define Hypertensive / computed "Hypertensive?" width=13;
compute Hypertensive / character length=3;
if Gender = 'F' and (SBP gt 138 or DBP gt 88)
then Hypertensive = 'Yes';
else Hypertensive='No';
if Gender = 'M' and
(SBP gt 140 or DBP gt 90)
then Hypertensive = 'Yes';
else Hypertensive = 'No';
endcomp;
run;
quit;

#Output:


#Explanation:

In the above program we are trying to check whether the person is Hypertensive or not.  For that we need an output based on the requirements which is explained in the problem statement. In the solution we use a statement called DEFINE which is used to specify the usage for each variable. Learning how to control whether to produce a detail listing or a summary report and what
statistics to produce leads you to the DEFINE statement. The DEFINE option DISPLAY is an instruction to produce a detailed listing of all observations. Besides defining the usage as DISPLAY, the DEFINE statement also carry a GROUP option when we need to club the data.

Another import thing in the above program is COMPUTE. One powerful feature of PROC REPORT is its ability to compute new variables. This makes PROC REPORT somewhat unique among SAS procedures. We can use the compute statements to create a COMPUTE block where we can define the new variables inside the block. Here we compute whether he patient is Hypertensive or not based on the SBP and DB values using the IF else statements which we already learned. Also, we used quit statement to stop the procedure, otherwise it wont stop.

2. Proc Means

In this post, we will see about PROC Means which is more versatile and can be used to create summary data sets that can then be analyzed with more DATA or PROC steps.By default, PROC MEANS produces statistics on all the numeric variables in the input SAS data set. Let's see some examples.


#Problem:

Using the SAS data set College, report the mean GPA for the following categories of
ClassRank: 0–50 = bottom half, 51–74 = 3rd quartile, and 75 to 100 = top quarter.

#Dataset:

*Creating user defined format;
proc format library=A15011;
   value $yesno 'Y','1' = 'Yes'
                'N','0' = 'No'
                ' '     = 'Not Given';
   value $size 'S' = 'Small'
               'M' = 'Medium'
               'L' = 'Large'
                ' ' = 'Missing';
   value $gender 'F' = 'Female'
                 'M' = 'Male'
                 ' ' = 'Not Given';
run;
*Calling the format library;
option FMTSEARCH=(A15011);
*Creating college dataset;
data A15011.A11_college;
   length StudentID $ 5 Gender SchoolSize $ 1;
   do i = 1 to 100;
      StudentID = put(round(ranuni(123456)*10000),z5.);
      if ranuni(0) lt .4 then Gender = 'M';
      else Gender = 'F';
      if ranuni(0) lt .3 then SchoolSize = 'S';
      else if ranuni(0) lt .7 then SchoolSize = 'M';
      else SchoolSize = 'L';
      if ranuni(0) lt .2 then Scholarship = 'Y';
      else Scholarship = 'N';
      GPA = round(rannor(0)*.5 + 3.5,.01);
      if GPA gt 4 then GPA = 4;
      ClassRank = int(ranuni(0)*60 + 41);
      if ranuni(0) lt .1 then call missing(ClassRank);
      if ranuni(0) lt .05 then call missing(SchoolSize);
      if ranuni(0) lt .05 then call missing(GPA);
      output;
   end;
   format Gender $gender1. 
          SchoolSize $size. 
          Scholarship $yesno.;
   drop i;
run;

#Solution:

proc format;
value rank 0-50 = 'Bottom Half'
51-74 = 'Third Quartile'
75-100 = 'Top Quarter';
run;
title "Statistics on the College Data Set";
title2 "Broken down by School Size";
proc means data=A15011.A11_college
n
mean
maxdec=2;
class ClassRank;
var GPA;
format ClassRank rank.;
run;

#Output:



#Explanation:


In the above program we tried to do some basic statistical calculation Mean which is to be said as average in the common man term. The data set which we used is College which we are seeing for most of the posts and that is not our interest of this post. So, we will concentrate on the solution part. The Proc Means procedure helps us to calculate the average of the variable. Here we are calculating the average of GPA based on the Class Rank where we created a range for the rank using Proc Format procedure. The options "n" gives the Number of persons and "Mean" gives the average value for that particular section of students and we can adjust the value as 2 decimal point by giving "Maxdec" option.

PROC MEANS lets you use a CLASS statement in place of a BY statement. The CLASS statement performs a similar function to the BY statement, with some significant differences. If you are using PROC MEANS to print a report and are not creating a summary output data set, the differences in the printed output between a BY and CLASS statement are basically cosmetic. The main difference, from a programmer’s perspective, is that you do not have to sort your data set before using a CLASS statement. Similarly, You can control which variables to include in the report by supplying a VAR statement.

3. PROC Tabulate


PROC TABULATE is an underused, under appreciated procedure that can create a wide
variety of tabular reports, displaying frequencies, percentages, and descriptive statistics such as sums and means) broken down by one or more CLASS variables. There are several excellent books devoted to PROC TABULATE. This posts introduces you to this procedure and, we hope, piques your interest.

#Problem:
Using the college data set which was given in my previous post, we should tabulate using the Proc Tabulate procedure.

#Solution:

title "Demographics from COLLEGE Data Set";
proc tabulate data=A15011.A11_college format=6.;
class Gender Scholarship SchoolSize;
tables SchoolSize all,
Gender Scholarship all/ rts=15;
keylabel n=' '
all = 'Total';
run;

#Output::


#Explanation:

PROC TABULATE uses a CLASS statement to allow you to specify variables that
represent categories (often character variables) where you want to compute frequencies
or percentages. So here we want to broke down the data based on the school size and type and Gender as well. Next, the TABLE statement specifies the table’s appearance. Any variable listed in a TABLE statement must be listed in a CLASS statement.

Apart from the above two keywords, we used format option which helps to display in the specific format for every cell in the table. Unlike many other SAS procedures, there are some reserved keywords used by PROC TABULATE and one such keyword is ALL. When you place ALL after a variable name in a table request, PROC TABULATE includes a column representing all levels of the preceding variable. Another customization option is RTS=, which increases the row title space (the space for the width of the row title, including the vertical lines).
Let us look another example where we can change the names of the variables in the Proc Tabulate Procedure.

#Solution:

title "Descriptive Statistics";
proc tabulate data=A15011.A11_college format=6.1;
class Gender;
var GPA;
tables GPA*(n*f=4.
mean min max),
Gender all;
keylabel n = 'Number'
all = 'Total'
mean = 'Average'
min = 'Minimum'
max = 'Maximum';
run;

#Output:

'
In the above output we can see that, the variable name "n" is changed as Number,"min" is changed as "Minimum" and similarly for max and avg. Thus usiing Proc Tabulate we can alter the table based on our needs to report the output.

4. Introduction to ODS

One of the most important changes in SAS, starting with Version 7, was the introduction of the Output Delivery System, abbreviated as ODS. Prior to ODS, each SAS procedure
produced its own unique output, usually featuring a non-proportional font.

Each SAS procedure creates output objects that can be sent to such destinations as HTML, RTF, PDF, and SAS data sets.There is now a separation between the results produced by each procedure and the delivery of this information. Not only can you send your SAS output to all of these formats, you can, if you are brave enough, customize the output’s fonts, colors, size, and
layout. Finally, you can now capture virtually every piece of SAS output to a SAS data
set for further processing.

#Problem:

Run the following program, sending the output to an HTML file. Issue the appropriate commands to prevent SAS from creating a listing file.

title "Sending Output to an HTML File";
proc print data=learn.college(obs=8) noobs;
run;
proc means data=learn.college n mean maxdec=2;
var GPA ClassRank;
run;


#Solution:

options fmtsearch=(A15011);
ods listing close;
ods html file = '/folders/myfolders/prob19_1.html';
title "Sending Output to an HTML File";
proc print data=A15011.A11_college(obs=8) noobs;
run;
proc means data=A15011.A11_college n mean maxdec=2;
var GPA ClassRank;
run;
ods html close;
ods listing;

#Output:





#Explanation:

In the above example we tried to get the output as HTML page rather than the normal listing output. If you do not want a listing style output, use the ODS statement before the
ODS HTML FILE statement. Next. to get the output as an HTML file, we use the ODS html statement to give a local path so that tho output can be saved in that place as an HTML file. Finally, If you want to reinstate the listing output, use "ods listing" which will reinstate the listing output.

5. Generating High-Quality Graphics

In this post we speaks about some basic concepts behind SAS/GRAPH software. First you need to have SAS/GRAPH installed on your computer. Without it, you are relegated to using the older style “line printer” type plots using such procedures as PROC CHART and PROC PLOT.
These procedures are fine if you want a quick look at your data in graphical form; however, they are not suitable for presentations.

The appearance of graphs and charts is controlled by graphics options and global
statements such as SYMBOL and PATTERN. Options that are set using these statements
act somewhat like titles created using TITLE statements. That is, they remain in effect
until you change them and they are additive. For example, if you already have dots
selected as your plotting symbols, with the color set to black, and you change the color to
red, your plots display with red dots. Lets do some problems.

#Problem:

Using the SAS data set Bicycles, we want to produce two vertical bar charts showing frequencies for Country and Model. Use the PATTERN option VALUE=empty.

#Dataset:

*Data set BICYCLES;
data learn.bicycles;
   input Country  & $25.
         Model    & $14.
         Manuf    : $10.
         Units    :   5.
         UnitCost :  comma8.;
   TotalSales = (Units * UnitCost) / 1000;
   format UnitCost TotalSales dollar10.;
   label TotalSales = "Sales in Thousands"
         Manuf = "Manufacturer";
datalines;
USA  Road Bike  Trek 5000 $2,200
USA  Road Bike  Cannondale 2000 $2,100
USA  Mountain Bike  Trek 6000 $1,200
USA  Mountain Bike  Cannondale 4000 $2,700
USA  Hybrid  Trek 4500 $650
France  Road Bike  Trek 3400 $2,500
France  Road Bike  Cannondale 900 $3,700
France  Mountain Bike  Trek 5600 $1,300
France  Mountain Bike  Cannondale  800 $1,899
France  Hybrid  Trek 1100 $540
United Kingdom  Road Bike  Trek 2444 $2,100
United Kingdom  Road Bike  Cannondale  1200 $2,123
United Kingdom  Hybrid  Trek 800 $490
United Kingdom  Hybrid  Cannondale 500 $880
United Kingdom  Mountain Bike  Trek 1211 $1,121
Italy  Hybrid  Trek 700 $690
Italy  Road Bike  Trek 4500  $2,890
Italy  Mountain Bike  Trek 3400  $1,877
;


#Solution:

title Freq of countries;
proc sgplot data=A15011.A11_bicycles;
    vbar Country;
    xaxis label='Country';
run;
 
title 'Freq of Models';
proc sgplot data=A15011.A11_bicycles;
    hbar Model;
    xaxis label='Count';
run;

#Output:




#Explanation:


There are lot of normal type of charts such as Proc Plot/Chart as said before, but it wont look like a feel good visuals. So creating a good graphical content there are lot of specific procedures such as gchart, gplot etc., which will gives some good graphical outputs. In the above example we used GPLOT procedure which produced the graphical content for your data. The VBAR and HBAR states abou the position of the graph like vertical or horizontal. Also we can give names for the axis xaxis and yaxis statement. Try the same graph using GCHART.

6. Proc FREQ

PROC FREQ can be used to count frequencies of both character and numeric variables, in one-way, two-way, and three-way tables. In addition, you can use PROC FREQ to create output data sets containing counts and percentages. Finally, if you are statistically inclined, you can use this procedure to compute various statistics such as chi-square, odds ratio, and relative risk.

#Problem:

Using the SAS data set Blood, we will generate one-way frequencies for the variables Gender, BloodType, and AgeGroup.

#Dataset:

Used in the previous example.

#Solution:

title "One-way Frequencies from BLOOD Data Set";
proc freq data=A15011.A11_blood;
tables Gender BloodType AgeGroup / nocum nopercent;
run;

#Output:




#Explanation:
Here using the Proc freq procedure we can computes counts for each unique value of a variable. Here the TABLES statement to list the variables for which you want to compute
frequencies. Thus, in this example we are trying to calculate the frequencies for the variables Gender, Blood type and Age group. Secondly, w have used some option like NOCUM and NOPERCENT which tells PROC FREQ not to include the two cumulative statistics columns and percentages in the output, respectively.

The above example is single way frequency table and we can also produce two way or three way frequency tables. The below example shows how to produce three way frequency table. By using the college dataset we can build a three way freq table.

proc freq data=A15011.A11_college;
tables Gender*Scholarship*SchoolSize;
run;

In the above program we try to get a freq table for Gender, Scholarship and School size. To built a multi way freq table we have to use (*) symbol between the variables. The output for the above program will looks like below.

#Output:



From the output, we got Gender wise 2 tables and each table shows whether they have scholarship or not and it is further classified based on the school type. Thus we can easily get the table format which will help us to classify based on the information we needed.

Friday, 2 October 2015

Welcome to SAS


Learning new things will help you to equip in this fast moving world. But writing a blog about your experience of new learning not only help others but it helps you as well in future as a reference for your work. In the competitive world every company should innovate themselves very frequently to stay ahead of their competition. Also they need to study about the changing market conditions or customers to suffice their needs. Lot of time taking the decision is very hard and it also get failed since we are all take the decision based on our experience. There is no way to support your decision with strong evidence.

On the other side you can make use of the data which is increasing day to day. Identifying the valuable insights from the data helps to take a valid decision which helps to grow your company. There are lot of tools available to analyze the big big data. I wills start to write about SAS which is a standard tool used by most of the organisation.

Learning SAS is not a big deals since it will be easier than other complex program languages. The code used here look like a normal English language and those who don't have a programming experience can also easy take this tool to learn. As a first step to learn SAS, I will start from one of the basic book " Learning SAS by examples" - written by Ron Cody. Here I will try to post some of the problems given in the books.

1. Using If-Else in SAS

Two of the basic tools for conditional processing are the IF and ELSE IF statements. To understand how these statements work, we will look some examples based on these statements.

#Dataset:
    *creating a new datset called school;
     data A15011.A11_school;
       input Age Quiz $ Midterm Final;

      datalines;
      12 A 92 95

      12 B 88 88
      13 C 78 75

      13 A 92 93

      12 F 55 62
      13 B 88 82
       ;

#Problem Statement:

Using IF and ELSE IF statements, we have to compute two new variables for the following data set:
        1)    Grade (numeric), with a value of 6 if Age is 12 and a value of 8 if Age is 13
        2)    Using this information, compute a course grade (Course) as a weighted average of the Quiz (20%), Midterm (30%) and Final (50%).

#Solution:
It is good practice a create a permanent library and save the work in the that. The permanent library ends when the session ends. So next time if you want to execute the programm you should call the permanent library again.

"libname A15011 "/folders/myfolders";

Libname is the SAS keywork to create a permanent SAS library. I will use A15011 as m library name throughout my posts. But you can create your own library name. Then the path for the library.


data A15011.A11_school1;
*subsetting the school datast;
set A15011.A11_school;

*Assiginig the grades based on the age;

if age = 12 then grade =6;

else if age eq 13 then grade=8;

*Replacing the quiz value based on the type;

if Quiz eq "A" then quiz=95;

if Quiz eq "B" then quiz=85;
if Quiz eq "C" then quiz=75;
if Quiz eq "F" then quiz=65;
*Calculating the coursegrade based on the weightage for different exams;
coursegrade = 0.2*Quiz+0.3*Midterm+0.5*Final;
run;
PROC PRINT DATA=A15011.A11_school1;
RUN;

The above program creates a two new variables called grade and course grade based on the given conditions. Also you can see comments in between the program which will explain each line. In SAS comment can be made by two methods like (*.....;) or (/*....*/).

#Output:



Thus, if you see the output two new variables are created and we are segregated the grade and course grade by the given conditions. We are creating two new variables based on the IF else conditions by using logical operators.

Yes, there are lot of ways to reduced the size of the program and since my aim to make the program clear and understandable, I will initially use a explanatory kind of program. In future we can see how to write the same program in efficient manner.

2. Do loops

In the previous post, we saw if else condition. In this post, we can see how can we improve programming using do loop. Some times we come up with a situation where we should use two or more IF statements for the same conditions. But we can avoid this by using DO and END statements where we can test a condition at first and then perform several actions. We will see this by the below examples.

#Problem:
There are three speed-reading methods(A, B and C) and we are assigning 10 subjects to each of the three methods. The results are given below in three lines of reading speeds, each line represents the results from each of the three methods.

250 255 256 300 244 268 301 322 256 333
267 275 256 320 250 340 345 290 280 300
350 350 340 290 377 401 380 310 299 399

Now, we want each observation should contain Method A,B or C and score. There should be 30 observation in the data set.

#Solution:
data A15011.A11_method;
*using Do loop assigning three methods and then the 10 subjects;
do method = 'method A','method B', 'method C';
do i = 1 to 10;
* @ symbol tells SAS more data to be added for the method;
input score @;
ouput;
end;
end;
drop i;
datalines;
250 255 256 300 244 268 301 322 256 333
267 275 256 320 250 340 345 290 280 300
350 350 340 290 377 401 380 310 299 399
;
proc print data=A15011.A11_method;
run;

In the above program we are using are using nested Do loop to assign 10 observations for each method. In first do loop SAS creates "Method A" and it will go to the next Do loop and which denotes there are totally ten subjects. When SAS starts to read the datalines it will read the 10 results in the first for method A. This is done because the @ symbol in the input line tell SAS there are more observation to add, so that SAS don't go for the next line. The below output shows both using @ symbol and without it.

#Output:

With @ symbol











                             Without @ Symbol



















#Learning:
So now we know that when and how to use Do loops and why it is efficient than IF statement. Also we learned about the nested DO loop. Moreover we now know how to read more data when it is present in the single line (by @ symbol).

3. SAS Dates

SAS normally stores the date into a single number—the number of days from January 1, 1960. Dates after January 1, 1960, are positive integers; dates before January 1, 1960, are negative integers. The below are the some of the example how SAS stores the data.
December 31, 1959    -1

       June 15, 2006             16,967
      October 21, 1950        -3,359
To avoid these we can use SAS date format  to display the date correctly in the output. There are few Date formats which we can used based on your need. Two very popular date formats are DATE9. and MMDDYY10. Also there is some difference in reading two digit year and four digit year in SAS. SAS can read four digit year flawlessly but for two year you have to specify the YEARCUTOFF option.The default value for this option is 1920 in SAS 8 and SAS®9. This value determines the start of a 100-year interval that SAS uses when it encounters a two-digit year. Now let us do some problems in the dates.

#Problem:
The below data contains three dates, the first two in the form mm/dd/yyyy descenders and the last in the form ddmmmyyyy. We have to name the three date variables Date1, Date2, and Date3. Also we have to format all three using the MMDDYY10. format. Also we can see how to include the number of years from Date1 to Date2 (Year12) and the number of
years from Date2 to Date3 (Year23) and finally we round these years to the nearest number.

01/03/1950 01/03/1960 03Jan1970
05/15/2000 05/15/2002 15May2003
10/10/1998 11/12/2000 25Dec2005


# Solution:
data A15011.A11_dates;
* using the date informats;
input Date1 : mmddyy10.
Date2 : mmddyy10.
Date3 : date9.;
*Using yrdif function to compute number of years between two dates;
*By giving actual we get the exact number of days;
Year1-2 = round(yrdif(Date1,Date2,'Actual'));
Year2-3 = round(yrdif(Date2,Date3,'Actual'));
format Date1-Date3 mmddyy10.;
datalines;
01/03/1950 01/03/1960 03Jan1970
05/15/2000 05/15/2002 15May2003
10/10/1998 11/12/2000 25Dec2005
;
Proc Print data=A15011.A11_threedates;
run;


#Output:


# Learning and reading the data from the output:           
In the above program we used two date informats (mmddyy10. & date9.). This tell SAS that how we read the data from the datalines. Don't forget to use . after the format. Then we use YRDIF function which is help to calculate the difference between the two dates and ACTUAL helps to get the exact difference which include the leap year. Finally we use formats which is different from informats. In formats we tell SAS how to write the data in output.

4. Sub-setting SAS data sets 

Subsetting SAS dataset is using some conditions and selecting observation from one dataset and creating the other. This may be useful when one want to work a particular set of observation rather than working the whole data. Moreover, this will help us to keep the original file undisturbed. In this post we will see how to subset the data from one dataset to the other .

#Problem:
We want to create a dataset from the hospital data (given the Ron cody book) where the admission data falls on Monday and the year is 2002. We also want to know the age of the patient as of the admission date.

Hospital Data-set:

data A15011.A11_hosp;
   do j = 1 to 1000;
      AdmitDate = int(ranuni(1234)*1200 + 15500);
      quarter = intck('qtr','01jan2002'd,AdmitDate);
      do i = 1 to quarter;
         if ranuni(0) lt .1 and weekday(AdmitDate) eq 1 then
            AdmitDate = AdmitDate + 1;
         if ranuni(0) lt .1 and weekday(AdmitDate) eq 7 then
            AdmitDate = AdmitDate - int(3*ranuni(0) + 1);
         DOB = int(25000*Ranuni(0) + '01jan1920'd);
         DischrDate = AdmitDate + abs(10*rannor(0) + 1);
         Subject + 1;
         output;
      end;
   end;
   drop i j;
   format AdmitDate DOB DischrDate mmddyy10.;
run;

#Solution:

data A15011.A11_monday02;
*subsetting the data hosp;
set A15011.A11_hosp;
where year(AdmitDate) eq 2002 and
weekday(AdmitDate) eq 2;
Age = round(yrdif(DOB,AdmitDate,'Actual'));
run;
proc print data=A15011.A11_monday02;
run;

#Output:















# About the program and Learning:
In this program we subset the original Hosp dataset to a new called monday02. This can be done by using SET function. The set function helps us to subset the observation from the original dataset. By giving any particular condition next to set function helos us to get the particular data or if we need the whole data we simply use the set function alone. In this programm we also used WEEKDAY function which helps us to compute the day of the week from the SAS date. Then we used yrdif and actual which we learned already.

5. Using Numeric functions

There are lot mathematical function that can be done through SAS. Starting from rounding numbers, computing dates from month-day-year values, summing and averaging the values of SAS variables, and hundreds of other tasks can be done in SAS. In this post we can see some of the numeric function by doing in SAS.

#Problem:
We want to compute the body mass index (BMI) from the health data set. Also we want to create four other variables based on BMI: 1) BMIRound is the BMI rounded to the nearest integer, 2)BMITenth is the BMI rounded to the nearest tenth, 3) BMIGroup is the BMI rounded to the nearest 5, and 4) BMITrunc is the BMI with a fractional amount truncated.

#Data set:
data A15011.A11_health;
   input Subj : $3.
         Height
         Weight;
datalines;
001 68 155
003 74 250
004 63 110
005 60 95
;
#Solution:
data A15011.A11_health1;
set A15011.A11_health;
BMI = (Weight/2.2) / (Height*.0254)**2;
BMIRound = round(BMI);
BMIRound_tenth = round(BMI,.1);
BMIGroup = round(BMI,5);
BMITrunc = int(BMI);
run;
Proc print data=A15011.A11_health1;
run;

#Output:



# Explanation and learning:
As seen in the previous posts, first we are sub-setting the data set from health to health1. Then we use the formula for BMI which is defined as the weight in kilograms divided by the height (in meters) squared. Then we use the round function with (.1) which denotes the nearest tenth and vice versa.

6. Working with Character function

In this post we will see character strings, take strings apart and put them back together again, and remove selected characters from a string. We can remove classes of characters, such as digits, punctuation marks, or space characters and even we can match between the two characters. Lets see this by some examples.

#Problem:
Using the data set Mixed, we want to the create following new variables:
a. NameLow – Name in lowercase
b. NameProp – Name in proper case
c. NameHard – Name in proper case without using the PROPCASE function

#Data set:
data A15011.A11_mixed;
   input Name & $20. ID;
datalines;
Daniel Fields  123
Patrice Helms  233
Thomas chien  998
;
Proc print data=A15011.A11_mixed;
run;

#Solution:
data A15011.A11_mixed1;
set A15011.A11_mixed;
length First Last $ 15 NameHard $ 20;
NameLow = lowcase(Name);
NameProp = propcase(Name);
First = lowcase(scan(Name,1,' '));
Last = lowcase(scan(Name,2,' '));
substr(First,1,1) = upcase(substr(First,1,1));
substr(Last,1,1) = upcase(substr(Last,1,1));
NameHard = catx(' ',First,Last);
drop First Last;
run;

#Output:



# Learning:
In this program we learned two new SAS functions called lowcase and Propcase. Also we used the substr function and how to use them in the SAS program.

7. Arrays in SAS

SAS arrays are a collection of elements (usually SAS variables) that allow you to write SAS statements referencing this group of variables. SAS arrays are different from arrays in many other programming languages. They do not hold values, and they convenient manner. In this post we can see some problem based on arrays.

#Problem:
Using the SAS data set Nines, create a SAS data set, where all values of 999 are replaced by SAS missing values. Do this without explicitly naming the numeric variables in data set Nines.

#Data set:
data A15011.A11_nines;
   infile datalines missover;
   input x y z (Char1-Char3)(:$1.) a1-a5;
datalines;
1 2 3 a b c 99 88 77 66 55
2 999 999 d c e 999 7 999
10 20 999 b b b 999 999 999 33 44
;
proc print data=A15011.A11_nines; run;

#Solution:   
data A15011.A11_nines1;
set A15011.A11_nines;
array nums{*} _numeric_;
do i = 1 to dim(nums);
if nums{i} = 999 then
call missing(nums{i});
end;
drop i;
run;
proc print data=A15011.A11_nines1;
run;

#Output:




#Learning :
In this program we get the idea about array and how it works in SAS. We used the do loop and dim function. Here we called missing value wherever 999 is present in the data set. 

8. Listing the observation using proc print

In this post we will see how to list the observations in a SAS data set using the PRINT procedure (PROC PRINT). Also we add some options and statements to this procedure to
allow you more control over what is displayed.

#Problem:
We want to list first 10 observations in data set Blood. Include only the variables Subject, WBC (white blood cell), RBC (red blood cell), and Chol. Label the last three variables “White Blood Cells,” “Red Blood Cells,” and “Cholesterol,” respectively. Omit the Obs column, and place Subject in the first column.

Blood data set: https://www.dropbox.com/s/9wq9gdqk99981n3/blood.txt?dl=0

#Solution:
proc print data=learn.blood(obs=10) label;
id Subject;
var WBC RBC Chol;
label WBC = 'White Blood Cells'
RBC = 'Red Blood Cells'
Chol = 'Cholesterol';
run;

#Output:




#Explanation and learning:
In the proc print step we are saying to the SAS that print first 10 observation alone along with the labels. Also we make the subject as the first column by using ID keyword. By giving the label for each variable SAS print the label name instead of the variable name in the output.

9. Customizing your reports

Although you can customize the output produced by PROC PRINT, there are times when you need a bit more control over the appearance of your report. PROC REPORT was
developed to fit this need. Not only can you control the appearance of every column of
your report, you can produce summary reports as well as detail listings. Lets see using PROC Report in the examples.

#Problem:
By using the same blood data set fro the previous post we want to produce a summary report showing the average WBC and RBC count for each value of Gender as well as an overall average.

#Solution:
title "Statistics from BLOOD by Gender";
proc report data=A15011.A11_blood nowd headline;
column Gender WBC RBC;
define Gender / group width=6;
define WBC / analysis mean "Average WBC"
width=7 format=comma6.0;
define RBC / analysis mean "Average RBC"
width=7 format=5.2;
rbreak after / dol summarize;
run;
quit;


#Output:





#Learning:
The title statement tells SAS to print the output with the given title. Also we use tell the SAS as how much the width we need for the column and what format the output should look like.