{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python for SAS Users" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For years I used SAS® software in my professional career. I have always been impressed with its flexibility, its ability to manage large data sets and its ability to take input from just about any source. These characteristics help to explain its ubiquity in businessed throghout the world. In the early days of data analysis business users had few choices for tools when it came to doing ad-hoc analysis. \n", "\n", "One of the tools available then was Base SAS® software. For clarity, we will refer to SAS and Base SAS as the language as opposed to the company, SAS Institute. Back then, there was no concept of self-serve, so users were mostly left to queue their requests for analysis and reports to a central IT group. Eventually, a few intrepid users discovered that SAS software was used for mainframe capacity planning. Mainframes were the dominate systems back then, and their costs were large enough to warrant the practice of analyzing utilization. SAS was the primary software used for this activity. CEO’s needed to know when they were obliged to deliver a substantial capital expenditure check to IBM. \n", "\n", "By taking matters into their own hands users learned the mechanics of submitting SAS batch jobs (no interactive processing back then) and soon discovered they too could access data, munge it, and produce the sorts of reports and analysis that had meaningful impacts. As the number of computing platforms expanded thought the 1980’s and 1990’s SAS became available for them as well. All of which lead to a substantial number of SAS users.\n", "\n", "All of this sounds quaint in light of today’s ability to visit a web page and by simply clicking a few buttons, you can spin-up a cluster of hundreds or even thousands of machines with an enormous number of open-source (and proprietary as well) software components. All of this is available in a matter of minutes by just using credit-cards. A lot has changed since back then. And that’s my motivation to write these examples, in the spirit of learning additional ways to analyze data. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Why Python\n", "\n", "There are plenty of substantive open source software projects out there for data scientists, so why choose Python? After all, there is R. R is a robust and well-supported language written initially by statistician for statisticians. The view is not to promote one solution over the other. The goal is to illustrate how the addition of Python to a SAS user’s skill set can broaden ones range of capabilities. And besides, Bob Muenchen has already written, R for SAS and SPSS Users.\n", "\n", "Python has its heritage in scientific and technical computing domains and it has a compact syntax. The latter making for a relatively easy language to learn while the former means it scales to offer good performance with massive data volumes. This is one of the reasons why Google uses it so extensively and has developed an outstanding tutorial for programmers." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A quick-start\n", "Another aspect both languages have in common is the wealth of information available on the web. \n", "\n", "You would think having a plethora of content available it is straightforward proposition to learn a new language. But, at times I experienced information overload. As I worked though examples, I was not sure until an good investment of time if what I was learning was applicable to my learning objectives. \n", "\n", "Sure there is learning for leaning’s sake. But not every tutorial or text I read was fruitful, \n", "however, most were. It was not until later in this endeavor that I realized I needed a specific \n", "context for ingesting new information. \n", "\n", "Like most people, I want fast results. And like most SAS users, I have developed a mental model for \n", "data analysis focused on a series of iterable steps.\n", "\n", "What I was lacking was someone to identify both the content to utilize as well as the order in which it should be consumed. I wanted to initially invest time in just those topics that I needed before getting on with the task of data analysis. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Chapter orginization\n", "\n", "These chapters are meant to be read in order as they start with foundational concepts used\n", "to build up more complex ideas. The chapters are:\n", "\n", " 1. Introduction (This chapter)\n", " 2. Python Data Sctructures\n", " 3. Python Data Types and Formatting\n", " 4. Pandas, Part 1\n", " a. Read from .csv \n", " b. Inspection \n", " c. Missing Data Detection \n", " d. Missing Data Replacement\n", " 5. Pandas, Part 2\n", " a. Slicing \n", " b. Dicing\n", " c. Subsetting\n", " 6. Understanding Indexes\n", " 7. Understanding Datetime Arithmetic\n", " 8. Panda Readers for Data Input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Python for SAS Users Approach\n", "\n", "\n", "A philosophical word (or two) about the merits of Python and SAS as languages. From my perspective, it is simply a question of finding the right tool for the job. Both languages have advantages and disadvantages. And since they are programming languages, their designers had to make certain tradeoffs which can manifest themselves as features or quirks, depending on one’s perspective. \n", "\n", "The goal is to provide a quick start for users already familiar with the SAS lanaguage and enable them to become familiar with Python. The choice of which tool to utilize typically comes down to a combination of what you as a user are familiar with and the context of the problem being solved." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The approach taken is to introduce a concept(s) in Python with a description of how the program works followed by a code cell for the Python program. This is then followed by an example program in the language of SAS to present a compare and constrast approach. Not every Python example has an analog SAS example. \n", "\n", "The Python code examples will always be inside a code cell within this notebook. The comparison SAS language example is contained inside a Raw NBConvert cell. To make the examples easy to follow, where reasonable, I have written the output to the SAS log. All of the SAS code examples are here ***github url goes here***. Their names follow the convention:\n", "\n", "c#_python_comment_header.sas\n", "\n", "where:\n", " * # is the chapter number from this notebook\n", " * python_comment_header is the comment block beginning the Python example\n", " * .sas is the file extension \n", "\n", "The SAS language programs were written and verified with Version: 3.2.2.0.15680 of the WPS Workbench for Windows. World Programming System offers a SAS language interpreter and can be reached at: https://worldprogramming.com/us/.\n", "\n", "This approach is illustrated by the next 3 cells below. The analog SAS program is called C1_Python_for_loop.sas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Comparing Python and SAS code fragments\n", "The list of numbers contained inside the square brackets [ ] make up the elements in a Python list. In Python, a list is a data structure that holds an arbitrary collection of items. i is an integer used as the index for the for loop. product holds the integer value from \n", "the arithmetic assignment of product * i Finally, the print() \n", "method writes the output. The same program is written in SAS as shown below." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The product is: 4224\n" ] } ], "source": [ "# Python for loop\n", "\n", "numbers = [2, 4, 6, 8, 11]\n", "product = 1\n", "for i in numbers:\n", " product = product * i \n", "print('The product is:', product)" ] }, { "cell_type": "raw", "metadata": { "collapsed": false }, "source": [ "4 data _null_;\n", "5 \n", "6 retain product 1;\n", "7 do i = 2 to 8 by 2, 11;\n", "8 product=product*i;\n", "9 end;\n", "10 \n", "11 put 'The product is: ' product;\n", "\n", "The product is: 4224" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python Terminology\n", "\n", "Python permits an object-oriented programming model. SAS is a procedural programming language. These examples use a procedural programming model for Python given the goal is to map SAS\n", "programming constructs into Python. \n", "\n", "This object-oriented programming model provides a number of classes with objects \n", "being instances of the class. The Python program in the cell below illustrates the int class (integers). Variable x is an instance (object) of the int class. You can execute help(int) to read more.\n", "\n", "Objects are said to belong to a class. Variables that belong to a class or objects are strictly \n", "speaking, refered to as fields. Objects have capabilities belonging to the class and are called \n", "methods(). \n", "\n", "My early experiences was that the object types I created were not always obvious from the code context. I neeed to know what type of object was being created. The type() method returns the object's type as illustrated in the cell below.\n", "\n", "Python has a number of built-in functions and types that are always available which are documented \n", " here. Later on, we will see how Python expands its capabilities through importing packages (libraries)." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "201\n", "\n" ] } ], "source": [ "# x is an instance of the int class\n", "\n", "x = 201;\n", "print(x)\n", "print(type(x))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Object References\n", "\n", "Consider the program in the cell below. Don't worry about the syntax for now. a_list is a Python list object. The a_list list is copied to another list object using the assignment:\n", "\n", "````python\n", " b_list = a_list\n", "````\n", "It turns out that while a_list and b_list are equivalent, they both point to the same memory location. In other words, b_list refers to the object a_list and does not represent the object itself. \n", "\n", "The program statement:\n", "\n", "````python\n", " del a_list[0]\n", "````\n", "removes the first item from the a_list list object. When we print the list objects, you see how both have the first item removed. The effect is subtle, but not one you will likely encounter a great deal. But certainly a subtly to be aware of." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a_list is: ['onyx', 'zebra', 'money', 'lemur']\n", "b_list is: ['onyx', 'zebra', 'money', 'lemur']\n" ] } ], "source": [ "# object reference example\n", "\n", "a_list = ['elephant', 'onyx', 'zebra', 'money', 'lemur']\n", "\n", "# b_list is another name pointing to the same object\n", "b_list = a_list\n", "\n", "# remove the first item in a_list\n", "del a_list[0]\n", "\n", "# print both lists\n", "print('a_list is:', a_list)\n", "print('b_list is:', b_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Ledgibility, Indentation, and Spelling matter\n", "\n", "To quote, Eric Raymond, \"A language that makes it hard to write elegant code makes it \n", "hard to write good code.\" From his essay, entitled, \"Why Python\", located at: \n", "\n", "The Python program in the cell below is the same as the one 6 cells above, with one exception. The line after the for block is *not* indented. This results in the interpreter raising the error:\n", "\n", "IndentationError: expected an indented block\n", "\n", "Once you get over the shock of how Python imposes the indentation requirements, you will come to see how this is an important feature used to create legible and easy-to-understand code. \n", "\n", "Notice also there appear to be no symbols used to end a program statement. The end-of-line character is used to end a Python statement. This also helps to enforce ledgibility by keeping each statement on a separate physical line.\n", "\n", "Coincidently, like SAS, Python will also honor a semi-colon as an end of statement terminator. However, you rarely see this. That's because multiple statements on the same physical line is considered an affront to program ledgibility. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "ename": "IndentationError", "evalue": "expected an indented block (, line 6)", "output_type": "error", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m6\u001b[0m\n\u001b[1;33m product = product * i\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m expected an indented block\n" ] } ], "source": [ "# Python for loop_2\n", "\n", "numbers = [2, 4, 6, 8, 11]\n", "product = 1\n", "for i in numbers:\n", "product = product * i \n", "print('The product is:', product)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Line continuation symbol\n", "\n", "Should you find you have a line of code that needs to extend past the physical line (i.e. wrap), then use the backslash (\\\\). This causes the Python interpreter to ignore the physical end-of-line terminator on the current line and continuing scanning for the next end-of-line terminator." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The product is: 607711104\n" ] } ], "source": [ "# Line continuation \n", "\n", "numbers = [2, 4, 6, 8, 11, 13, 21, \\\n", " 17, 31]\n", "product = 1\n", "for i in numbers:\n", " product = product * i \n", "print('The product is:', product)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Spelling\n", "\n", "Of course, the incorrect spelling of keywords is a source of error. Unlike SAS, in Python, object names are case sensetive." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "ename": "NameError", "evalue": "name 'x' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mX\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m201\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'x' is not defined" ] } ], "source": [ "# Python object names are case sensetive\n", "\n", "X = 201\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SAS keywords and variable names are case insensetive. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " 4 data _null_;\n", " 5 \n", " 6 X = 201;\n", " 7 put x ;\n", "\n", " 201" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Finally, a word about name choices. Names should be descriptive because more than likely you will be one who has to re-read and understand tomorrow the code you write today. As with any language, it is a good practice to avoid language keywords for object names." ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [Root]", "language": "python", "name": "Python [Root]" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }