Programming for Data Processing

Lectures: Nguyễn Tuấn Phong, Đào Việt Anh

Labs: Trịnh Ngọc Huỳnh, Phạm Tiến Du

Semester: 2025-2026-1

Institute for AI, VNU-UET

Cute panda illustration

Lecture 6
Getting Started with Pandas

1.
Overview

What & Why

  • pandas = data structures + tools for fast, convenient data cleaning/analysis
  • Works great with: NumPy, SciPy, statsmodels, scikit-learn, matplotlib
  • NumPy-style array computing, vectorized operations (no Python loops)

pandas vs NumPy

  • pandas: tabular / heterogeneous data
  • NumPy: homogeneous numeric arrays

Community

  • Open source since 2010, large & active ecosystem
  • 2,500+ contributors; widely used in real-world analytics

Imports

Convention: pd. refers to pandas:

Importing Series / DataFrame directly also common:

2.
Pandas
Data Structures

Outline

  1. Series ⭐ →
  2. DataFrame ⭐ →
  3. Index Objects →

2.1.
Series ⭐

What is a Series?

  • 1D, array-like values + labeled index
  • Homogeneous dtype (NumPy-like)
  • Think of as: ordered dict (label → value)

Create a Series

Use pd.Series to create a Series:

Implicit Index

Series has an implicit index:

Custom Index

Label Selection

Use labels in the index to select/assign

Vectorized Operations

Preserve index → value linkage

Vectorized Operations

Can also apply NumPy functions

Dict Interoperability

Construct from dict

Dict Interoperability

Convert back with to_dict

Reindex (Explicit Order)

Provide an index; missing labels → NaN (Not a Number)

Detect Missing

Use isna / notna to detect missing values

Automatic Alignment

  • Arithmetic aligns by label (union of labels)
  • Non-overlap → NaN (like an outer join in databases)

Names

Use .name and .index.name to set names

Rename Index

Assign new labels directly (in place) using .index

2.2.
DataFrame ⭐

What is a DataFrame?

  • 2D, tabular data with labeled rows & columns
  • Think of as: Dictionary of Series sharing the same index

Create a DataFrame

Most common: from a dict of equal-length lists

Peek at Rows

For large DataFrames, use .head() and .tail() to quickly inspect first/last 5 rows.

Column Order & Missing

  • Use columns=[...] to specify column order
  • Column names must match; if missing → NaN

Column Access

  • Can use dict-style [...] or attribute-style . access
  • Return Series, with name attribute
  • ⚠️ . access: Only for valid identifiers

Row Selection

  • loc by label, iloc by position
  • More on this later

Assign Columns

From Scalars

Scalar fills column

Assign Columns

From Arrays

Array must match length of DataFrame

Assign Columns

From Series

Aligns by index; others → NaN

New Columns

Create new columns with assignment:

⚠️ Cannot create new columns with . access!

Drop Columns

Remove columns with del

DataFrame From Nested Dict

  • Outer dict keys → DataFrame columns
  • Inner dict keys → DataFrame index
  • Missing values → NaN

Overriding Index

  • Use index= to override inner keys
  • Missing values → NaN

DataFrame From Dict of Series

Dict of Series → indexes are unioned (label alignment across Series)

DataFrame Constructor Inputs

Type Notes
2D ndarray Matrix of data; optional row/column labels
Dict of arrays/lists/tuples Each sequence → column; all sequences same length
NumPy structured/record array Treated like “dict of arrays”
Dict of Series Values → columns; row index = union of Series indexes (if no explicit index)
Dict of dicts Inner dicts → columns; row index = union of inner keys
List of dicts/Series Each item → row; columns = union of keys/indexes
List of lists/tuples Treated like 2D ndarray
Another DataFrame Reuses its indexes unless overridden
NumPy MaskedArray Like 2D ndarray; masked values become missing

Transpose

Similar to NumPy: Use .T to swap rows & columns

⚠️ Mixed dtypes + transpose can coerce to object.

Names

Use .index.name/.columns.name to set names

→ Useful in multi-indexed DataFrames

To NumPy

to_numpy() → 2D ndarray

Mixed dtypes → object

2.3.
Index Objects

What is an Index?

  • Holds axis labels + metadata (e.g., name)
  • Inputs to Series/DataFrame are converted to an Index

Construct & Inspect

Immutability & Sharing

Immutable → safer to share across objects

Set-like Behavior

Index supports membership tests and set logic

Duplicate Labels

  • Unlike sets, an Index can contain duplicates
  • Selection with a duplicate label returns all occurrences

Index: Useful Methods

Method/Property Description
append() Concatenate with additional Index objects
difference() Set difference
intersection() Set intersection
union() Set union
isin() Boolean mask for membership
delete(i) New Index with position i removed
drop(vals) New Index without specified labels
insert(i, val) Insert at position i
is_monotonic True if non-decreasing
is_unique True if no duplicates
unique() Array of unique labels

3.
Essential Functionality

Outline

  1. Reindexing →
  2. Dropping entries (rows/cols) →
  3. Indexing, selection, filtering ⭐ →
  4. Arithmetic & alignment ⭐ →
  5. Function application & mapping ⭐ →
  6. Sorting & ranking ⭐ →
  7. Axis indexes with duplicate labels →

3.1.
Reindexing

What is Reindexing?

  • Create new object with a new index / column labels
  • Values are rearranged; missing labels become NaN
  • Optional fill methods (e.g., method="ffill")

Series: Reindex

Reorder & introduce new labels → missing become NaN

Series: Fill During Reindex

Use method="ffill" to forward-fill gaps

DataFrame: Construct

DataFrame: Reindex Rows

  • Use keyword index=
  • Missing row “b” filled with NaN

DataFrame: Reindex Columns

  • Use keyword columns=
  • Columns not requested are dropped
  • New column “Utah” filled with NaN

Axis Keyword

Equivalently specify axis with axis="columns"

Reindex via loc

Label-based reordering when labels already exist (no new labels allowed)

reindex Arguments

Argument Description
labels New sequence to use as an index (used as-is if an Index).
index / columns New row / column labels.
axis Which axis to reindex ("index" or "columns").
method Fill method ("ffill", "bfill").
fill_value Value to use for introduced missing data.
limit / tolerance Max gap size (count / distance) to fill.
level Match on a specific level of a MultiIndex.
copy Force data copy even if new index is equivalent.

3.2.
Dropping Entries from an Axis

Concept

  • Remove labels from an axis with .drop
  • Returns a new object (not in-place)
  • Works on rows (index) and columns (columns or axis)

Series: Build Example

Series: Drop Labels

DataFrame: Build Example

DataFrame: Drop Rows

Use index= to remove row labels

DataFrame: Drop Columns

Use columns= or axis synonyms

3.3.
Indexing, Selection, and Filtering ⭐

Series: Construct

Series: Basics

Prefer loc / iloc

loc uses labels; iloc uses integer positions.

💡 Why this matters

Plain [] with integers is label-based if your index is integers, which can be surprising.

Int Index: Different Behavior

Int Index: Different Behavior

When use loc, it is always label-based

Int Index: Different Behavior

When use iloc, it is always position-based

Int Index: Different Behavior

Label slices with loc also include the stop label:

Assigning with loc

💡 Reminder

loc/iloc are indexers, not functions: use square brackets [], not parentheses ().

DataFrame: Column Indexing

Rows & Boolean Filtering

⚠️ Special case: Use slicing with [] or boolean arrays to select rows

Rows & Boolean Filtering

Can also use boolean DataFrame to filter values

DataFrame: loc / iloc

Use loc for label-based indexing

DataFrame: loc / iloc

Use iloc for position-based indexing

DataFrame: loc / iloc

Use iloc for position-based indexing

Slices & Boolean with loc

Integer Indexing Pitfalls

Plain [] with integers is label-based if your index is integers

Integer Indexing Pitfalls

If your index is non-integer, plain [] with integers is position-based

Integer Indexing Pitfalls

✅ Best practice: Use .loc for labels and .iloc for positions to avoid ambiguity.

Pitfalls with Chained Indexing

Avoid assigning through chained selections; use a single loc instead.

Pitfalls with Chained Indexing

Avoid assigning through chained selections; use a single loc instead.

Cheat Sheet: Common Indexing

Type Notes
df[column] Select column(s); special cases: boolean filter, row slice
df.loc[rows] Rows by label
df.loc[:, cols] Cols by label
df.loc[rows, cols] Rows & cols by label
df.iloc[rows] Rows by integer position
df.iloc[:, cols] Cols by integer position
df.iloc[rows, cols] Rows & cols by integer position
df.at[row, col] Single scalar by labels
df.iat[row, col] Single scalar by positions
reindex Select rows or columns by labels

3.4.
Arithmetic &
Data Alignment ⭐

Key idea: label alignment

  • pandas aligns on index/column labels before doing math.
  • Labels present in only one operand → result is NaN.
  • Use arithmetic methods (e.g., add) with fill_value to control missing parts.

Series + Series: union of labels

Labels d/f/g only appear in one Series ⇒ NaN after alignment.

DF + DF: align on rows & cols

DF + DF: align on rows & cols

Only overlapping (row, col)'s produce numbers; else NaN.

Filling gaps during arithmetic

Plain + (NaNs remain)
Using add(fill_value=0)

Reverse-op twins

Each arithmetic method has an r* variant with reversed arguments:

Other methods: radd, rsub, rmul, rdiv, rfloordiv, rpow

DataFrame ± Series

  • Series index matches DataFrame columns
  • Values are broadcast down rows

DataFrame ± Series

DataFrame ± Series

Columns not in the Series become NaN:

Broadcast across columns

Use a method and pass axis="index" to match on rows:

“axis” here means: the axis to align/match on.

Tips

  • Need zeros instead of NaN?
    • Prefer df1.add(df2, fill_value=0) over filling beforehand.
  • Mismatched labels ≠ error:
    • They quietly become NaN and can propagate.
  • reindex(..., fill_value=...) can prep shapes before arithmetic.

3.5.
Function Application
& Mapping ⭐

NumPy ufuncs on pandas

NumPy ufuncs work element-wise on Series/DataFrame

Per column operation

Use DataFrame.apply to apply a 1D function to each column (default):

Per row operation

Use DataFrame.apply with axis="columns" → apply across columns (once per row):

⚠️ Many stats (e.g., sum, mean) are built-in methods; apply isn’t always needed.

Return multiple values

Return a Series → becomes a DataFrame of results:

Element-wise functions

  • applymap → element-wise on a DataFrame
  • Series.map → element-wise on a Series

3.6.
Sorting &
Ranking ⭐

Sort by labels: sort_index

  • Lexicographic sort by index/column labels.
  • Works on Series and DataFrame; choose axis.

DataFrame: sort by index

Sort by values: sort_values

Series: order by the data (NaNs last by default).

DataFrame: sort by columns

Tips

  • sort_index → sort by labels; sort_values → sort by data.
  • Control NaN placement with na_position ("last" default, or "first").
  • For multi-key sorts, pass a list: df.sort_values(["key1","key2"]).

Ranking: rank

  • Assigns ranks 1..N after sorting.
  • Default tie-break = average (ties get mean rank → floats).
  • ascending=False → larger values get rank 1.

Ranking: grade leaderboard

We’ll rank students by score (higher = better).

Leaderboard view

sort by score

Just sorting first helps see the order.

Default ranking: average ties

rank(ascending=False) — ties get the average of their positions.

Why 1.5 for Ava & Chloe? They tie for 1st and 2nd → average is (1+2)/2.

Tie-break by first appearance

rank(ascending=False, method="first") — earlier entry wins the lower rank.

Among tied 95s, Ava appears before Chloe in the data → Ava gets 1, Chloe 2.

Other tie policies

min: give the whole tie the best (lowest) rank number.

max: give the whole tie the worst (highest) rank number.

Other tie policies

dense: like min, but ranks don’t skip numbers between distinct scores.

DataFrame ranking

  • Across columns (per row): rank each row’s values (e.g., a student’s subjects).
  • Down rows (per column): rank within each column (e.g., class leaderboard per subject).

Example data

Rank across columns (per row)

“Which subject is each student best at?” (higher score → better rank)

Ties get the average rank (Dan’s three equal scores → all 2.0).

Rank down rows (per column)

“Who ranks #1 in each subject?” (higher score → better rank)

Tie-breaking methods

For Series/DataFrame.rank

Method Description
"average" Default: average rank within ties
"min" All ties get the minimum rank
"max" All ties get the maximum rank
"first" Order of appearance decides ranks
"dense" Like "min", but ranks increase by 1 per group

3.7.
Axis Indexes with
Duplicate Labels

Key idea

duplicates are allowed

  • Index (row/column labels) need not be unique.
  • Some ops (e.g., reindex) expect uniqueness, but most selection & math still work.
  • Behavior changes: selecting a duplicate label returns multiple rows.

Series: duplicate labels

Series selection with duplicates

Selecting a label returns:

  • Series when the label appears multiple times
  • Scalar when it appears once

DataFrame: duplicate row labels

DataFrame selection with duplicates

.loc returns a DataFrame if the label is duplicated; otherwise a Series.

Working safely with duplicates

  • Find duplicates in the index:
  • Drop later duplicates (keep first):
  • Aggregate duplicate groups (e.g., sum or mean):

Takeaways

  • Duplicates change selection return types (Series vs DataFrame).
  • Use index.is_unique or index.duplicated() to check/handle duplicates.
  • Pick a policy: keep first/last duplicate, or aggregate with groupby(level=0).

4.
Summarizing &
Descriptive Statistics

Outline

  1. Reductions ⭐ →
  2. Indirect statistics ⭐ →
  3. Correlation and covariance →
  4. Unique values, value counts, membership →

4.1.
Reductions ⭐

Overview

  • Reductions return one value per axis: sum, mean, min/max, …
  • Handle missing data by default (skipna=True).
  • Axis matters: axis="index" (down rows) vs axis="columns" (across columns).

Set up a tiny DataFrame

reductions

Column-wise vs row-wise

Default skipna=True: ignore NaNs (all-NaN → 0 for sum).

Missing data: skipna

When skipna=False:

  • any NaN on the reduction axis → result is NaN.

More reductions

Some methods, e.g. mean, require at least one non-NaN value to compute a result.

4.2.
Indirect Statistics ⭐

Indirect statistics

Some methods, like idxmin and idxmax, return indirect statistics (index/label of min/max value).

Accumulations

multi-stat summary

describe on non-numeric

Tips

  • Prefer built-ins: df.mean(), df.quantile(), df.idxmax(), etc.
  • Set axis explicitly when teaching/reading code.
  • Control NaNs with skipna; default is True.
  • See Table 5.8: Descriptive and summary statistics for more descritive and summary stats.

4.3.
Correlation & Covariance

Key idea

  • Series: s1.corr(s2), s1.cov(s2) align on index first.
  • DataFrame: df.corr() / df.cov() → full matrices.
  • corrwith computes pairwise correlations vs another Series/DataFrame.

Setup: prices → daily returns

Real stock data: daily prices & volumes. Available here.

Series ↔ Series

.corr: Pearson correlation (aligning on index)

.cov: covariance (aligning on index)

DataFrame ↔ DataFrame

corr / cov: full pairwise matrices

corrwith

pairwise vs Series / DataFrame

Use axis="columns" to compute row-wise.

Takeaways

  • Correlations align labels automatically before computing.
  • Use corr/cov for full matrices; corrwith for pairwise columns/rows.

4.4.
Unique Values, Value Counts, Membership

Key idea

  • unique → unique values (array).
  • value_counts → frequencies (Series, sorted desc by default).
  • isin → vectorized membership filter.
  • Index.get_indexer → map values to integer positions.

Unique & value counts

Membership testing with isin

Map values → positions

Index.get_indexer: map values to integer positions (or -1 if not found).

Counts across multiple columns

DataFrame.value_counts

Counts distinct rows (tuples) in the DataFrame.

Takeaways

  • unique, value_counts for 1-D distributions.
  • isin builds Boolean filters; combine with [] or loc.
  • For many columns, df.apply(pd.value_counts) + fillna(0) gives a compact histogram table.

Wrap-up

  • What is pandas? Labeled, columnar data (Series/DataFrame) with alignment and NaN-aware ops.
  • Apply functions: per row/column or element-wise.
  • Order & compare: sort/rank; relate columns with correlation/covariance.
  • Summarize: reductions & accumulations; be mindful of axis and duplicate labels.
Next: Advanced Topics in Pandas