TechByteByByte

Python for Data and AI (NumPy and Pandas)

Learn the essential NumPy and Pandas concepts needed for AI development, including arrays, shapes, vector operations, cosine similarity, DataFrames, and filtering evaluation datasets.

#Python#NumPy#Pandas#Embeddings#Vectors#AI#Python for AI

The problem: Python lists can store numbers, but numerical AI work needs known shapes, compact numeric types, and fast operations over many values. Real datasets add named columns, missing values, filtering, and readable tables.

What you will learn: NumPy supplies multidimensional numeric arrays; Pandas supplies labeled tables for data analysis. We will focus on the parts needed for embeddings and dataset preparation: shapes, axes, vector math, views, precision, filtering, missing data, and leakage prevention. Both libraries are much larger, so this is a practical AI-focused path through them rather than a complete reference course.


Part A — NumPy

1. Introduction to NumPy

Python lists are flexible containers. Numerical AI work often needs something more specialized: many numbers with one known shape and dtype, processed by fast compiled operations.

raw records ── Pandas ─→ clean rows and columns
                              ↓ select numeric values
                         NumPy arrays
                              ↓ vector and matrix operations
                       model-ready numbers

NumPy and Pandas are related but not interchangeable. NumPy focuses on multidimensional numeric arrays. Pandas adds labels such as column names and row indexes, making tables easier to inspect and transform.

Numeric Arrays with a Known Shape

NumPy (“Numerical Python”) is a library for working with arrays of numbers, extremely efficiently.

Why Python Lists Are Not Always Enough

A Python list can hold numbers, but it’s slow for heavy math and doesn’t naturally support things like “add every element by 5” or “multiply two grids of numbers together.” NumPy was built specifically to make numeric computation fast and expressive.

Picture One Operation Reaching Every Number

A Python list is a shopping bag — general-purpose, holds anything, but not built for math. A NumPy array is a spreadsheet grid built purely for numbers — every operation on it is fast and works on the whole grid at once.

A Familiar Example

Doing math on a Python list is like adding two grocery lists item-by-item with a calculator, by hand. NumPy is like feeding both lists into a machine that adds every matching pair instantly, all at once.

Installing and importing

pip install numpy
import numpy as np   # "np" is the near-universal convention

🤖 Why This Matters for AI (the short version): An embedding — the numeric representation of a sentence that an AI model produces — is a NumPy array. Every similarity search, every “which document is closest to this query,” every operation inside a neural network, ultimately comes down to NumPy-style array math.


2. NumPy Arrays

Creating arrays

import numpy as np

a = np.array([1, 2, 3, 4, 5])
print(a)
print(type(a))

Expected Output:

[1 2 3 4 5]
<class 'numpy.ndarray'>

Why not just use a list?

python_list = [1, 2, 3]
numpy_array = np.array([1, 2, 3])

# Bad / naive approach — doubling every value in a plain Python list
doubled_list = [x * 2 for x in python_list]
print(doubled_list)

# Better approach — NumPy does this natively, on the whole array at once
doubled_array = numpy_array * 2
print(doubled_array)

Expected Output:

[2, 4, 6]
[2 4 6]

Both give the same result here, but the NumPy version:

  • reads more naturally (“multiply the array by 2,” not “loop and multiply each item”)
  • runs dramatically faster on large data (thousands or millions of numbers — exactly the scale of real embeddings)
  • is the syntax every AI library actually expects

Common array creation helpers

zeros = np.zeros(5)              # [0. 0. 0. 0. 0.]
ones = np.ones(3)                # [1. 1. 1.]
range_arr = np.arange(0, 10, 2)  # [0 2 4 6 8]
random_arr = np.random.rand(3)   # 3 random floats between 0 and 1

🤖 How Is This Used in AI? np.zeros and np.random.rand are commonly used to initialize placeholder vectors or test embeddings before real model output is available.


3. Array Shapes

What Is It?

The shape of an array describes its dimensions — how many rows, columns, etc.

vector = np.array([0.1, 0.2, 0.3])
print(vector.shape)     # (3,)  -> a 1D array of 3 numbers

matrix = np.array([[0.1, 0.2, 0.3],
                    [0.4, 0.5, 0.6]])
print(matrix.shape)     # (2, 3) -> 2 rows, 3 columns

Expected Output:

(3,)
(2, 3)

🧠 Intuition

Shape answers: “how many numbers, arranged how?” (3,) is a single row of 3 numbers. (2, 3) is a grid: 2 rows, each with 3 numbers.

🤖 How Is This Used in AI?

This is not optional trivia — shape mismatches are one of the single most common errors in AI code.

embedding = np.array([0.12, -0.05, 0.33, 0.91])   # shape (4,) — one embedding
print(embedding.shape)

batch_of_embeddings = np.array([
    [0.12, -0.05, 0.33, 0.91],
    [0.44, 0.10, -0.22, 0.05],
    [0.03, 0.67, 0.19, -0.41],
])
print(batch_of_embeddings.shape)   # (3, 4) -> 3 documents, each a 4-number embedding

Expected Output:

(4,)
(3, 4)

A real embedding model (e.g., producing 1536-dimensional vectors) would give you (1536,) for one piece of text, or (batch_size, 1536) for many. When something in your AI pipeline throws a shape-mismatch error, this is exactly the concept you’ll be debugging.


4. Indexing and Slicing (NumPy)

vector = np.array([10, 20, 30, 40, 50])

print(vector[0])        # 10
print(vector[-1])       # 50
print(vector[1:4])      # [20 30 40]

matrix = np.array([[1, 2, 3],
                    [4, 5, 6],
                    [7, 8, 9]])

print(matrix[0])        # [1 2 3]        -> first row
print(matrix[0, 1])     # 2              -> row 0, column 1
print(matrix[:, 1])     # [2 5 8]        -> every row, column 1 only
print(matrix[1:, :2])   # rows 1+, first 2 columns

Expected Output:

10
50
[20 30 40]
[1 2 3]
2
[2 5 8]
[[4 5]
 [7 8]]

🧠 Intuition: matrix[row, column] — comma-separated indexing lets you reach directly into a specific cell or slice of a grid, something plain nested Python lists make much clumsier (matrix[row][col] everywhere).

🤖 How Is This Used in AI? Pulling a single embedding out of a batch (batch_of_embeddings[2]), or grabbing one specific dimension across every embedding in a batch (batch_of_embeddings[:, 0]) — common when inspecting or debugging embedding data.


5. Vector Operations

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(a + b)    # [5 7 9]     element-wise addition
print(a - b)    # [-3 -3 -3]  element-wise subtraction
print(a * b)    # [4 10 18]   element-wise multiplication
print(a / b)    # [0.25 0.4 0.5]

# Dot product — multiply matching elements, then sum them
dot_product = np.dot(a, b)
print(dot_product)   # 1*4 + 2*5 + 3*6 = 32

Expected Output:

[5 7 9]
[-3 -3 -3]
[ 4 10 18]
[0.25 0.4  0.5 ]
32

🧠 Intuition

Regular Python math operators work element by element, automatically, across the whole array — no loop required.

🤖 How Is This Used in AI?

The dot product is the mathematical heart of measuring how similar two embeddings are. A simplified but genuinely accurate version of cosine similarity:

def cosine_similarity(vec_a, vec_b):
    dot = np.dot(vec_a, vec_b)
    magnitude_a = np.linalg.norm(vec_a)
    magnitude_b = np.linalg.norm(vec_b)
    return dot / (magnitude_a * magnitude_b)

query_embedding = np.array([0.9, 0.1, 0.3])
doc_embedding_a = np.array([0.8, 0.2, 0.35])   # similar direction
doc_embedding_b = np.array([-0.5, 0.9, -0.1])  # very different direction

print(cosine_similarity(query_embedding, doc_embedding_a))
print(cosine_similarity(query_embedding, doc_embedding_b))

Expected Output:

0.9944...
-0.3218...

Visually, cosine similarity measures the angle between these vectors:

graph LR
    subgraph Cosine Similarity
        origin((Origin)) -->|Query Vector| query["Query: [0.9, 0.1, 0.3]"]
        origin -->|Small Angle| docA["Document A: [0.8, 0.2, 0.35] (Similar)"]
        origin -->|90 degree Angle| docB["Document B: [-0.5, 0.9, -0.1] (Unrelated)"]
    end

This is how a vector database decides “which stored document is most relevant to this query” — under the hood, it’s running this exact calculation (at large scale, with optimized indexing) millions of times.

💡 Dot Product vs. Cosine Similarity: Key Differences & Selection

It is very common to confuse the Dot Product with Cosine Similarity. Here is how they relate and when to choose which one:

1. What are they? Are they the same?

  • Dot Product (ab\mathbf{a} \cdot \mathbf{b}): A raw mathematical operation. It multiplies corresponding elements and sums them. Its output has no bounds (can be anywhere from -\infty to ++\infty), depending entirely on the length (magnitude) of the vectors.
  • Cosine Similarity: A similarity metric that measures only the angle between two vectors, completely ignoring their lengths. It squashes the result to a fixed range between 1-1 and 11 (where 11 means pointing in the exact same direction, 00 means perpendicular, and 1-1 means opposite).

2. Does one use the other?

Yes! Cosine similarity is built on top of the dot product. The formula is:

Cosine Similarity=Dot ProductMagnitude of a×Magnitude of b=abab\text{Cosine Similarity} = \frac{\text{Dot Product}}{\text{Magnitude of } \mathbf{a} \times \text{Magnitude of } \mathbf{b}} = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \|\mathbf{b}\|}

The dot product is the numerator. The denominator acts as a “normalization factor” that strips away the length of the vectors.

3. When do you select which one?

  • Choose Cosine Similarity when vector lengths can vary and you only care about direction/topic. For example, in text retrieval, a document containing the word “AI” 100 times is not 100 times more “related” than a document containing it once. Cosine similarity treats them as similar because their angles are identical.
  • Choose Dot Product when your vectors are pre-normalized (magnitude = 1). In this case, a=1\|\mathbf{a}\| = 1 and b=1\|\mathbf{b}\| = 1, which makes the denominator 1×1=11 \times 1 = 1. The formula simplifies to:

Cosine Similarity=ab\text{Cosine Similarity} = \mathbf{a} \cdot \mathbf{b}

When vectors are normalized to length 1, cosine similarity and dot product give the same ranking. Some embedding models already produce normalized vectors and some vector databases can normalize them, but this is not a universal requirement. Choose the metric recommended for the particular embedding model and index. Also remember that cosine 0 means perpendicular in the vector space; calling that “unrelated” is an interpretation, not a law of mathematics.

⚠️ Common Beginner Mistake: Trying to add/multiply two arrays of different shapes without understanding broadcasting rules (next section) leads to confusing ValueError: operands could not be broadcast together errors — this is almost always a shape mismatch.


6. Matrix Operations

matrix_a = np.array([[1, 2],
                      [3, 4]])
matrix_b = np.array([[5, 6],
                      [7, 8]])

print(matrix_a + matrix_b)          # element-wise addition
print(matrix_a @ matrix_b)          # matrix multiplication (the @ operator)
print(matrix_a.T)                   # transpose — flip rows and columns

Expected Output:

[[ 6  8]
 [10 12]]
[[19 22]
 [43 50]]
[[1 3]
 [2 4]]

🧠 Intuition: @ is not the same as *. * multiplies matching positions; @ performs true matrix multiplication (rows of the first matrix combined with columns of the second) — the operation neural networks are built from at every layer.

🤖 How Is This Used in AI? You will rarely hand-write matrix multiplication yourself in application-level AI work (PyTorch/TensorFlow handle it), but recognizing @ and understanding “this combines a batch of embeddings against a batch of documents” will help you read framework source code and debug shape errors with confidence.

💡 Understanding Matrix Axes (axis=0 vs axis=1)

When you perform operations on 2D arrays (matrices)—like taking the average or sum—you must specify which axis to run the calculation along. This is one of the most common points of confusion for beginners.

graph TD
    subgraph "Array Axes"
        direction TB
        row1["[ Row 0:  1,  2,  3 ]"]
        row2["[ Row 1:  4,  5,  6 ]"]

        row1 -->|axis=0: Downwards| row2
        col1["Col 0: [1, 4]"] -->|axis=1: Sideways| col2["Col 1: [2, 5]"]
    end
  • axis=0 (Downwards / Col-wise): Collapses rows to calculate a result for each column.
  • axis=1 (Sideways / Row-wise): Collapses columns to calculate a result for each row.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])

# Sum along axis=0 (collapses rows downwards)
print(np.sum(matrix, axis=0))  # [1+4, 2+5, 3+6] = [5, 7, 9]

# Sum along axis=1 (collapses columns sideways)
print(np.sum(matrix, axis=1))  # [1+2+3, 4+5+6] = [6, 15]

7. Broadcasting

What Is It?

Broadcasting is NumPy’s rule for performing operations between arrays of different shapes, by automatically “stretching” the smaller one.

vector = np.array([1, 2, 3])
print(vector + 10)          # adds 10 to every element
# [11 12 13]

matrix = np.array([[1, 2, 3],
                    [4, 5, 6]])
row_adjustment = np.array([10, 20, 30])
print(matrix + row_adjustment)
# [[11 22 33]
#  [14 25 36]]

Expected Output:

[11 12 13]
[[11 22 33]
 [14 25 36]]

🧠 Intuition

Broadcasting is NumPy silently repeating a smaller array across a larger one so their shapes line up — you get to write matrix + row_adjustment instead of manually looping through every row.

Real-World Analogy

Think of stamping the same small logo (the smaller array) onto every page of a big document (the larger array), without manually copying the logo onto each page yourself.

🤖 How Is This Used in AI?

Normalizing a batch of embeddings (dividing each embedding by its own magnitude) or scaling every embedding in a batch by the same factor both rely on broadcasting to happen efficiently, without an explicit Python loop.

⚠️ Common Beginner Mistake: Assuming any two shapes will broadcast together. They won’t — broadcasting follows specific compatibility rules (matching or 1-sized dimensions). Shape mismatches here are one of the most common real debugging sessions in AI code.


8. Why NumPy Matters for AI

Without NumPyWith NumPy
Loop through lists manually to do mathWhole-array operations, no explicit loop
Slow on large data (thousands+ of numbers)Highly optimized, fast at scale
No natural concept of “shape”Shape is explicit and checkable
Hard to compute similarity between vectorsnp.dot, np.linalg.norm built in

Key Takeaway: Every embedding you’ll ever touch — whether from OpenAI, Anthropic, or an open-source model — arrives as (or is easily converted to) a NumPy array. Vector similarity, batching, and normalization all rest on the operations in this section.


9. Introduction to Pandas

What Is It?

Pandas is a library for working with tabular data — rows and columns, like a spreadsheet — with much more power than a plain CSV reader.

Why Does It Exist?

Datasets (evaluation results, labeled examples, logs, documents with metadata) are naturally table-shaped. Pandas gives you fast, expressive tools to filter, clean, and transform that kind of data — things that would take many lines of manual list/dict code otherwise.

pip install pandas
import pandas as pd   # "pd" is the near-universal convention

10. Series

What Is It?

A Series is a single labeled column of data — think of it as one column from a spreadsheet.

scores = pd.Series([0.9, 0.4, 0.75, 0.6], name="relevance_score")
print(scores)

Expected Output:

0    0.90
1    0.40
2    0.75
3    0.60
Name: relevance_score, dtype: float64

🧠 Intuition: A Series is a NumPy array with labels attached to each value (the numbers on the left, called the index).


11. DataFrames

What Is It?

A DataFrame is a full table — multiple named columns (each internally a Series), like a complete spreadsheet.

data = {
    "question": ["What is Python?", "What is RAG?", "What is an embedding?"],
    "score": [0.9, 0.85, 0.72],
    "source": ["docs.txt", "docs.txt", "notes.txt"],
}

df = pd.DataFrame(data)
print(df)

Expected Output:

                 question  score    source
0        What is Python?   0.90  docs.txt
1           What is RAG?   0.85  docs.txt
2  What is an embedding?   0.72  notes.txt

🧠 Intuition

A DataFrame is a spreadsheet living inside Python — rows, columns, labels, all queryable with code instead of mouse clicks.

Real-World Analogy

If a Series is one column of an Excel sheet, a DataFrame is the whole sheet — many columns, working together, each row representing one record.

💡 Creating DataFrames from JSON-like Shapes

In AI applications, data often arrives as a list of dictionaries (the standard shape of a JSON array) rather than a dictionary of lists. Pandas handles this shape natively:

json_data = [
    {"question": "What is Python?", "score": 0.9, "latency_ms": 150},
    {"question": "What is RAG?", "score": 0.85, "latency_ms": 220},
    {"question": "What is an embedding?", "score": 0.72, "latency_ms": 180},
]
df_from_json = pd.DataFrame(json_data)
print(df_from_json)

Expected Output:

                question  score  latency_ms
0        What is Python?   0.90         150
1           What is RAG?   0.85         220
2  What is an embedding?   0.72         180

💡 Vectorized Column Operations (No Loops Needed!)

Just like NumPy, Pandas columns support vectorized operations. If you want to compute a new column by combining or modifying existing ones, never write a loop. You can perform calculations directly on the columns:

# Calculate latency in seconds
df_from_json["latency_seconds"] = df_from_json["latency_ms"] / 1000
print(df_from_json[["question", "latency_seconds"]])

Expected Output:

                question  latency_seconds
0        What is Python?            0.150
1           What is RAG?            0.220
2  What is an embedding?            0.180

This runs instantly because Pandas delegates the math directly to NumPy’s compiled C code under the hood!


12. Reading CSV with Pandas

# Recall Module 7 — we wrote results.csv with plain Python's csv module.
# Pandas reads (and understands types in) the same kind of file directly:

df = pd.read_csv("results.csv")
print(df)
print(df.dtypes)

Expected Output (approximate, depends on file content):

          question  score
0  What is Python?   0.90
1     What is RAG?   0.85
question     object
score       float64
dtype: object

🧠 Note the difference from Module 7’s raw csv module: Pandas automatically converts "0.9" into the actual float 0.9 — no manual float(...) conversion needed. This is one of the biggest reasons Pandas is preferred over the plain csv module for real datasets.

🤖 How Is This Used in AI? Loading a labeled evaluation dataset, a benchmark of question/answer pairs, or logged model outputs — almost always as a first step: df = pd.read_csv("eval_results.csv").


13. Filtering Data

data = {
    "question": ["Q1", "Q2", "Q3", "Q4"],
    "score": [0.92, 0.45, 0.81, 0.30],
    "source": ["wiki", "notes", "wiki", "notes"],
}
df = pd.DataFrame(data)

# Bad / naive approach — looping manually like plain Python
high_score_rows = []
for i in range(len(df)):
    if df.loc[i, "score"] >= 0.7:
        high_score_rows.append(df.loc[i])

# Better approach — Pandas boolean filtering, no explicit loop
high_scores = df[df["score"] >= 0.7]
print(high_scores)

# Combining multiple conditions
wiki_high_scores = df[(df["score"] >= 0.7) & (df["source"] == "wiki")]
print(wiki_high_scores)

Expected Output:

  question  score source
0       Q1   0.92   wiki
2       Q3   0.81   wiki
  question  score source
0       Q1   0.92   wiki
2       Q3   0.81   wiki

Why the better approach matters in AI

Real evaluation datasets can have thousands or millions of rows. The boolean-filtering style (df[condition]) is dramatically faster than a Python for loop, and it’s also the standard, idiomatic way every real data-analysis and AI-evaluation script is written — code reviewers and teammates will expect this style, not manual loops.

⚠️ Common Beginner Mistake: Using and/or (Python’s regular logical operators) instead of &/| when combining Pandas conditions. Regular and/or don’t work correctly on Series and will raise an error — always use & and |, with each condition wrapped in parentheses.

🤖 How Is This Used in AI? Filtering an evaluation dataset down to “only the questions the model answered incorrectly,” or “only documents above a relevance threshold,” is one of the most common operations in any AI evaluation or data-prep workflow.


14. Handling Missing Data

data = {
    "question": ["Q1", "Q2", "Q3"],
    "score": [0.9, None, 0.75],   # Q2's score is missing
}
df = pd.DataFrame(data)
print(df)
print(df.isna())            # True where data is missing

# Option 1: drop rows with missing data
print(df.dropna())

# Option 2: fill missing data with a default value
print(df.fillna(0))

Expected Output:

  question  score
0       Q1   0.90
1       Q2    NaN
2       Q3   0.75
   question  score
0     False  False
1     False   True
2     False  False
  question  score
0       Q1   0.90
2       Q3   0.75
  question  score
0       Q1   0.90
1       Q2   0.00
2       Q3   0.75

🧠 Intuition: NaN (“Not a Number”) is Pandas’ way of representing “missing” — you must consciously decide whether to drop those rows or fill them with a sensible default, because leaving NaN in place will silently break later calculations.

🤖 How Is This Used in AI? Real-world logged data is messy — some requests fail to log a score, some rows have missing metadata. Deciding how to handle missing evaluation scores or missing document fields is a routine, important step before that data feeds into any analysis or model.


15. Data Transformation

df = pd.DataFrame({
    "question": ["What is Python?", "What is RAG?"],
    "score": [0.92, 0.45],
})

# Add a new column derived from an existing one
df["label"] = df["score"].apply(lambda s: "high" if s >= 0.7 else "low")
print(df)

# Apply a transformation to an entire column at once
df["question_upper"] = df["question"].str.upper()
print(df)

# Sort by a column
sorted_df = df.sort_values("score", ascending=False)
print(sorted_df)

Expected Output:

           question  score label
0  What is Python?   0.92  high
1     What is RAG?   0.45   low
           question  score label    question_upper
0  What is Python?   0.92  high  WHAT IS PYTHON?
1     What is RAG?   0.45   low     WHAT IS RAG?
           question  score label    question_upper
0  What is Python?   0.92  high  WHAT IS PYTHON?
1     What is RAG?   0.45   low     WHAT IS RAG?

🤖 How Is This Used in AI? .apply(lambda ...) is exactly how you’d label evaluation results, categorize confidence scores, or run a cleaning function across an entire column of raw text before embedding it — the DataFrame equivalent of the list comprehensions from Module 4, but built for tabular data at scale.


16. Why Pandas Matters for AI

TaskWhy Pandas helps
Loading evaluation datasetsread_csv handles types automatically
Filtering results by score/categoryFast, readable boolean filtering
Cleaning messy logged dataBuilt-in missing-data handling
Preparing features before embedding.apply() transforms whole columns at once
Summarizing model performanceBuilt-in aggregation (.mean(), .describe(), .groupby())
df = pd.DataFrame({"score": [0.9, 0.4, 0.75, 0.6, 0.85]})
print(df["score"].mean())
print(df["score"].describe())

Expected Output:

0.7
count    5.000000
mean     0.700000
std      0.196723
min      0.400000
25%      0.600000
50%      0.750000
75%      0.850000
max      0.900000
Name: score, dtype: float64

🤖 A single line like df["score"].mean() is often exactly how you’d report “average relevance score across an evaluation run” for an AI system — this is a real, common step in evaluating RAG pipelines and model outputs.

Key Takeaway: NumPy is for numbers and vectors (embeddings, similarity math). Pandas is for tables of records (datasets, logs, evaluation results). Real AI projects use both, often together — NumPy inside the model/embedding layer, Pandas around the data/evaluation layer.


Dtypes, Views, and Precision

A NumPy array normally uses one dtype, such as int32, float32, or float64, for all its elements. The dtype controls memory use, numeric range, and precision. A small integer dtype can overflow, while lower-precision floats can round values. Always inspect array.dtype when exact behaviour matters.

A slice can be a view into the original array rather than an independent copy:

values = np.array([10, 20, 30])
view = values[:2]
view[0] = 99
print(values)  # [99 20 30]

Use .copy() when the new array must change independently. Vectorized NumPy operations are usually valuable for large numeric arrays, but a tiny array or an object-dtype array may not gain the same speed advantage.

Prevent Data Leakage

Suppose missing ages are filled with the average age and numeric columns are normalized. Calculate those values from the training split only, save them, and reuse them for validation, test, and future inputs.

training data ── fit mean/scaling values ──┐
                                          ├── transform each split
validation/test data ─────────────────────┘

If test data helps calculate preprocessing values, information from the final exam has leaked into the lesson. The evaluation may look better than the model will perform on truly new data.

Module Summary

You can now create and reason about NumPy arrays and their shapes, perform vector and matrix math (including the dot product behind cosine similarity), understand broadcasting, and — on the Pandas side — build and filter DataFrames, handle missing data responsibly, transform columns, and summarize results with simple aggregations.

AI Connection

This module is the direct bridge between “Python fundamentals” and “actual AI/ML code.” Embeddings are NumPy arrays. Similarity search is dot products and norms. Evaluation datasets, logged results, and labeled data are Pandas DataFrames. When you next open a PyTorch tutorial, a RAG pipeline’s retrieval code, or an evaluation script, you’ll recognize the shapes, operations, and vocabulary immediately.

Mini Practice

  1. Create two NumPy vectors representing simplified “embeddings” and compute their cosine similarity using the function from this module.
  2. Create a (3, 4) NumPy array representing a batch of 3 embeddings, each with 4 dimensions, and print its shape.
  3. Build a small Pandas DataFrame of 5 question/score pairs, then filter it down to only rows with score >= 0.6.
  4. Given a DataFrame with a score column containing a missing value, fill the missing value with the column’s mean using .fillna(df["score"].mean()).
  5. Add a new column to a DataFrame labeling each row "pass" or "fail" based on whether score >= 0.5, using .apply() with a lambda.

Next: Module 10 — Advanced Python — generators, decorators, context managers, and type hints: the patterns inside real AI frameworks.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed