Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
17860 views
%md # Math 152: Intro to Mathematical Software <img src="https://natgeoeducationblog.files.wordpress.com/2016/09/embarrassment-of-pandas.jpg" class="pull-right" width=300> ### 2017-02-15 ### Kiran Kedlaya; University of California, San Diego ### adapted from lectures by William Stein, University of Washington ### **Lecture 16: Pandas (part 2)**

Math 152: Intro to Mathematical Software

### 2017-02-15 ### Kiran Kedlaya; University of California, San Diego ### adapted from lectures by William Stein, University of Washington

Lecture 16: Pandas (part 2)

Announcements:

  1. Peer reviews due Thursday 8pm. Request from the graders: please place all feedback in a file called "grades.txt", to make it easier to find. (If one of your assigned folders is empty, please still make "grades.txt" and report that you found an empty folder.)

  2. Next Monday is a University holiday, so no lecture, sections, or office hours. Zonglin's office hours are rescheduled to Tuesday 10-12 (and also replace my usual Tuesday office hour).

Today: more pandas...

  • getting data into SMC

  • Series

  • DataFrames

%auto import pandas as pd pd.__version__ import numpy as np import matplotlib.pyplot as plt import matplotlib matplotlib.style.use('ggplot') %default_mode python # avoid Sage data types like Integer, which cause trouble (due to the Sage preparser). %typeset_mode True
u'0.21.0'

1. Getting data into SMC

  • WARNING: SMC has absolutely no direct access to the files on your laptop. It is a remote computer account running in the cloud. That said, if you use pandas/python, etc, on your own computer at some point, it will of course have direct access. (Maybe do a live demo of python get-pip.py then pip install --user pandas on my Linux laptop.)

  • +New, paste the link into the box, click "Download from Internet".

  • +New, drag and drop, upload a file.

  • Use wget or curl from the terminal or in a %sh cell.

  • Use scp or rsync (see project settings... SSH button) from your computer to the project.

  • Note: the last two methods require your project to have an Internet upgrade. For this course, that is provided by UCSD.

The %sh command simulates a Unix (or Mac) terminal from within a worksheet. As long as a command isn't interactive, it should work for you.

%sh wget http://spatialkeydocs.s3.amazonaws.com/FL_insurance_sample.csv.zip
--2017-02-15 22:14:38-- http://spatialkeydocs.s3.amazonaws.com/FL_insurance_sample.csv.zip Resolving spatialkeydocs.s3.amazonaws.com (spatialkeydocs.s3.amazonaws.com)... 54.231.40.83 Connecting to spatialkeydocs.s3.amazonaws.com (spatialkeydocs.s3.amazonaws.com)|54.231.40.83|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 866400 (846K) [application/zip] Saving to: ‘FL_insurance_sample.csv.zip’ FL_insurance_sample 100%[=====================>] 846.09K 2.07MB/s in 0.4s 2017-02-15 22:14:39 (2.07 MB/s) - ‘FL_insurance_sample.csv.zip’ saved [866400/866400]
%sh ls
2017-02-15-140805        FL_insurance_sample.csv.zip  index.html   nyt.png
2017-02-15.sagews        __MACOSX                     index.shtml
FL_insurance_sample.csv  animals.csv                  nikolai.jpg
%sh unzip FL_insurance_sample.csv.zip
Archive: FL_insurance_sample.csv.zip inflating: FL_insurance_sample.csv creating: __MACOSX/ inflating: __MACOSX/._FL_insurance_sample.csv
df = pd.read_csv('FL_insurance_sample.csv') df.head(10)
policyIDstatecodecountyeq_site_limithu_site_limitfl_site_limitfr_site_limittiv_2011tiv_2012eq_site_deductiblehu_site_deductiblefl_site_deductiblefr_site_deductiblepoint_latitudepoint_longitudelineconstructionpoint_granularity
0119736FLCLAY COUNTY498960.0498960.00498960.0498960.0498960.00792148.900.09979.20.0030.102261-81.711777ResidentialMasonry1
1448094FLCLAY COUNTY1322376.31322376.301322376.31322376.31322376.301438163.570.00.00.0030.063936-81.707664ResidentialMasonry3
2206893FLCLAY COUNTY190724.4190724.40190724.4190724.4190724.40192476.780.00.00.0030.089579-81.700455ResidentialWood1
3333743FLCLAY COUNTY0.079520.760.00.079520.7686854.480.00.00.0030.063236-81.707703ResidentialWood3
4172534FLCLAY COUNTY0.0254281.500.0254281.5254281.50246144.490.00.00.0030.060614-81.702675ResidentialWood1
5785275FLCLAY COUNTY0.0515035.620.00.0515035.62884419.170.00.00.0030.063236-81.707703ResidentialMasonry3
6995932FLCLAY COUNTY0.019260000.000.00.019260000.0020610000.000.00.00.0030.102226-81.713882CommercialReinforced Concrete1
7223488FLCLAY COUNTY328500.0328500.00328500.0328500.0328500.00348374.250.016425.00.0030.102217-81.707146ResidentialWood1
8433512FLCLAY COUNTY315000.0315000.00315000.0315000.0315000.00265821.570.015750.00.0030.118774-81.704613ResidentialWood1
9142071FLCLAY COUNTY705600.0705600.00705600.0705600.0705600.001010842.5614112.035280.00.0030.100628-81.703751ResidentialMasonry1
df.describe()
policyIDeq_site_limithu_site_limitfl_site_limitfr_site_limittiv_2011tiv_2012eq_site_deductiblehu_site_deductiblefl_site_deductiblefr_site_deductiblepoint_latitudepoint_longitudepoint_granularity
count36634.0000003.663400e+043.663400e+043.663400e+043.663400e+043.663400e+043.663400e+043.663400e+043.663400e+0436634.00000036634.00000036634.00000036634.00000036634.000000
mean548661.9371897.314780e+052.074348e+066.646009e+059.911724e+052.172875e+062.571004e+067.787908e+027.037985e+03192.45321026.48359428.087477-81.9035651.640907
std259912.9264941.752300e+071.964150e+071.746114e+071.767178e+072.015015e+072.036777e+074.787979e+049.582593e+048037.7137164702.7409321.6477341.8090661.070561
min100074.0000000.000000e+000.000000e+000.000000e+000.000000e+009.000000e+017.337000e+010.000000e+000.000000e+000.0000000.00000024.547514-87.4472901.000000
25%323647.7500000.000000e+004.248106e+040.000000e+000.000000e+004.562415e+045.401351e+040.000000e+000.000000e+000.0000000.00000026.471996-82.4393311.000000
50%548525.0000000.000000e+001.926911e+050.000000e+000.000000e+002.021051e+052.416310e+050.000000e+000.000000e+000.0000000.00000028.057077-81.5857001.000000
75%774252.0000000.000000e+009.163381e+050.000000e+005.741010e+049.465821e+051.128871e+060.000000e+000.000000e+000.0000000.00000029.623005-80.3729103.000000
max999971.0000002.160000e+092.160000e+092.160000e+092.160000e+092.160000e+091.701000e+096.273765e+067.380000e+06450000.000000900000.00000030.989820-80.0332577.000000

pd.Series

http://pandas.pydata.org/pandas-docs/version/0.18.1/dsintro.html#series


  • Datasets are built out of pd.Series objects, which are like a List of values, but with a specific type (like floating point number, integer, string, ...) and an index. More precisely, a pd.Series is a "One-dimensional ndarray with axis labels"

  • Larger pd.DataFrame objects are built out of several such series. Each of them is a column, must have the same length, and each column has a name.

Examples:

names = pd.Series(["Bob", "Marlene", "Joe", "Jane"]) age = pd.Series([55, 18, 71, 22])
names
0 Bob 1 Marlene 2 Joe 3 Jane dtype: object
age
0 55 1 18 2 71 3 22 dtype: int64
s = pd.Series(['john', 'private', 389, 'nathan'], index=['name', 'rank', 'number', 'name']) s
name john rank private number 389 name nathan dtype: object
s['rank']
private
s['name']
name john name nathan dtype: object
t = pd.Series([39, 'sergeant'], index=['number', 'rank']) s + t
name NaN name NaN number 428 rank privatesergeant dtype: object

Indexing...

age
0 55 1 18 2 71 3 22 dtype: int64
age[2]
$\displaystyle 71$
age[:-1]
0 55 1 18 2 71 dtype: int64
age[age > 30]
0 55 2 71 dtype: int64
age[age > 30][2]
$\displaystyle 71$
age[age > 30][age < 60]
0 55 dtype: int64

... so a pd.Series is much like a Python dict except you can do arithmetic, there is an order, you can have the same key multiple times, indexing is amazing. And everything is super fast.

Exercise right now!:

  • Make a Python dict d of your choosing, then try doing pd.Series(d). It should work.

  • Make up 3 different pd.Series objects with various choices of values and index.

  • Try adding them together and see what happens.

"50 to 80 percent of time is spent wading through the tedium of the first two steps – acquiring and wrangling data – before even getting to the real work of analysis and insight." -- New York Times

pd.DataFrame

Documentation: http://pandas.pydata.org/pandas-docs/version/0.18.1/dsintro.html#dataframe

DataFrame = "a 2-dimensional labeled data structure with columns of potentially different types."

Think of it as:

  • a spreadsheet, or

  • a SQL table, or

  • a dict of pd.Series objects.

Now, we build a pd.DataFrame:

names = pd.Series(["William", "Marlene", "Jon", "Jane"]) age = pd.Series([42, 68, 19, 22]) # We are literally making this data frame from a dictionary of series objects! # (This gives us no control over the order of the columns though...) people = pd.DataFrame({"name": names, "age": age}) people
agename
042William
168Marlene
219Jon
322Jane
# Explicit control of column order: pd.DataFrame({"name": names, "age": age}, columns=['name', 'age', 'location'])
nameagelocation
0William42NaN
1Marlene68NaN
2Jon19NaN
3Jane22NaN

The bold numbers or values on the left are called the "index".

The index is used to uniquely identify a row.

Use people.ix[i] to get the row with given index!

This isn't obvious. You just have to memorize it. Learn it now.

# get the row with index "1" -- which people.ix[1]
age 68 name Marlene Name: 1, dtype: object

Of course, the rows don't have to be indexed by numbers -- anything hashable is allowed.

d = pd.DataFrame({'col1':{'name':'william', 'rank':'private'}, 'col2':{'name':'jon', 'rank':'general', 'ser':5077}}) d
col1col2
namewilliamjon
rankprivategeneral
serNaN5077
d.ix['rank']
col1 private col2 general Name: rank, dtype: object
d.ix['ser']
col1 NaN col2 5077 Name: ser, dtype: object

** Exercise right now!** Make a data frame for which there are two rows with the same index i, showing that the index need not be unique! [Hint: we made such a series above]

What happens when you type d.ix[i]?

d = pd.DataFrame({'col1':{'name':'william', 'rank':'private', 'i': 1, 'i':2}, 'col2':{'name':'jon', 'rank':'general', 'ser':5077, 'i':1, 'i':3}}) d
col1col2
i23
namewilliamjon
rankprivategeneral
serNaN5077
s.ix['name']
name john name nathan dtype: object

NOTE: Besides .ix, there are also other properties for various purposes. Read more about them here:

s d = pd.DataFrame({'a': s,'b': s}) d d.ix['name']
name john rank private number 389 name nathan dtype: object
ab
namejohnjohn
rankprivateprivate
number389389
namenathannathan
ab
namejohnjohn
namenathannathan
d = pd.DataFrame({'col1':{'name':'william', 'rank':'private'}, 'col2':{'name':'jon', 'rank':'general', 'ser':5077}}) d
col1col2
namewilliamjon
rankprivategeneral
serNaN5077
d.loc[['name', 'rank']]
col1col2
namewilliamjon
rankprivategeneral
d.iloc[1]
col1 private col2 general Name: rank, dtype: object
d.iloc[0]
col1 william col2 jon Name: name, dtype: object
d.iloc[-1]
col1 NaN col2 5077 Name: ser, dtype: object

Question: How to get all rows starting from index 1 up to the end?

Answer: slicing.

people = pd.DataFrame({"name": names, "age": age}) people
agename
042William
168Marlene
219Jon
322Jane
people[:2]
agename
042William
168Marlene
people[1:3]
agename
168Marlene
219Jon
people[::2]
agename
042William
219Jon

CSV

CSV is a very simple column-oriented data format, where a text file contains rows and a comma is a delimiter for the columns.

see animals.csv

The first row contains the header, describing the columns.

Pandas then imports this file via pd.read_csv() (the argument of this function could not only be a filename, but also a URL link 'http://...' pointint to a csv file)

open("animals.csv",'w').write( """name,type,tail,legs,age,color joe,elephant,Y,4,16,gray tim,dog,Y,4,7,golden susan,cat,Y,4,4,black frank,fish,N,0,1,green olivia,spider,N,6,.5,black minki,cat,Y,4,6,white""")
%sh cat animals.csv
name,type,tail,legs,age,color joe,elephant,Y,4,16,gray tim,dog,Y,4,7,golden susan,cat,Y,4,4,black frank,fish,N,0,1,green olivia,spider,N,6,.5,black minki,cat,Y,4,6,white
animals = pd.read_csv("animals.csv") animals
nametypetaillegsagecolor
0joeelephantY416.0gray
1timdogY47.0golden
2susancatY44.0black
3frankfishN01.0green
4oliviaspiderN60.5black
5minkicatY46.0white
# access columns animals.name
0 joe 1 tim 2 susan 3 frank 4 olivia 5 minki Name: name, dtype: object

The power of Pandas is, that you can start asking questions about this data, filter it, compare it with other datasets, or even picture it in a plot very easily.

animals.describe()
legsage
count6.0000006.000000
mean3.6666675.750000
std1.9663845.654644
min0.0000000.500000
25%4.0000001.750000
50%4.0000005.000000
75%4.0000006.750000
max6.00000016.000000
# average age? animals.age.mean()
$\displaystyle 5.75$
# which ones are younger than 6? animals[animals.age < 6]
nametypetaillegsagecolor
2susancatY44.0black
3frankfishN01.0green
4oliviaspiderN60.5black
animals.ix[animals.legs == 4]
nametypetaillegsagecolor
0joeelephantY416.0gray
1timdogY47.0golden
2susancatY44.0black
5minkicatY46.0white

Question: which animal(s) has/have the largest number of legs?

animals.name.ix[animals.legs == animals.legs.max()]
4 olivia Name: name, dtype: object
animals.legs
0 4 1 4 2 4 3 0 4 6 5 4 Name: legs, dtype: int64
animals.legs.plot.hist()

Plotting

In a related library "statsmodels", there are also various datasets included. Try plotting one of them (where it makes sense)

%auto from statsmodels import datasets
x = datasets.statecrime d = x.load_pandas().data # accesses the pandas dataframe d.head(5) # .head or .tail give you the n-th rows at top or at the bottom
violentmurderhs_gradpovertysinglewhiteurban
state
Alabama459.97.182.117.529.070.048.65
Alaska632.63.291.49.025.568.344.46
Arizona423.25.584.216.525.780.080.07
Arkansas530.36.382.418.826.378.439.54
California473.45.480.614.227.862.789.73
d.violent.plot.hist()