{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Mapping Inequality in Baltimore\n", "Contributers : Sarah Agarrat and Richard Marciano " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction \n", "\n", "After the 1929 Stock Market Crash, thousands of Americans were in danger of home foreclosure. To address this problem and stabilize the market, The Home Owners Loan Coperation (HOLC) was created under the Rooselvelt Administration to asses credibility of families in order to decide to refinance their homes.\n", " \n", "The HOLC created area descriptions and maps to \"grade\" neighborhoods based on racial/ethnic presence, the income of the residents, and environmental factors to determine their \"financial risk\". A grade of an 'A' (red) , was given to an area characterized as undesirable due to detrimental influences and unfavorable infiltration. Grade 'B' (yellow) areas were characterized by infiltration of a \"lower grade population\", \"lacking homogeniety\", and age of the neighborhoods, grade 'C' (blue) areas were completely developed, and 'grade 'D' (green) areas were characterized as \"hot spots\" that weren't fully built up yet and contained homogeinety. This is called __*redlining*__, denying financial services based on race/ethnic background.\n", "\n", " \"Baltimore\n", "\n", "Learn more the Mapping Inequality Project [here.](https://dsl.richmond.edu/panorama/redlining/#loc=4/36.71/-96.93&opacity=0.8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook demonstrates computational techniques using attributes from the HOLC Baltimore records. The topics covered are:\n", "- Aquiring Data\n", "- Data Cleaning and Data Preperation\n", "- Data Manipulation\n", "- Exploratory Data Analysis and Visualization " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aquiring Data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The fields of each record are characteristics of a graded section indicated by the security grade map seen above. These fields have been transcribed and stored in a __comma separated value (csv)__ format.\n", "\n", "Using the pandas library, we can create a data frame from the csv. A __data frame__ is a table where every row represents a single unique object, called an __entity__, and every column represents characteristics of these objects, called __attributes__." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Importing the Data and Creating a Data Frame" ] }, { "cell_type": "code", "execution_count": 675, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
FormStateCitySecurity_GradeArea_NumberTerrain_DescriptionFavorable_InfluencesDetrimental_InfluencesINHABITANTS_TypeINHABITANTS_Annual_Income...INHABITANTS_Population_IncreaseINHABITANTS_Population_DecreaseINHABITANTS_Population_StaticBUILDINGS_TypesBUILDINGS_ConstructionBUILDINGS_AgeBUILDINGS_RepairTen_Fifteen_DesirabilityRemarksDate
0NS FORM-8 6-1-37MarylandBaltimoreA2RollingFairly new suburban area of homogeneous charac...NoneSubstantial Middle Class$3000 - 5,000...FastNaNNaNDetached an row housesBrick and frame1 to 10 yearsGoodUpwardA recent development with much room for expans...May 4,1937
1NS FORM-8 6-1-37MarylandBaltimoreA1UndulatingVery nicely planned residential area of medium...NoneExecutives, Professional Menover $5000...Moderately FastNaNNaNSingle family detachedBrick and Stone12 yearsVery goodUpwardMostly fee properties. A few homes valued at $...May 4,1937
2NS FORM-8 6-1-37MarylandBaltimoreA3RollingGood residential area. Well planned.Distance to CityExecutives, Professional Men3500 - 7000...Moderately FastNaNNaNOne family detachedBrick, Stone, and Frame1 to 20 yearsGood to excellentUpwardPrincipally fee property. This section lies in...May 4,1937
\n", "

3 rows × 26 columns

\n", "
" ], "text/plain": [ " Form State City Security_Grade Area_Number \\\n", "0 NS FORM-8 6-1-37 Maryland Baltimore A 2 \n", "1 NS FORM-8 6-1-37 Maryland Baltimore A 1 \n", "2 NS FORM-8 6-1-37 Maryland Baltimore A 3 \n", "\n", " Terrain_Description Favorable_Influences \\\n", "0 Rolling Fairly new suburban area of homogeneous charac... \n", "1 Undulating Very nicely planned residential area of medium... \n", "2 Rolling Good residential area. Well planned. \n", "\n", " Detrimental_Influences INHABITANTS_Type \\\n", "0 None Substantial Middle Class \n", "1 None Executives, Professional Men \n", "2 Distance to City Executives, Professional Men \n", "\n", " INHABITANTS_Annual_Income ... INHABITANTS_Population_Increase \\\n", "0 $3000 - 5,000 ... Fast \n", "1 over $5000 ... Moderately Fast \n", "2 3500 - 7000 ... Moderately Fast \n", "\n", " INHABITANTS_Population_Decrease INHABITANTS_Population_Static \\\n", "0 NaN NaN \n", "1 NaN NaN \n", "2 NaN NaN \n", "\n", " BUILDINGS_Types BUILDINGS_Construction BUILDINGS_Age \\\n", "0 Detached an row houses Brick and frame 1 to 10 years \n", "1 Single family detached Brick and Stone 12 years \n", "2 One family detached Brick, Stone, and Frame 1 to 20 years \n", "\n", " BUILDINGS_Repair Ten_Fifteen_Desirability \\\n", "0 Good Upward \n", "1 Very good Upward \n", "2 Good to excellent Upward \n", "\n", " Remarks Date \n", "0 A recent development with much room for expans... May 4,1937 \n", "1 Mostly fee properties. A few homes valued at $... May 4,1937 \n", "2 Principally fee property. This section lies in... May 4,1937 \n", "\n", "[3 rows x 26 columns]" ] }, "execution_count": 675, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# loads the pandas library \n", "import pandas as pd\n", "\n", "# creates data frame named df by reading in the Baltimore csv\n", "df = pd.read_csv(\"AD_Data_BaltimoreProject.csv\")\n", "df.head(n=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "In this form, `SECUIRITY GRADE` has value A and `AREA NO.` has value 2. This form is located in the first row with index 0 in the data frame." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Cleaning and Preparation " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After obtaining our data, we need to clean it to prepare for data analysis. This includes handling similiar text values and making sure a column of interest contains a single attribute." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Handling Text Values with Similar Meanings " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `INHABITANTS_Foreignborn` varaible indicates whether there are foreigners in a neighborhood section. Observe that different forms used 'No' or 'None' to indicate there are no foreigners and 'Small' , 'Very few' , and 'Mixture' are various ways of indicating there were foreigners. `NaN` indicates the value in the form is missing." ] }, { "cell_type": "code", "execution_count": 676, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 None\n", "2 None\n", "3 None\n", "4 None\n", "5 NaN\n", "6 No\n", "7 No\n", "8 No\n", "9 Small\n", "10 Very few\n", "11 No\n", "12 No\n", "13 No\n", "14 No\n", "15 Mixture\n", "Name: INHABITANTS_Foreignborn, dtype: object" ] }, "execution_count": 676, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# selects rows with indices between 0 to 15 included of the 'INHABITANTS_Foreignborn' column\n", "df.ix[0:15,'INHABITANTS_Foreignborn']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since columns with categorized values are easier to analyze, we are going to transform this column to indicate whether there are foreigners or not. In Python, `None` is a special keyword that indicates the cell has a null value. Therefore, we will alter all the 'None' values to 'No' and every other value that indicates there are to 'Yes'." ] }, { "cell_type": "code", "execution_count": 677, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 No\n", "2 No\n", "3 No\n", "4 No\n", "5 Yes\n", "6 No\n", "7 No\n", "8 No\n", "9 Yes\n", "10 Yes\n", "11 No\n", "12 No\n", "13 No\n", "14 No\n", "15 Yes\n", "Name: INHABITANTS_Foreignborn, dtype: object" ] }, "execution_count": 677, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# replaces the values of 'None' with 'No'\n", "df['INHABITANTS_Foreignborn'] = df['INHABITANTS_Foreignborn'].replace('None', 'No')\n", "\n", "# replaces all other values with 'Yes'\n", "for value in df['INHABITANTS_Foreignborn']:\n", " if value != 'No' and value != 'NaN':\n", " df['INHABITANTS_Foreignborn'] = df['INHABITANTS_Foreignborn'].replace(value, 'Yes')\n", "\n", "df.ix[0:15,'INHABITANTS_Foreignborn']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Detrimental_Influences` are descriptions of a region's undesiriable characteristics. Notice in this case that there are multiple variations of the meaning of 'No' to be replaced. " ] }, { "cell_type": "code", "execution_count": 678, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "0 None\n", "1 None\n", "2 Distance to City\n", "3 None\n", "4 None\n", "5 NaN\n", "6 No.\n", "7 None\n", "8 Few streets of property in poor condition\n", "9 None\n", "10 None\n", "11 Built on filled ground.\n", "12 None\n", "13 None\n", "14 Distance to center of city\n", "15 None\n", "Name: Detrimental_Influences, dtype: object" ] }, "execution_count": 678, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'Detrimental_Influences']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To handle the multiple words to be replaced we can use an __array__, a list that holds a fixed number of values of the same type, to store several strings. Then we can replace each occurence in `Detrimental_Influences` by iterating through the array and using the `replace()` function." ] }, { "cell_type": "code", "execution_count": 679, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# declares an array called 'no_words' containing strings that all mean 'No'\n", "no_words = ['No.','no', 'none', 'None']\n", "\n", "# interates through no_words and replaces each occurence in Detrimental_Influences\n", "for word in no_words:\n", " df['Detrimental_Influences'] = df['Detrimental_Influences'].replace( word , 'No')" ] }, { "cell_type": "code", "execution_count": 680, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 No\n", "2 Distance to City\n", "3 No\n", "4 No\n", "5 NaN\n", "6 No\n", "7 No\n", "8 Few streets of property in poor condition\n", "9 No\n", "10 No\n", "11 Built on filled ground.\n", "12 No\n", "13 No\n", "14 Distance to center of city\n", "15 No\n", "Name: Detrimental_Influences, dtype: object" ] }, "execution_count": 680, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'Detrimental_Influences']" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "We need to do these same operations for `INHABITANTS_Negro`, whether residents are African American, and `INHABITANTS_Infiltration`, which refers to if the area is being infiltrated. __Functions__ are procedures that perform specific tasks. In Python, we can create our own functions or used built-in functions such as `replace()`. __Parameters__ are variables that are defined in the function definition. __Arguments__ are the values passed into a function.\n", "\n", "The `replace_values` function has three parmeters : `attribute`, `new_word`, and `words_to_replace`." ] }, { "cell_type": "code", "execution_count": 681, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# this function iterates through an array of words to be replaced and replaces each occurence in the attribute \n", "# with the new word\n", "def replace_values(attribute, new_word, words_to_replace):\n", " for word in words_to_replace:\n", " df[attribute] = df[attribute].replace(word, new_word) \n", "\n", "\n", "replace_values('INHABITANTS_Negro', 'No', no_words)\n", "replace_values('INHABITANTS_Infiltration', 'No', no_words)" ] }, { "cell_type": "code", "execution_count": 682, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 No\n", "2 No\n", "3 No\n", "4 No\n", "5 NaN\n", "6 No\n", "7 No\n", "8 No\n", "9 NaN\n", "10 No\n", "11 No\n", "12 No\n", "13 No\n", "14 No\n", "15 People from C-1\n", "Name: INHABITANTS_Infiltration, dtype: object" ] }, "execution_count": 682, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'INHABITANTS_Infiltration']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we do the same procedure for words meaning 'few', however we could have made these columns have two categories, 'yes' or 'no', and indicate in our data analysis the alterations to our data." ] }, { "cell_type": "code", "execution_count": 683, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Various words meaning small \n", "small_words = ['Nominal','nominal', 'Small','small','Minimum', 'minimum','minimal', 'Very few']\n", "\n", "replace_values('INHABITANTS_Negro', 'Few', small_words)\n", "replace_values('INHABITANTS_Infiltration', 'Few', small_words)" ] }, { "cell_type": "code", "execution_count": 684, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 No\n", "2 No\n", "3 No\n", "4 No\n", "5 NaN\n", "6 No\n", "7 No\n", "8 No\n", "9 NaN\n", "10 No\n", "11 No\n", "12 No\n", "13 No\n", "14 No\n", "15 People from C-1\n", "Name: INHABITANTS_Infiltration, dtype: object" ] }, "execution_count": 684, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'INHABITANTS_Infiltration']" ] }, { "cell_type": "code", "execution_count": 685, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 No\n", "1 No\n", "2 No\n", "3 No\n", "4 No\n", "5 NaN\n", "6 No\n", "7 No\n", "8 No\n", "9 No\n", "10 No\n", "11 No\n", "12 No\n", "13 No\n", "14 No\n", "15 No\n", "Name: INHABITANTS_Negro, dtype: object" ] }, "execution_count": 685, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'INHABITANTS_Negro']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can clean up the values of `INHABITANTS_Population_Increase`, how the population is increasing in an area, by choosing standard categories for the rate the population." ] }, { "cell_type": "code", "execution_count": 686, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 Fast \n", "1 Moderately Fast\n", "2 Moderately Fast\n", "3 Slowly\n", "4 Moderately Fast\n", "5 NaN\n", "6 NaN\n", "7 Slowly\n", "8 Moderately Fast\n", "9 Moderately Fast\n", "10 NaN\n", "11 Slowly\n", "12 Slowly\n", "13 Moderately\n", "14 Slowly\n", "15 Fast \n", "Name: INHABITANTS_Population_Increase, dtype: object" ] }, "execution_count": 686, "metadata": {}, "output_type": "execute_result" } ], "source": [ " df.ix[0:15,'INHABITANTS_Population_Increase']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will define rates of the population as very slowly, slowly, moderately, moderately fast, fast based on the data." ] }, { "cell_type": "code", "execution_count": 687, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# defines values to replace in the table \n", "very_slowly = ['Very Slowly', 'very slowly', 'very Slowly']\n", "slowly = ['slowly', 'fairly slowly']\n", "moderately = ['moderately']\n", "moderately_fast = ['Moderately Fast', 'moderately Fast', 'moderately fast']\n", "fast = ['very fast', 'Very Fast', 'fast']\n", "\n", "# applies function to obtain our new values \n", "replace_values('INHABITANTS_Population_Increase', 'Very slowly', very_slowly)\n", "replace_values('INHABITANTS_Population_Increase', 'Slowly', slowly)\n", "replace_values('INHABITANTS_Population_Increase', 'Moderately', moderately )\n", "replace_values('INHABITANTS_Population_Increase', 'Moderately fast', moderately_fast)\n", "replace_values('INHABITANTS_Population_Increase', 'Moderately fast', moderately_fast)\n", "replace_values('INHABITANTS_Population_Increase', 'Fast', fast)\n" ] }, { "cell_type": "code", "execution_count": 688, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 Fast \n", "1 Moderately fast\n", "2 Moderately fast\n", "3 Slowly\n", "4 Moderately fast\n", "5 NaN\n", "6 NaN\n", "7 Slowly\n", "8 Moderately fast\n", "9 Moderately fast\n", "10 NaN\n", "11 Slowly\n", "12 Slowly\n", "13 Moderately\n", "14 Slowly\n", "15 Fast \n", "Name: INHABITANTS_Population_Increase, dtype: object" ] }, "execution_count": 688, "metadata": {}, "output_type": "execute_result" } ], "source": [ " df.ix[0:15,'INHABITANTS_Population_Increase']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### String Parsing to Extract Data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some of the cities have corresponding suburbs followed by a dash. We can extract the suburbs and create a new column using `str.split()`." ] }, { "cell_type": "code", "execution_count": 689, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "16 Baltimore \n", "17 Baltimore - Dundalk\n", "18 Baltimore\n", "19 Baltimore - Metropolitan\n", "20 Baltimore\n", "21 Baltimore - Metropolitan\n", "22 Baltimore\n", "23 Baltimore - Sub. Burton\n", "24 Baltimore - Sub. Mt. Washington Summit\n", "25 Baltimore - Sub. Villahove\n", "26 Baltimore - Sub. Colonial Park\n", "27 Baltimore - Sub. Linthicum Heights\n", "28 Baltimore\n", "29 Baltimore\n", "30 Baltimore\n", "Name: City, dtype: object" ] }, "execution_count": 689, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[16:30,'City']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " A new data frame seperate is created with two columns seperated based on `str.split`, where `n=1` indicates the string is split once. We create two new attributes in the original data frame, `City_clean` and `Suburb`. Then we drop the old `City` city column and rename our new `City` attribute." ] }, { "cell_type": "code", "execution_count": 690, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [], "source": [ "# creates a new data frame that splits the values in the orginal data frame on the '-' character \n", "newdf = df[\"City\"].str.split('-', n = 1, expand = True) \n", "newdf.head()\n", "\n", "# creates two new columns \n", "df['City_clean'] = newdf[0]\n", "df['Suburb'] = newdf[1]\n", "\n", "# removes the old column\n", "df.drop([\"City\"], axis = 1, inplace = True) \n", "\n", "# renames as 'City'\n", "df.rename(index=str, columns={\"City_clean\": \"City\"});" ] }, { "cell_type": "code", "execution_count": 691, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Suburb
16None
17Dundalk
18None
19Metropolitan
20None
21Metropolitan
22None
23Sub. Burton
24Sub. Mt. Washington Summit
25Sub. Villahove
26Sub. Colonial Park
27Sub. Linthicum Heights
28None
29None
30None
\n", "
" ], "text/plain": [ " Suburb\n", "16 None\n", "17 Dundalk\n", "18 None\n", "19 Metropolitan\n", "20 None\n", "21 Metropolitan\n", "22 None\n", "23 Sub. Burton\n", "24 Sub. Mt. Washington Summit\n", "25 Sub. Villahove\n", "26 Sub. Colonial Park\n", "27 Sub. Linthicum Heights\n", "28 None\n", "29 None\n", "30 None" ] }, "execution_count": 691, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[16:30,['Suburb']]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "The `BUILDINGS_Age` attribute represents the range of the age of the buildings in a region. Notice the range is given is given as a string of text. For purpose of analysis, we would like to extract the upper end of the range and create a column of numeric values." ] }, { "cell_type": "code", "execution_count": 692, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "0 1 to 10 years\n", "1 12 years\n", "2 1 to 20 years\n", "3 10 years\n", "4 1 to 20 years\n", "5 NaN\n", "6 25 years\n", "7 15 to 25 years\n", "8 15 years\n", "9 5 to 25 years\n", "10 20 years\n", "11 5 to 10 years\n", "12 10 years\n", "13 25 years\n", "14 1 to 20 years\n", "15 6 to 25 years\n", "Name: BUILDINGS_Age, dtype: object" ] }, "execution_count": 692, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,'BUILDINGS_Age']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observe that the numeric value at the end of the range is always the last number followed by the string `years`. We use specific string patterns called __regular expressions (regex)__ and `str.extract()` to create a new attribute called `max_building_age`." ] }, { "cell_type": "code", "execution_count": 693, "metadata": { "collapsed": false }, "outputs": [], "source": [ "df['max_building_age'] = df['BUILDINGS_Age'].str.extract('(\\d+)(?!.*\\d)', expand=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The regular expression in this example is `(\\d+)(?!.*\\d)` and was tested using [Pythex](https://pythex.org/), a regex editor. We could have imported `re` , Python's regular expression library, to perform the same task, however this notebook consistenly uses `str()` functions." ] }, { "cell_type": "code", "execution_count": 694, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BUILDINGS_Agemax_building_age
01 to 10 years10
112 years12
21 to 20 years20
310 years10
41 to 20 years20
5NaNNaN
625 years25
715 to 25 years25
815 years15
95 to 25 years25
1020 years20
115 to 10 years10
1210 years10
1325 years25
141 to 20 years20
156 to 25 years25
\n", "
" ], "text/plain": [ " BUILDINGS_Age max_building_age\n", "0 1 to 10 years 10\n", "1 12 years 12\n", "2 1 to 20 years 20\n", "3 10 years 10\n", "4 1 to 20 years 20\n", "5 NaN NaN\n", "6 25 years 25\n", "7 15 to 25 years 25\n", "8 15 years 15\n", "9 5 to 25 years 25\n", "10 20 years 20\n", "11 5 to 10 years 10\n", "12 10 years 10\n", "13 25 years 25\n", "14 1 to 20 years 20\n", "15 6 to 25 years 25" ] }, "execution_count": 694, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:15,['BUILDINGS_Age','max_building_age']]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ " The `Date`, the date indicated on the form, has three attributes with the pattern given by **month day, year**. As previously stated, we would like to have a single attribute per column." ] }, { "cell_type": "code", "execution_count": 695, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Date
0May 4,1937
1May 4,1937
2May 4,1937
3May 4,1937
\n", "
" ], "text/plain": [ " Date\n", "0 May 4,1937\n", "1 May 4,1937\n", "2 May 4,1937\n", "3 May 4,1937" ] }, "execution_count": 695, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:3,['Date']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can seperate this column into three columns: `Month`, `Day`, and `Year` using `str.extract()` and regex patterns\n", "`(\\d\\d\\d\\d)` to indicate four digit year, `(\\d)` to indicate a single digit day, and ` [A-Z]\\w{0,}` to indicate __aplhanumeric__ text to extract the month. Note that regex can also be used to reformat the date column." ] }, { "cell_type": "code", "execution_count": 696, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
DateMonthDayYear
0May 4,1937May41937
1May 4,1937May41937
2May 4,1937May41937
3May 4,1937May41937
\n", "
" ], "text/plain": [ " Date Month Day Year\n", "0 May 4,1937 May 4 1937\n", "1 May 4,1937 May 4 1937\n", "2 May 4,1937 May 4 1937\n", "3 May 4,1937 May 4 1937" ] }, "execution_count": 696, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# extracts the year \n", "df['Year'] = df['Date'].str.extract('(\\d\\d\\d\\d)', expand=True)\n", "\n", "# extracts day \n", "df['Day'] = df['Date'].str.extract('(\\d)', expand=True)\n", "\n", "# extracts month \n", "df['Month'] = df['Date'].str.extract('([A-Z]\\w{0,})', expand=True)\n", "\n", "df.ix[0:3,['Date','Month','Day','Year']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similar to `BUILDINGS_Age`, `INHABITANTS_Annual_Income`, the range of income of residents in a section, is a string of text and we would like to extract the numeric value at the end of the range." ] }, { "cell_type": "code", "execution_count": 697, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
INHABITANTS_Annual_Income
0$3000 - 5,000
1over $5000
23500 - 7000
3over $5000
4$3,500 - $10,000
5NaN
6over $4000
7over $5000
\n", "
" ], "text/plain": [ " INHABITANTS_Annual_Income\n", "0 $3000 - 5,000\n", "1 over $5000\n", "2 3500 - 7000\n", "3 over $5000\n", "4 $3,500 - $10,000\n", "5 NaN\n", "6 over $4000\n", "7 over $5000" ] }, "execution_count": 697, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:7,['INHABITANTS_Annual_Income']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observe that some values are located after '$', some inlcude '-', and others include ','.Since the pattern to extract the last numeric value varies, we use `str.replace()`, `str.extract`, and regex in a sequence of operations to create a new column `max_annual_income`." ] }, { "cell_type": "code", "execution_count": 698, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# replaces anything that is not a digit or ',' with empty space\n", "df['max_annual_income'] = df['INHABITANTS_Annual_Income'].str.replace('[^\\d(,)]',' ')" ] }, { "cell_type": "code", "execution_count": 699, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
max_annual_income
03000 5,000
15000
23500 7000
35000
43,500 10,000
5NaN
64000
75000
\n", "
" ], "text/plain": [ " max_annual_income\n", "0 3000 5,000\n", "1 5000\n", "2 3500 7000\n", "3 5000\n", "4 3,500 10,000\n", "5 NaN\n", "6 4000\n", "7 5000" ] }, "execution_count": 699, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:7,['max_annual_income']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We did not include the delimeter in the previous `str.replace()` operation because their positions would have been replaced by an empty space. Now we want to remove delimeters." ] }, { "cell_type": "code", "execution_count": 700, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# removes delimeter by replacing ',' with ''\n", "df['max_annual_income'] = df['max_annual_income'].str.replace('[(,)]','')" ] }, { "cell_type": "code", "execution_count": 701, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
max_annual_income
03000 5000
15000
23500 7000
35000
43500 10000
5NaN
64000
75000
\n", "
" ], "text/plain": [ " max_annual_income\n", "0 3000 5000\n", "1 5000\n", "2 3500 7000\n", "3 5000\n", "4 3500 10000\n", "5 NaN\n", "6 4000\n", "7 5000" ] }, "execution_count": 701, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:7,['max_annual_income']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can extract the last number." ] }, { "cell_type": "code", "execution_count": 702, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# extracts the second or last number \n", "df['max_annual_income'] = df['max_annual_income'].str.extract('(\\d+)(?!.*\\d)', expand=True)" ] }, { "cell_type": "code", "execution_count": 703, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
max_annual_income
05000
15000
27000
35000
410000
5NaN
64000
75000
\n", "
" ], "text/plain": [ " max_annual_income\n", "0 5000\n", "1 5000\n", "2 7000\n", "3 5000\n", "4 10000\n", "5 NaN\n", "6 4000\n", "7 5000" ] }, "execution_count": 703, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.ix[0:7,['max_annual_income']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Manipulation " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some aspects of __data manipulation__, altering data to make it easier to read or use, include sorting and grouping attributes and encoding categorical variables." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sorting and Grouping " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The values of `Area_Number` are out of order and we want these values to be sorted by `Security_Grade`. " ] }, { "cell_type": "code", "execution_count": 704, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Security_GradeArea_Number
0A2
1A1
2A3
3A4
4A5
5A6
6B1
7B2
8B3
9B4
10B5
\n", "
" ], "text/plain": [ " Security_Grade Area_Number\n", "0 A 2\n", "1 A 1\n", "2 A 3\n", "3 A 4\n", "4 A 5\n", "5 A 6\n", "6 B 1\n", "7 B 2\n", "8 B 3\n", "9 B 4\n", "10 B 5" ] }, "execution_count": 704, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# removes any additional spaces from Security_Grade\n", "df['Security_Grade'] = df['Security_Grade'].str.replace('[\\W]','')\n", "# converts 'Area_Number' from type object to type 'numeric'\n", "df['Area_Number'] = pd.to_numeric(df['Area_Number'])\n", "df.ix[0:10,['Security_Grade','Area_Number']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To do this, we created use the `sort_values()` function on the original data frame and reset the index. First, the data is sorted and grouped by `Security_Grade` and then `Area_Number` is sorted in increasing order." ] }, { "cell_type": "code", "execution_count": 705, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Security_GradeArea_Number
0A1
1A2
2A3
3A4
4A5
5A6
6B1
7B2
8B3
9B4
10B5
\n", "
" ], "text/plain": [ " Security_Grade Area_Number\n", "0 A 1\n", "1 A 2\n", "2 A 3\n", "3 A 4\n", "4 A 5\n", "5 A 6\n", "6 B 1\n", "7 B 2\n", "8 B 3\n", "9 B 4\n", "10 B 5" ] }, "execution_count": 705, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = df.sort_values(by=['Security_Grade', 'Area_Number'])\n", "# resets the index starting from 0\n", "df = df.reset_index(drop=True)\n", "df.ix[0:10,['Security_Grade','Area_Number']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Encoding Categorical Data" ] }, { "cell_type": "code", "execution_count": 706, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 Moderately fast\n", "1 Fast \n", "2 Moderately fast\n", "3 Slowly\n", "4 Moderately fast\n", "5 NaN\n", "6 NaN\n", "7 Slowly\n", "8 Moderately fast\n", "9 Moderately fast\n", "10 NaN\n", "11 Slowly\n", "12 Slowly\n", "13 Moderately\n", "14 Slowly\n", "15 Fast \n", "Name: INHABITANTS_Population_Increase, dtype: object" ] }, "execution_count": 706, "metadata": {}, "output_type": "execute_result" } ], "source": [ " df.ix[0:15,'INHABITANTS_Population_Increase']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exploratory Data Analysis and Visualization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The goal of __exploratory data analysis (EDA)__ is to explore attributes across multiple entities to decide what statistical or machine learning techniques to apply to the data. Visualizations are used to assist in understanding the data." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `.describe()` function summarizes a data frame column. Since the data type of `max_building_age` is currently type 'object', which in python is an indcator of type 'string', we have to first convert this attribute into a numeric value." ] }, { "cell_type": "code", "execution_count": 707, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "count 46\n", "unique 12\n", "top 25\n", "freq 9\n", "Name: max_building_age, dtype: object" ] }, "execution_count": 707, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['max_building_age'].describe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that `max_building_age` is numeric type, we see that `describe()` provides __summary statistics__ on this attribute." ] }, { "cell_type": "code", "execution_count": 708, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "count 46.000000\n", "mean 30.086957\n", "std 16.497577\n", "min 10.000000\n", "25% 20.000000\n", "50% 25.000000\n", "75% 40.000000\n", "max 65.000000\n", "Name: max_building_age, dtype: float64" ] }, "execution_count": 708, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# converts max_building age to numeric type\n", "df[\"max_building_age\"] = pd.to_numeric(df[\"max_building_age\"])\n", "df['max_building_age'].describe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can the same operations to `max_annual_income`." ] }, { "cell_type": "code", "execution_count": 709, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "count 46\n", "unique 12\n", "top 2500\n", "freq 8\n", "Name: max_annual_income, dtype: object" ] }, "execution_count": 709, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['max_annual_income'].describe()" ] }, { "cell_type": "code", "execution_count": 710, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "count 46.000000\n", "mean 3139.130435\n", "std 2009.806874\n", "min 1000.000000\n", "25% 1850.000000\n", "50% 2750.000000\n", "75% 4000.000000\n", "max 10000.000000\n", "Name: max_annual_income, dtype: float64" ] }, "execution_count": 710, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['max_annual_income'] = pd.to_numeric(df['max_annual_income'])\n", "df['max_annual_income'].describe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally we create some plots our data. A __scatter plot__ and a __bar chart__ are shown below." ] }, { "cell_type": "code", "execution_count": 734, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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\n4NGIOFPSqcBWEfEJSbsAFwEzgG1IDftTI+JFSYuAE0lVaT8E/i0ifjjc+Tvml/ceFqRz+b2z4XTo\n9AqN/vJ+g1ZkZi32Aj4MLJF0W047HTgTWCBpFrASOBwgIpZKWgAsI/UoOyEiXsz7fRQ4D5gAXJ0f\n9dDVtU5/yGwYfu9sOP1tccXA0t8WV4PPTVsCS0T8Ahjq9yb7DrHPF4AvrCV9MfDG6nJnZtZkNW+L\na3uvMDOzMafmbXHtqgozMxvbZs6E/farZVucA4tZp6v7XDN17ghR07Y4V4WZdbJWd1mt+/msEp7o\ny6xTtbrLat3PZyPyRF9mddfq4WPqfj6rjAOLWadqdZfVup/PKuPAYtapWt1lte7ns8q4jcWs09W9\nl1ade4V1mHV9SBdrRJ3/gP1lUZ1Wd1mt+/nsVXNV2Lqqzt063YXUrNZcFbYuqnO3TnchNetY7m7c\nyercrdNdSM1qz4FlXVTnbp1jpQtpTWcGbIs6X8veXpg3Ly1boUXX0oFlXVTnbp1joQup25CqU+dr\nOWcOTJ8OxxyTlnPmNPd8LbyWbmNZl7lXWOdxG1J16nwte3tTMBls2TKYNq3681V0Ld3duA7q3K2z\nrl1Iaz4zYEvV+VouWjR0ejMCS4uvpavCzKo0VtqQWqHO13LGjHLpr1aLr6UDi1mVxkIbUqvU+VpO\nmwazZw9Mmz27OXcr0PJr6TYWs2aoaxtSO9T5Wvb2puqvGTOaF1SKXuW1dBuLWTvVtQ2pHep8LadN\na01A6deia+mqMDMzq5QDi5mZVcqBxczMKuXAYmZmlXJgMTOzSo3J7saS+oCVo9x9EvBIhdlZ19S5\nfC5b56pz+TqpbDtExIjdysZkYHk1JC1upB93p6pz+Vy2zlXn8tWxbK4KMzOzSjmwmJlZpRxYyjun\n3RlosjqXz2XrXHUuX+3K5jYWMzOrlO9YzMysUg4sZmZWKQeWYUj6tqSHJd1RSNtK0rWS7s7LLduZ\nx9GStJ2k6yUtk7RU0kk5vePLJ2kjSYsk/U8u22dyeseXrZ+k9SXdKumq/LxOZVshaYmk2yQtzmm1\nKJ+kLSRdIulOSb2S9qxL2YocWIZ3HnDQoLRTgYURMRVYmJ93oheAj0fEdGAP4ARJ06lH+Z4F3h0R\nbwZ2Aw6StAf1KFu/k4DewvM6lQ3gzyJit8LvO+pSvrOAayJiZ+DNpPewLmVbIyL8GOYBdAN3FJ7f\n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\nTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "df.plot(kind='scatter',x='max_building_age',y='max_annual_income',color='red', title='max_annual income vs. max_building age')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 730, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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\nA/iVEEVybUmoAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "df.groupby('Security_Grade')['max_annual_income'].nunique().plot(kind='bar', title='Max Annual Income by Security_Grade')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 731, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAW4AAAEVCAYAAADARw+NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAFyBJREFUeJzt3Xm4JHV97/H3xxmQVdaJso9BgoK5QRwERUXE3IDIomJE\nEMFouBo3fOKNxFwVjSb4ZJFoWEJMQBDZVAhXrgoKGFFBhy3IokEYHFl0QBAEFdHv/aPqMM3hLD3M\n6Tn+Zt6v5+lnuqt+XfWt7jqf/tWvq2tSVUiS2vGE2S5AkrRsDG5JaozBLUmNMbglqTEGtyQ1xuCW\npMYY3KuQJC9I8t2Bx4uSvGSSti9K8sOBx9cledEKKHNkxm/TyiDJCUneO9t1PB5JDkty6WzX0SKD\nezn0wfdQko3HTb8qSSWZP8Prm98v92f97UdJjkuy2jDPr6qvVdW2j2fdVbV9VV3yeJ47jD5UK8m7\nR7WOmZRk8ySfTXJXkp8m+U6Sw1Z0HVX1pqr6676mGftgSrJJkn9Ncnu/r92c5OQkT5+J5Wv5GNzL\n7xbgNWMPkvw+sNaI17l+Va0D/D7wXOAtI17finAo8BPgdbNdyJBOBRYDWwEbAYcAP1qRBSSZM6Ll\nbgR8g24/fgGwLrAj8FXgDyd5ztxR1KKJGdzL71QeHTaHAqcMNkiyd98Lvy/J4iRHDcx7dZJbkjyp\nf7xXkjuTzJtuxVX1Y+BCYLuB5VWSpw08PjnJh/r7k/bIkqzZt70nyfXATuPmPzKskuSoJGclOSXJ\n/f0wyoKBtjv223t/krOTnDlWwyTrXhs4gO4DaJvBZfXzX5fk1iR3J3nvuFqekOTIJN/v55+VZMOp\nXrck7+l7youSHNxP26k/gpkz0O4VSa6ZZDE7ASdX1QNV9XBVXVVVXxh47i5JvpHk3iTXDA4zJdkw\nyUl9b/aeJOf20x8zdDD4fvbvz/FJ/l+SB4Ddx97f/jX8ArDpwBHZpkke7IN4bHk7JlkyzVHaO4H7\ngEOq6vvVubeqTqqqj/fLGTv6e0OSHwAX9dPP7vffnyb5zyTbD6x7oyTn9X8H3wK2HretT09yYZKf\nJPlukj+eosZVmsG9/C4DnpTkGf0f/YHAp8a1eYAu3NcH9gbenGR/gKo6k65387H+D+zfgDdW1ZLp\nVpxkU+CP+hqW1/vp/pC27pd56DTt9wXOoNum84B/7mtaHTgHOBnYEDgdePk0y3oF8DPgbOBLg+tO\n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\npMYY3JLUmP8PVmnxHVPgKtkAAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "df.groupby('Security_Grade')['max_building_age'].nunique().plot(kind='bar', title='Max Building Age by Security_Grade')\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.6.0" } }, "nbformat": 4, "nbformat_minor": 2 }