Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 5

DataFrame Manipulation with Indexing and Boolean Masking

Recommended resources

Welcome to the fifth lesson of our first module, "Python for Data Science and ML." In our previous lesson, we delved into the world of NumPy, exploring the critical concepts of vectorization and broadcasting. You learned how to replace slow Python loops with highly optimized array operations, a fundamental skill for writing performant numerical code.

Today, we build directly on that foundation by introducing Pandas, the quintessential library for data manipulation and analysis in Python. While NumPy provides the raw power for numerical computation, Pandas offers a higher-level, more intuitive interface for working with structured, tabular data. This lesson will focus on the core skill of data wrangling: how to select, filter, and modify data within Pandas DataFrames. Mastering these operations is the first step toward preparing any dataset for machine learning.

1. From NumPy Arrays to Pandas DataFrames

At its heart, a Pandas DataFrame is a two-dimensional, size-mutable, and potentially heterogeneous tabular data structure with labeled axes (rows and columns). You can think of it as a supercharged spreadsheet or a SQL table, but with the full power of Python.

Crucially, a DataFrame is built upon NumPy arrays. Each column in a DataFrame is a Pandas Series, which is essentially a one-dimensional labeled array. The data within that Series is stored in a NumPy ndarray. This design choice means that the vectorized operations and broadcasting principles you learned in the last lesson apply directly to operations on Pandas Series and DataFrames, allowing for highly efficient data manipulation.


2. The Pillars of Indexing: .loc and .iloc

To work with data in a DataFrame, you first need to know how to access it. Pandas provides two primary, explicit methods for indexing: .loc and .iloc. Understanding the distinction between them is one of the most important foundational concepts in Pandas.

  • .loc[] is label-based. It selects data based on the index labels and column names.
  • .iloc[] is integer position-based. It selects data based on its integer position, starting from 0, just like a standard Python list or NumPy array.

This distinction is especially important when it comes to slicing:

  • Slicing with .loc is inclusive of both the start and end labels.
  • Slicing with .iloc is exclusive of the end position, following Python's convention.

The following image provides a clear visual summary of this core difference.

This infographic contrasts `loc` (label-based, inclusive slicing) with `iloc` (integer-based, exclusive slicing), which are the two primary methods for selecting data in a Pandas DataFrame.

To see these indexers in action, the following video provides a practical walkthrough using a real-world dataset.

Pandas loc and iloc | Pandas loc tutorial | Pandas iloc slicing | loc vs iloc

This tutorial from the CodeWithData channel clearly demonstrates the syntax and behavior of both .loc and .iloc.

First, watch the section on loc to see how to select rows and columns using their labels. Pay close attention to how single items, lists of items, and slices are used for both rows and columns. Watch from the start of the loc explanation. Next, watch the segment on iloc, which explains integer-based indexing. Note the presenter's emphasis on how slicing with iloc is exclusive of the final index, a key difference from loc. Watch from the iloc explanation. Finally, the video provides a concise summary of the differences, which is a great recap.

While the video gives a great overview, it's also useful to read through a detailed guide with more code examples. The following article provides a thorough comparison and addresses some common "gotchas," such as when an operation returns a Series versus a DataFrame.

Pandas iloc and loc – quickly select data in DataFrames

This article by Shane Lynn provides further examples and clarifies common points of confusion between .iloc and .loc.

First, read the section on iloc, Pandas iloc data selection, to reinforce your understanding of integer-position based selection. Then, read the section on loc, focusing on label-based indexing. Notice how it works with both the default integer index and a custom string-based index.


3. Powerful Filtering with Boolean Indexing

Often, you don't want to select data by its position or label, but by its content. For instance, you might want to find all rows where a certain value is above a threshold, or all entries belonging to a specific category. This is achieved using boolean indexing, also known as creating a "mask".

This process directly leverages the vectorized nature of Pandas (and NumPy). When you apply a comparison operator (like ==, >, <) to a Pandas Series, it doesn't return a single True or False. Instead, it performs the comparison element-wise and returns a new Series of boolean values. This boolean Series is your "mask," which you can then use to select rows from your DataFrame.

This image illustrates a boolean mask. The `True`/`False` values correspond to rows in the DataFrame, allowing for the selection of only the rows marked `True`.

The following video masterfully explains this concept, connecting it directly to the broadcasting principle from our last lesson.

Boolean indexing in Pandas made simple

This video by Reuven Lerner provides an exceptionally clear explanation of how boolean indexing works, starting from first principles.

Watch the first segment to understand the basic concept of using a list of booleans to select data from a Series. The next part is crucial, as it connects boolean indexing to broadcasting. Watch how a comparison operator applied to a Series creates a boolean Series, which can then be used to filter the original data. This bridges the gap between our NumPy and Pandas lessons. Finally, see how this concept is extended to DataFrames to filter rows based on a condition in one column, and then select specific other columns.

To filter based on multiple conditions, you can combine boolean masks using the bitwise operators & (and) and | (or). Due to Python's operator precedence rules, you must wrap each individual condition in parentheses.

For example: df[(df['age'] > 30) & (df['country'] == 'Canada')]


4. Modifying Data

Once you've mastered selecting data, modifying it is straightforward. You simply use a selection statement on the left side of an assignment operator (=). The recommended and most robust way to do this is with .loc, as it avoids ambiguity and a common warning in Pandas called SettingWithCopyWarning.

You can modify a single cell, an entire column, or a slice of rows and columns. A particularly powerful pattern is to combine boolean indexing with assignment to conditionally update values.




# Create a sample DataFrame
import pandas as pd
data = {'product': ['A', 'B', 'A', 'C', 'B'],
        'price': [100, 150, 110, 200, 140],
        'in_stock': [True, True, False, True, True]}
df = pd.DataFrame(data)




# Example 1: Update the price of a specific product (row 0)
df.loc[0, 'price'] = 105




# Example 2: Apply a 10% discount to all products
df['price'] = df['price'] * 0.9




# Example 3: Mark all products with a price over 120 as "premium"
df.loc[df['price'] > 120, 'category'] = 'premium'

print(df)

The article you read earlier also has a concise section on this technique.

Pandas iloc and loc – quickly select data in DataFrames

This section shows how to combine .loc selection with assignment to modify DataFrame values.

Read the short section titled Setting values. It demonstrates the syntax for updating values based on a filter.


5. A Comprehensive View of Indexing

While .loc and .iloc are the workhorses of Pandas indexing, you've seen a few other methods. It's helpful to have a consolidated view of all the techniques. The resource below provides an excellent chapter on Pandas, including a handy cheatsheet that summarizes all the selection methods.

Chapter 7: Introduction to Pandas — Python Programming for Data ...

This chapter from "Python Programming for Data Science" provides a comprehensive overview of indexing methods and concludes with a useful summary table.

Quickly review the section on Indexing and Slicing DataFrames. It covers .loc, .iloc, boolean indexing, and also introduces .query(), which can be a more readable, SQL-like alternative for complex filtering. Finally, study the Indexing cheatsheet. This table is an invaluable reference that summarizes the syntax and output of each selection method.


Conclusion

In this lesson, we transitioned from the raw numerical power of NumPy to the flexible data structures of Pandas. You've learned the essential techniques for accessing and manipulating data within a DataFrame, which is the starting point for nearly every data analysis and machine learning task.

Key takeaways from this lesson:

  • DataFrames are built on NumPy, enabling efficient, vectorized operations.
  • .loc[] is for label-based selection and uses inclusive slicing.
  • .iloc[] is for integer position-based selection and uses exclusive slicing.
  • Boolean indexing is a powerful method for filtering data based on its content, by creating a "mask" from one or more conditions.
  • Data can be modified by using a selection accessor like .loc[] on the left side of an assignment.

In our next lesson, we will continue our exploration of Pandas by moving from selecting data to transforming it. We will cover aggregation and reshaping operations using powerful tools like groupby, merge, and pivot, which allow you to summarize and restructure your data to uncover deeper insights.