🔁 Recap

Week 1: What Do You Remember 🤔

  • What is the best sport in the world?
  • Why is data mining important?
  • What is a variable?
  • What are Python’s basic data types?
  • Where do we write and run Python code (at least for this class)?

🔮 Predict the Output

With your neighbor (3 min): what does each snippet print — before running it?

x = 10
print(x // 3)
print(x % 3)


name = "Alice"
score = 94.5
print(f"Student {name} scored {score:.0f}%")


words = "data mining"
print(words.upper()[:4])


print(type(5 / 2))
print(type(5 // 2))


word = "data"
print(word + "!" * 3)
print(len(word + "!"))

Answers:

x = 10
print(x // 3)
print(x % 3)
3
1


name = "Alice"
score = 94.5
print(f"Student {name} scored {score:.0f}%")
Student Alice scored 94%


words = "data mining"
print(words.upper()[:4])
DATA


print(type(5 / 2))
print(type(5 // 2))
<class 'float'>
<class 'int'>


word = "data"
print(word + "!" * 3)
print(len(word + "!"))
data!!!
5

Agenda


  1. Jupyter Notebooks – How we organize our analyses
  2. Data Structures – How we organize data
  3. Packages & Libraries – How we expand Python


Today’s Session

Follow along: Open the companion notebook and run code as we work through each concept.

Participate: We’ll pause throughout for group discussions and hands-on activities — come ready to think out loud with your neighbors!

Open the Companion Notebook Now

Week 2 Lecture Notebook

Open this now and keep it handy throughout class — we’ll run code, try exercises, and explore examples together.

Open In Colab

You can also use it after class as a reference and for additional “Try It” practice.

📓 Jupyter Notebooks

🧠 Think-Pair-Share: Data Analysis Reality

Your manager gives you customer data and asks for a report by Friday that:

  1. Explains the business problem clearly
  2. Shows your analytical process step-by-step
  3. Presents results with visualizations
  4. Provides actionable recommendations
  5. Can be updated when new data arrives next month

How would you approach this before this class?

And — what breaks at step 5 when new data arrives next month?

⏳ You have 2–3 minutes — chat with a neighbor!

📊 Data Analysis: Before vs After Jupyter

❌ Traditional Workflow Problems

Excel Analysis
    ↓
Screenshot Charts
    ↓
Word Document
    ↓
Email to Boss
    ↓
"Can you update this?"
    ↓
Start over! 😱
  • Manual copy/paste errors
  • No audit trail
  • Hard to reproduce
  • Version control nightmare

✅ Jupyter Notebook Solution

Data + Code + Narrative
         ↓
Single Document
         ↓
Export & Share
         ↓
"Update with new data?"
         ↓
Re-run notebook! 🎉
  • Automatic documentation
  • Reproducible analysis
  • Version controlled
  • Professional presentation

Bottom line: Notebooks let you explore, document, and communicate all in one place. Change one cell — the entire report updates.

🧱 Notebook Building Blocks

From your reading: Notebooks combine two cell types for complete analysis documentation

📝 Markdown Cells

  • Business context: Explain the problem
  • Methodology: Describe your approach
  • Insights: Interpret results
  • Recommendations: What should we do?


Like the narrative in a business report

🐍 Code Cells

  • Data loading: Import customer data
  • Analysis: Calculate key metrics
  • Visualization: Create charts/tables
  • Validation: Test assumptions


Like the calculations in a spreadsheet


The Magic: These work together to create professional, reproducible analysis reports!

🐍 Code Cells in Action

A single code cell holds your logic and its output — no copy/paste into a slide deck.

# Quarterly revenue analysis — code and result live together in one cell
revenue = {"Q1": 125_000, "Q2": 98_000, "Q3": 142_000, "Q4": 110_000}

annual = sum(revenue.values())
best_quarter = max(revenue, key=revenue.get)

print(f"Annual revenue: ${annual:,.0f}")
print(f"Quarterly avg:  ${annual / 4:,.0f}")
print(f"Best quarter:   {best_quarter} (${revenue[best_quarter]:,.0f})")
Annual revenue: $475,000
Quarterly avg:  $118,750
Best quarter:   Q3 ($142,000)

✏️ Your Turn

In the companion notebook, find the “Try It” cell for this section. Write code that:

  1. Assigns your name to a variable
  2. Assigns any number to a second variable
  3. Prints both using an f-string

🐍 Notebooks Tell a Story

The 3-cell pattern: context → analysis → interpretation

📝 Markdown Cell — Before

Business Question: Which subscription plan is most popular?

We’ll look at the distribution of customers across plan tiers to identify where to focus retention efforts.

subscriptions = {"Basic": 820, "Premium": 310, "Enterprise": 120}
total = sum(subscriptions.values())

for plan, count in subscriptions.items():
    bar = "█" * (count // 40)
    print(f"{plan:12s}: {count:4,} customers ({count/total:.0%})  {bar}")
Basic       :  820 customers (66%)  ████████████████████
Premium     :  310 customers (25%)  ███████
Enterprise  :  120 customers (10%)  ███

📝 Markdown Cell — After

Finding: Basic plan dominates at 66% of customers. Premium (25%) is the primary upsell opportunity — targeted Basic → Premium campaigns could meaningfully improve revenue.

🎯 Why Notebook Organization Matters

Your notebook has three different readers — organization is what lets one document serve all three.


👔 Stakeholders

They need the business story:

  • What problem are we solving?
  • What did you find?
  • What should we do about it?

Most will never read a line of your code.

🔍 Technical Reviewers

They need your reasoning:

  • Why this analytic approach?
  • What assumptions did you make?
  • Can I trust — and reproduce — this?

Your code shows what. Your writing shows why.

🔮 Future You

Six months from now:

  • What was I trying to do here?
  • Why did I do it that way?
  • Where do I pick this back up?

You will not remember. Write it down.

📂 Open both examples now — we’ll review them next

📋 Exercise: What Makes These Notebooks Work?

Both examples: Project notebook · Homework notebook

With your neighbor (5 min) — skim both and discuss:

  1. What works? Do they feel well organized? Are they easy to follow? What stands out as particularly clear or helpful?

  2. What’s missing? What would you add or change to make either one clearer?

✅ What Makes a Notebook Work

Most of what you just called out probably lands somewhere on this list.

📝 Structure — tells the story

  • Clear title with date and author
  • Executive summary in 1–2 sentences
  • Business problem stated up front
  • Methodology explaining your approach
  • Key findings called out, not buried
  • Recommendations with next steps

✍️ Craft — makes it usable

  • Descriptive file name: customer_churn_2026.ipynb
  • Markdown headers to signal sections
  • Explain your thinking, not just your code
  • State assumptions and data caveats
  • Professional writing — grammar counts
  • Export to HTML/PDF to share outside Jupyter

Important

“Structure your notebook like a story — introduce the goal, describe your approach, show the results, and summarize your findings.”

The test: could a stakeholder, a reviewer, and future-you each get what they need — without you in the room to explain it?

⚠️ Avoiding Common Pitfalls

🚨 The #1 Problem: Execution order ≠ cell order — output can lie

The number in brackets [N] shows when each cell last ran, not its position:

🔴 Out-of-order (untrustworthy)

print(f"Hello {my_name}!")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 1
----> 1 print(f"Hello {my_name}!")

NameError: name 'my_name' is not defined


my_name = "Brad"


✅ After “Restart & Run All”

my_name = "Brad"


print(f"Hello {my_name}!")
Hello Brad!

Pro Tip:

Always restart the kernel and run all cells before sharing your notebook. This ensures that your code runs in the correct order and that all outputs are reproducible.

🙋‍♀️ Questions & Discussion

Open floor for any questions about Jupyter notebooks:

  • Organizing professional analysis reports
  • Best practices for reproducible research
  • Cell execution and kernel management
  • Markdown formatting and documentation
  • Sharing notebooks with stakeholders


Let’s make sure everyone feels confident with notebooks before moving to data structures!

Python Data Structures

Why Do We Care?

Last week, we worked with individual data types like:

  • int for numbers
  • float for decimals
  • str for text

But in real-world analyses, we usually need to work with collections of values.

  • A list of product names
  • A mapping of customer IDs to sales
  • A set of unique email addresses

Important

This is where data structures come in. Data structures help us organize values.

🏢 Data Structures in Python

Python’s built-in structures are designed for the work data analysis actually does:

✅ What They Give You

  • Fast lookups — get a record by name or ID instantly, no scanning row by row
  • Scales cleanly — the same code works on 100 rows or 100 million
  • Easy to automate — write the logic once, re-run it on next month’s data
  • Built-in protection — some structures refuse to change by accident
  • Purpose-built — dedupe, order, and label your data with no extra work

🐍 What They Look Like

# Dictionary
customer_plans = {
    "sarah": "premium",
    "mike": "basic"
}

# List
renewals = ["sarah", "mike", "alex"]

# Set
regions = {"midwest", "south", "midwest"}

The Question

Which Python structure fits each business need?

🗂️ The Four Main Data Structures

Python gives us four powerful (built-in) tools to organize business data:


Structure Ordered? Mutable? Best For Business Example
List Ordered sequences Daily sales figures, customer queue
Tuple Fixed, protected data Store coordinates, product dimensions
Set Unique values only Email subscribers, product categories
Dictionary Lookups & labeled data Customer profiles, product catalog


Tip

The Goal: Match your data’s behavior to the right structure

Which One Matters


Choosing the right one makes your code:

  • Easier to write
  • Faster to run
  • Simpler to understand


For example…

Example 1: List


📈 Goal: You’re storing daily sales figures, in order.

daily_sales = [1842, 2105, 1956, 2341, 890]


  • This is a list
  • Ordered and mutable (can add/remove/change items)
  • Uses [] brackets for creation

Important

✅ A list lets you store sequences of items and modify them easily.

📌 Use when order matters and you’ll be changing the contents.

🔧 Working with Lists

A few basic things you can do — the readings and lab will go deeper:

Get an item by position:

daily_sales = [1842, 2105, 1956, 2341, 890]
daily_sales[1]   # index starts at 0, so [1] = second item
2105

Append a new item to the end:

daily_sales = [1842, 2105, 1956, 2341, 890]
daily_sales.append(3102)
daily_sales
[1842, 2105, 1956, 2341, 890, 3102]

Change an existing item:

daily_sales = [1842, 2105, 1956, 2341, 890]
daily_sales[1] = 2200   # correct a data entry error
daily_sales
[1842, 2200, 1956, 2341, 890]

✏️ Your Turn: Build a List

In your notebook, start with this exact list:

daily_customers = [182, 205, 196, 234, 89]

Then:

  1. Extract — print the third day’s count
  2. Add — a sixth day had 310 customers; append it
  3. Change — day 5 was a typo; correct 89 to 128
  4. Print the final list

✅ Check your output

196

[182, 205, 196, 234, 128, 310]

Example 2: Tuple


📍 Goal: You’re storing a store location that should never change.

store_location = (39.1031, -84.5120)


  • This is a tuple
  • Ordered, but immutable (cannot be changed)
  • Surrounded by () and contains values in sequence

Important

✅ A tuple protects data from being changed accidentally.

📌 Use when data is fixed and position matters.

🔧 Working with Tuples

Tuples support reading but not writing:

Get items by position:

store_location = (39.1031, -84.5120)
lat, lon = store_location  # tuple unpacking 🤯
print(lat)   
print(lon)   
39.1031
-84.512

Try to change a value — tuples won’t allow it:

store_location = (39.1031, -84.5120)
store_location[0] = 40.0
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[16], line 2
      1 store_location = (39.1031, -84.5120)
----> 2 store_location[0] = 40.0

TypeError: 'tuple' object does not support item assignment

Important

Key Insight: The error is intentional — tuples protect your data from accidental changes.

✏️ Your Turn: Build a Tuple

In your notebook, start with this exact tuple:

warehouse_gps = (39.2734, -84.4569)

Then:

  1. Extract — unpack it into lat and lon, then print both
  2. Extract — print just the longitude using an index
  3. Try to change — set the latitude to 40.0. What happens?

✅ Check your output

39.2734 -84.4569-84.4569 … then:

TypeError: 'tuple' object does not support item assignment

Example 3: Set


📧 Goal: You’re collecting unique customer email addresses, no duplicates allowed.

subscribers = {"john@email.com", "sarah@email.com", "mike@email.com"}


  • This is a set
  • Unordered but mutable (can add/remove items)
  • Uses {} brackets but NO key-value pairs (just values)
  • Automatically removes duplicates

Important

✅ A set ensures all items are unique and provides fast membership testing.

📌 Use when you need to eliminate duplicates or check “is this item in the collection?”

🔧 Working with Sets

Sets don’t support indexing — but they excel at membership testing and deduplication:

Check if an item exists:

subscribers = {"john@email.com", "sarah@email.com", "mike@email.com"}
print("sarah@email.com" in subscribers)
print("alex@email.com" in subscribers)
True
False

Add a new item:

subscribers = {"john@email.com", "sarah@email.com", "mike@email.com"}
subscribers.add("alex@email.com")
subscribers
{'alex@email.com', 'john@email.com', 'mike@email.com', 'sarah@email.com'}

✏️ Your Turn: Build a Set

In your notebook, start with this exact set — note the repeats:

categories = {"dairy", "produce", "bakery", "dairy", "produce"}

Then:

  1. Extract — print len(categories). How many survived?
  2. Check — is "bakery" in the set? Is "frozen"?
  3. Add — add "frozen" to the set
  4. Print sorted(categories)

✅ Check your output

3True False['bakery', 'dairy', 'frozen', 'produce']

Use sorted() — a set has no order, so printing it raw varies run to run!

Example 4: Dictionary


🔎 Goal: You need to look up a product price by name.

prices = {"organic milk": 4.99, "whole grain bread": 3.29}


  • This is a dictionary (dict)
  • It uses key–value pairs surrounded by {}
  • Keys are product names; values are prices

Important

✅ A dictionary allows fast key-based lookup.

📌 Use when you need to map one thing (e.g. product name) to another (e.g. price).

🔧 Working with Dictionaries

Dictionaries let you look up, add, and update by key:

Get a value by key:

prices = {"organic milk": 4.99, "whole grain bread": 3.29}
prices["organic milk"]
4.99

Add a new key-value pair:

prices = {"organic milk": 4.99, "whole grain bread": 3.29}
prices["eggs"] = 2.89
prices
{'organic milk': 4.99, 'whole grain bread': 3.29, 'eggs': 2.89}

Update an existing value:

prices = {"organic milk": 4.99, "whole grain bread": 3.29}
prices["organic milk"] = 5.49
prices["organic milk"]
5.49

✏️ Your Turn: Build a Dictionary

In your notebook, start with this exact dictionary:

prices = {
    "organic milk": 4.99,
    "whole grain bread": 3.29,
    "free-range eggs": 5.49,
}

Then:

  1. Extract — print the price of "whole grain bread"
  2. Add — add "cold brew coffee" at 8.99
  3. Change — bread is on sale; update it to 2.79
  4. Print the whole dictionary

✅ Check your output

3.29, then all four items with bread at 2.79 and coffee added at the end.

🎯 Business Decision Framework

When choosing a data structure, ask yourself:

  1. Do I need to look things up by name/ID? → Dictionary
  2. Is the order of items important? → List or Tuple
  3. Will the data change over time? → List (if yes), Tuple (if no)
  4. Do I need only unique values? → Set


Important

Key Insight: The right structure makes your analysis faster, clearer, and more maintainable!

🗳️ Quick Vote: Which Structure?

Scenario: Your fraud detection system receives 50,000 transaction IDs per hour. You need to instantly answer: “Have we seen this transaction ID before?”


Vote — which structure would you use?

🅐 List — simple and familiar

🅑 Set — fast membership testing, no duplicates

🅒 Dictionary — key-value lookup by ID


Important

Answer: Setid in seen_ids is nearly instant regardless of size. A List checks every element one-by-one — fast for 10 items, unusably slow for 50,000.

🧠 Mini Challenge - Pick the Structure

You’re a data analyst at different companies. Choose the best data structure:

Scenario 1: Social Media Startup 📱 Track trending hashtags from user posts — each hashtag should only appear once, regardless of how many times users post it.

Scenario 2: E-commerce Platform 🛒 Track daily website traffic for 30 days for trend analysis and allow quick lookup of any specific date’s traffic by date.

(Hint: more than one structure could work — be ready to defend your choice!)

Scenario 3: Restaurant Chain 🍕 Store the GPS coordinates of your flagship restaurant. This data will never change and is critical for delivery mapping software.

Scenario 4: University System 🎓 Build a student lookup system where professors can quickly find a student’s information (name, major, GPA) using their student ID number.

🤔 Work with a partner (3 min) — then class vote on Scenario 2!

Summary: Data Structures Matter


Choosing the right structure makes your code:

  • Easier to write and read
  • More efficient
  • Better aligned to the task

You’ll explore these structures more in depth this week and you’ll get practice:

  1. choosing the right one
  2. creating these data structures
  3. accessing and modifying items inside them

📦 Packages, Libraries & Modules

Python Ecosystem

  • Python is great, but not perfect out of the box
  • We use libraries to add features

Tip

Python’s true power comes from its ecosystem of libraries that extend its core functionality

🤔 Build from Scratch or Reuse?

If you needed to calculate the correlation between two variables (x and y)

x = [2, 4, 7, 8, 10, 11, 14, 13]
y = [1, 3, 5, 7, 10, 9, 13, 13]

would you rather…

🛠️ Option 1: Build It Yourself

mean_x = sum(x) / len(x)
mean_y = sum(y) / len(y)

numerator = sum((a - mean_x)*(b - mean_y) for a, b in zip(x, y))
denominator = (
    sum((a - mean_x)**2 for a in x) *
    sum((b - mean_y)**2 for b in y)
) ** 0.5

correlation = numerator / denominator
print(f"correlation = {correlation}")
correlation = 0.9861297973047767

🤖 Option 2: Use a Library

import numpy as np

correlation = np.corrcoef(x, y)[0, 1]
print(f"correlation = {correlation}")
correlation = 0.9861297973047767

Important

Packages like numpy help us reuse reliable, optimized code

📌 They save time, reduce bugs, and make your code easier to read

The Python Ecosystem

🛠️ Standard vs. Third-Party

Small difference in accessing these libraries

Standard Library

import random
random.randint(1, 10)
7

Third-Party Library

# must first install (typically from PyPI)
pip install numpy   # command line
!pip install numpy  # jupyter notebook


import numpy as np
np.mean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
np.float64(5.5)

🛠️ Standard vs. Third-Party

  • Standard Library – comes with Python (math, datetime)
  • Third-Party Libraries – must install (numpy, pandas, seaborn)

Standard Library

  • Already installed with Python
  • Lots of functionality
    • os
    • math
    • itertools
    • functools
    • random
    • pickle
    • datetime
    • etc.

Third-Party Library

  • Must be installed
  • Python Package Index (PyPI - https://pypi.org/)
    • numpy
    • pandas
    • matplotlib
    • seaborn
    • scikit-learn
    • 650,000+ pkgs on PyPI!!!

✏️ Your Turn: Use a Standard Library

Nothing to installrandom ships with Python.

Scenario: simulate 10 daily sales figures between $3,000 and $8,500.

import random

random.seed(13)      # so everyone gets the same "random" numbers

daily_sales = random.sample(range(3000, 8501), 10)
print(daily_sales)
[5121, 5381, 4521, 8341, 4888, 8457, 4205, 4844, 8250, 4534]

Now use your list skills on the result:

  1. Extract — print day 1 and day 3 sales
  2. Summarize — print the total across all 10 days using sum()

✅ Check your output

Day 1 → 5121 · Day 3 → 4521 · Total → 58542

✏️ Your Turn: Now Bring in numpy

Two stores this time — and a question random alone can’t answer.

import random

random.seed(13)

store_a = random.sample(range(3000, 8501), 10)
store_b = random.sample(range(3000, 8501), 10)

print("Store A:", store_a)
print("Store B:", store_b)
Store A: [5121, 5381, 4521, 8341, 4888, 8457, 4205, 4844, 8250, 4534]
Store B: [4066, 3580, 7352, 4752, 5413, 3245, 6535, 4034, 7984, 3118]

Now bring in a third-party library:

  1. import numpy as np (note np is called an alias)
  2. Compute the mean daily sales for each store (hint: np.mean())
  3. Are the two stores related? Compute np.corrcoef(store_a, store_b)[0, 1]

✅ Check your output

Store A mean → 5854.2 · Store B mean → 5007.9 · correlation → 0.026

Essentially zero — we generated the two stores independently, so there’s no relationship to find. numpy gave us the number; you supplied the interpretation.

✏️ Your Turn: Install a Third-Party Package

This one you have to install firstcompletejourney_py holds the retail data we’ll use all semester.

# Run this once. In Colab keep the `!`; in a terminal, drop it.
!pip install completejourney-py

Then load the data:

from completejourney_py import get_data

cj = get_data()          # returns a dictionary of DataFrames
print(sorted(cj.keys()))
['campaign_descriptions', 'campaigns', 'coupon_redemptions', 'coupons', 'demographics', 'products', 'promotions', 'transactions']
transactions = cj["transactions"]

print(f"{transactions.shape[0]:,} rows × {transactions.shape[1]} columns")
transactions[["household_id", "product_id", "quantity", "sales_value"]].head(3)
1,469,307 rows × 11 columns
household_id product_id quantity sales_value
0 900 1095275 1 0.50
1 900 9878513 1 0.99
2 1228 1041453 1 1.43

📖 Want to explore?

Dataset descriptions and examples: cunningjames.github.io/completejourney_py

Let’s Wrap This Up

Recap: What Did We Learn?

  • Jupyter helps us explore + explain
  • Data structures help us organize
  • Libraries help us do more with Python

Next Up: Lab Time on Thursday

Hands-on practice with…

  • Jupyter notebooks
  • Data structures
  • Practice using packages


Important

Be sure to read the chapter readings before Thursday’s lab! And bring your questions!

Q&A 🙋‍♀️

Open floor for any questions regarding…

  • Last week’s content
  • This week’s content
  • Data mining in general
  • Career questions
  • Etc