Data 3-1 Pandas Basics#

series, data frame, columns, index, numpy types, Nan, slicing

What is Pandas?#

Pandas is a Python library for working with tabular data. Pandas is short for PANeled DAta.

Pandas is like a programmable spreadheet. It is used by programmers to wrangle data (sort, filter, clean, enhance, etc.)

Pandas Series and DataFrame#

The two fundamental compoents of Pandas are the Series and DataFrame

  • a Series is a list of values with labels. This creates a column of data

  • a DataFrame is a collection of series. This creates a table of data

Null / No Value#

The constant np.nan is used to represent “no value”

1import pandas as pd
2import numpy as np

Series#

A Series is a named list of values.

The series has an index, too to reference each value. The default index is a zero based, similar to a python list.

1grades = pd.Series(data=[100,80,90,np.nan,100], name="Midterm Grades")
2grades
0    100.0
1     80.0
2     90.0
3      NaN
4    100.0
Name: Midterm Grades, dtype: float64
1# The the value at index 2
2grades[2]
90.0

The index can be anyting . Here’s the same grades with student names as the index.

1grades2 = pd.Series( data=[100,80,90,np.nan,100], 
2                    name="Midterm Grades",
3                    index=["Alice", "Bob", "Charlie", "David", "Eve"])
4grades2
Alice      100.0
Bob         80.0
Charlie     90.0
David        NaN
Eve        100.0
Name: Midterm Grades, dtype: float64
1# Get Charlie's grade
2grades2["Charlie"]
90.0

Series Aggregate Functions#

The beauty of Pandas is that for most operations, you won’t even need a loop! For example, we derive the min(), max(), mean(), sum() and count() of non np.nan values in a series without a for loop!!!

We do this by calling those method functions on the series itself, for example:

1print("Highest grade:", grades.max())
2print("Average grade:", grades.mean())
3print("lowest grade:", grades.min())
4print("Sum of grades:", grades.sum())
5print("Count of grades", grades.count())
Highest grade: 100.0
Average grade: 92.5
lowest grade: 80.0
Sum of grades: 370.0
Count of grades 4

Other Series Functions#

We use the unique() method function to return only the non-duplicate values from the series.

The value_counts() method function adds up values, creating a new series where the index is the value and the value is the count.

For example consider the following series:

1votes = pd.Series(data=[ 'y','y','y','n','y',np.nan,'n','n','y'], name="Vote")
2print("deduplicate the votes:", votes.unique())
3print("counts by value:", votes.value_counts())
deduplicate the votes: ['y' 'n' nan]
counts by value: Vote
y    5
n    3
Name: count, dtype: int64

DataFrame#

The pandas DataFrame is a table representation of data. It is the primary use case for pandas itself. A dataframe is simply a collection of Series that share a common Index. I like to think of the DataFrame as a programmable spreadsheet. It has rows and columns which can be accessed and manipulated with Python.

1names = pd.Series( data = ['Allen','Bob','Chris','Dave','Ed','Frank','Gus'])
2gpas = pd.Series( data = [4.0, np.nan, 3.4, 2.8, 2.5, 3.8, 3.0])
3years = pd.Series( data = ['So', 'Fr', 'Fr', 'Jr', 'Sr', 'Sr', 'Fr'])
4series_dict = { 'Name':  names, 'GPA': gpas, 'Year' : years }  # dict of Series, keys are the series names
5students = pd.DataFrame( series_dict )
6students
Name GPA Year
0 Allen 4.0 So
1 Bob NaN Fr
2 Chris 3.4 Fr
3 Dave 2.8 Jr
4 Ed 2.5 Sr
5 Frank 3.8 Sr
6 Gus 3.0 Fr

Other Ways to create dataframes:#

https://pandas.pydata.org/pandas-docs/stable/user_guide/dsintro.html#dataframe

Lists of lists: pd.DataFrame([['Tom', 7], ['Mike', 15], ['Tiffany', 3]])

Dictionary pd.DataFrame({"Name": ['Tom', 'Mike', 'Tiffany'], "Number": [7, 15, 3]})

Series pd.DataFrame({"Name": pd.Series(['Tom', 'Mike', 'Tiffany']), "Number": pd.Series([7, 15, 3])})

DataFrames share the index#

The dataframe is stitched together from values macthing on their index. For example:

1gpas = pd.Series(data=[4.0, np.nan, 3.4, 2.8, 2.5 ], index=['Allen','Bob','Chris','Ed', 'Frank'])
2yrs = pd.Series(data=['So', 'Fr', 'Jr', 'Sr'], index=['Allen','Bob','Dave', 'Frank'])
3studentsn = pd.DataFrame( {'GPA': gpas, 'Year': yrs})
4studentsn
GPA Year
Allen 4.0 So
Bob NaN Fr
Chris 3.4 NaN
Dave NaN Jr
Ed 2.8 NaN
Frank 2.5 Sr

Accessing elements with loc and iloc#

The loc[index, col] and iloc[row_pos, col_pos] properties allow you to slice the dataframe. loc uses the index and column names, while iloc uses ordinal positions starting at zero.

Here are some examples, using studentsn

1# Examples using loc
2print("loc: Get the Chris' GPA: ", students.loc['Chris', 'GPA'])
3print("loc: Get the Year of the last student (Frank): ", students.loc['Frank', 'Year'])
4
5# Same examples using iloc
6print("iloc: Get the GPA of the student at row 2 (Chris): ", students.iloc[2, 0])
7print("iloc: Get the Year of the last student (Frank): ", students.iloc[-1, 1])
loc: Get the Chris' GPA:  3.4
loc: Get the Year of the last student (Frank):  Sr
iloc: Get the GPA of the student at row 2 (Chris):  3.4
iloc: Get the Year of the last student (Frank):  Sr
1# You can also slice using loc and iloc
2print("loc: last two rows:\n", students.loc['Ed':, 'GPA':'Year'])
3print()
4print("iloc: last two rows:\n", students.iloc[-2:, 0:2])
loc: last two rows:
        GPA Year
Ed     2.8  NaN
Frank  2.5   Sr

iloc: last two rows:
        GPA Year
Ed     2.8  NaN
Frank  2.5   Sr

Null Checks#

use isna() to check for np.nan.

1students[students.GPA.isna()]
GPA Year
Bob NaN Fr
Dave NaN Jr

Challenge 3-1-1#

Create this dataframe:

   s1   s2 s3
a   1  2.2  q
b   2  NaN  q
c   3  3.0  z
d   4  1.5  z

Use series to create it to make sure the index is correct. print() the dataframe

Then print() the first 2 rows and columns using loc or iloc

Basic Dataframe operations#

  • info() provide names of columns, counts of non-null values in each columns, and data types.

  • describe() for each numerical column provide some basic statistics (min, max, mean, and quartiles).

  • head(n=5) view the FIRST n rows in the dataframe (defaults to 5)

  • tail(n=5) view the LAST n rows in the dataframe (defaults to 5)

  • sample(n=1) view a random n rows from the dataframe (defautls to 1)

  • .columns retrieve a list of columns in the dataframe

1customers = pd.read_csv('https://raw.githubusercontent.com/mafudge/datasets/master/customers/customers.csv')
2len(customers)
30

Display the dataframe in Streamlit#

You can use the st.dataframe() function to display a dataframe in Streamlit.

Here is an example: 3-1-streamlit-dataframe.py

Challenge 3-1-2#

Similar to the previous example, load this file into a customers dataframe:

https://raw.githubusercontent.com/mafudge/datasets/master/customers/customers.csv

Then create a radio widget to allow the user to select Head or Tail and a number input widget to enter a number of lines

output the head or tail of the dataframe and only show the number of lines input

Selecting Rows and Columns#

We can pair down the output of a dataframe by using:

  • a list of column names to select columns.

  • a boolean index to select matching rows.

1data_dict = { 
2    'Name':  ['Allen','Bob','Chris','Dave','Ed','Frank','Gus'], 
3    'GPA': [4.0, np.nan, 3.4, 2.8, 2.5, 3.8, 3.0], 
4    'Year' : ['So', 'Fr', 'Fr', 'Jr', 'Sr', 'Sr', 'Fr'] } 
5students = pd.DataFrame( data_dict )
6students
Name GPA Year
0 Allen 4.0 So
1 Bob NaN Fr
2 Chris 3.4 Fr
3 Dave 2.8 Jr
4 Ed 2.5 Sr
5 Frank 3.8 Sr
6 Gus 3.0 Fr

Selecting Columns#

This example just gets the name and GPA columns

1columns_to_show = ['Name', 'GPA']
2students[columns_to_show]
Name GPA
0 Allen 4.0
1 Bob NaN
2 Chris 3.4
3 Dave 2.8
4 Ed 2.5
5 Frank 3.8
6 Gus 3.0

Getting the freshmen using a boolean index#

consider the following:

1students['Year'] == 'Fr'
0    False
1     True
2     True
3    False
4    False
5    False
6     True
Name: Year, dtype: bool

This it called a boolean index. The boolean expression is evaluted for each index in the dataframe.

When we apply the boolean index to the dataframe, only the rows where the index == True are returned.

1students[students['Year'] == 'Fr'] 
Name GPA Year
1 Bob NaN Fr
2 Chris 3.4 Fr
6 Gus 3.0 Fr

Likewise we can assign these variables for clarity

1only_freshmen_index = students['Year'] == 'Fr'
2only_freshmen = students[only_freshmen_index]
3only_freshmen
Name GPA Year
1 Bob NaN Fr
2 Chris 3.4 Fr
6 Gus 3.0 Fr

And Or and Not with Boolean indexes#

What if we want freshmen or seniors? We cannot use or in this case, instead we must use the python bitwise or operator. This is because the series contains multiple values.

Bitwise Operators

  • and &

  • or |

  • not ~

Note: () are required between each bitwise operator.

1# freshmen and seniors
2only_freshmen_seniors = (students['Year'] == 'Fr') | (students['Year'] == 'Sr')
3students[only_freshmen_seniors]
Name GPA Year
1 Bob NaN Fr
2 Chris 3.4 Fr
4 Ed 2.5 Sr
5 Frank 3.8 Sr
6 Gus 3.0 Fr

Putting it Together#

Get the name and GPA of onlt freshmen with a GPA

1cols = ['Name', 'GPA']
2fr_with_gpa = (students['Year'] == 'Fr') & (students['GPA'].notna())
3students[fr_with_gpa][cols]
Name GPA
2 Chris 3.4
6 Gus 3.0

Challenge 3-1-3#

Similar to the previous example, load this file into a customers dataframe:

https://raw.githubusercontent.com/mafudge/datasets/master/customers/customers.csv

Then create a radio widget to allow the user to select “M” or “F” for gender A multi-select widget to pick which columns to display

filter the rows to match the gender and selected columns

display the dataframe