⬡ Hub
Skip to content

Pandas: Indexing, Selecting, and Slicing Data

Efficiently accessing specific subsets of data is fundamental to data analysis. Pandas provides powerful and flexible ways to index, select, and slice data from Series and DataFrame objects. This document will cover the primary methods: [], .loc[], and .iloc[], along with boolean indexing.

1. Understanding .loc[] and .iloc[]

These are the two main methods for indexing and selecting data in Pandas, and it's crucial to understand their distinction:

  • .loc[] (Label-based indexing): Used for selection by label (index names and column names).
    • When slicing with loc, both the start and end labels are included.
  • .iloc[] (Integer-location based indexing): Used for selection by position (0-based integer position).
    • When slicing with iloc, the start position is included, but the end position is excluded (just like standard Python slicing).

Let's create a sample DataFrame to demonstrate these methods:

import pandas as pd
import numpy as np

# Create a DataFrame with custom index and columns
data = {
    'A': [1, 2, 3, 4, 5],
    'B': [6, 7, 8, 9, 10],
    'C': [11, 12, 13, 14, 15]
}
index_labels = ['row1', 'row2', 'row3', 'row4', 'row5']
df = pd.DataFrame(data, index=index_labels)

print("Original DataFrame:\n", df)

2. Selection using [] (Square Brackets)

The [] operator is versatile but can be ambiguous as its behavior changes based on context (single label, list of labels, slice, boolean array).

For Series:

import pandas as pd
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])

# Select single element by label
print("\ns['c']:", s['c'])

# Select single element by integer position
print("s[2]:", s[2])

# Slice by label (inclusive)
print("s['b':'d']:\n", s['b':'d'])

# Slice by integer position (exclusive)
print("s[1:4]:\n", s[1:4])

For DataFrames:

import pandas as pd
df = pd.DataFrame({
    'col1': [1, 2, 3],
    'col2': [4, 5, 6],
    'col3': [7, 8, 9]
}, index=['row_a', 'row_b', 'row_c'])

# Select single column (returns a Series)
print("\ndf['col2']:\n", df['col2'])

# Select multiple columns (returns a DataFrame)
print("\ndf[['col1', 'col3']]:\n", df[['col1', 'col3']])

# Slice rows by integer position (exclusive, like Python lists)
print("\ndf[0:2]:\n", df[0:2])

# Slice rows by label (inclusive, if index is monotonic)
# Caution: This can be confusing, prefer .loc[] for label-based row slicing.
print("\ndf['row_a':'row_b']:\n", df['row_a':'row_b'])

3. Selection using .loc[] (Label-based)

.loc[] is strictly label-based.

Syntax: df.loc[row_label, column_label]

import pandas as pd
df = pd.DataFrame({
    'Col_X': [10, 20, 30],
    'Col_Y': [40, 50, 60]
}, index=['Alpha', 'Beta', 'Gamma'])

print("DataFrame for .loc examples:\n", df)

# Select a single element by row and column label
print("\ndf.loc['Beta', 'Col_Y']:", df.loc['Beta', 'Col_Y'])

# Select a single row by label (returns a Series)
print("\ndf.loc['Alpha']:\n", df.loc['Alpha'])

# Select multiple rows by labels (returns a DataFrame)
print("\ndf.loc[['Alpha', 'Gamma']]:\n", df.loc[['Alpha', 'Gamma']])

# Select rows by label slice (inclusive)
print("\ndf.loc['Alpha':'Beta']:\n", df.loc['Alpha':'Beta'])

# Select multiple columns by labels
print("\ndf.loc[:, ['Col_X']]:\n", df.loc[:, ['Col_X']])

# Select specific rows and columns
print("\ndf.loc[['Alpha', 'Gamma'], ['Col_X']]:\n", df.loc[['Alpha', 'Gamma'], ['Col_X']])

# Boolean indexing with .loc
print("\ndf.loc[df['Col_X'] > 15, 'Col_Y']:\n", df.loc[df['Col_X'] > 15, 'Col_Y'])

4. Selection using .iloc[] (Integer-location based)

.iloc[] is strictly integer-location based (like NumPy arrays).

Syntax: df.iloc[row_position, column_position]

import pandas as pd
df = pd.DataFrame({
    'Col_X': [10, 20, 30],
    'Col_Y': [40, 50, 60]
}, index=['Alpha', 'Beta', 'Gamma'])

print("DataFrame for .iloc examples:\n", df)

# Select a single element by row and column position
print("\ndf.iloc[1, 1]:", df.iloc[1, 1])

# Select a single row by position (returns a Series)
print("\ndf.iloc[0]:\n", df.iloc[0])

# Select multiple rows by positions (returns a DataFrame)
print("\ndf.iloc[[0, 2]]:\n", df.iloc[[0, 2]])

# Select rows by position slice (exclusive of end)
print("\ndf.iloc[0:2]:\n", df.iloc[0:2])

# Select multiple columns by positions
print("\ndf.iloc[:, [0]]:\n", df.iloc[:, [0]])

# Select specific rows and columns by positions
print("\ndf.iloc[[0, 2], [0]]:\n", df.iloc[[0, 2], [0]])

5. Boolean Indexing

Boolean indexing allows you to select data based on conditions. This is very powerful for filtering data.

import pandas as pd
data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David'],
    'Age': [25, 30, 35, 28],
    'City': ['New York', 'Paris', 'London', 'Berlin']
}
df = pd.DataFrame(data)

print("Original DataFrame:\n", df)

# Select rows where Age > 30
print("\nRows where Age > 30:\n", df[df['Age'] > 30])

# Select rows with multiple conditions
print("\nRows where Age > 25 AND City is 'New York':\n", df[(df['Age'] > 25) & (df['City'] == 'New York')])

# Select rows using .isin()
cities_to_find = ['New York', 'London']
print(f"\nRows where City is in {cities_to_find}:\n", df[df['City'].isin(cities_to_find)])

# Using boolean indexing with .loc to select specific columns based on a condition
print("\nNames of people older than 28:\n", df.loc[df['Age'] > 28, 'Name'])

Further Topics:

  • reindex for conforming to new index
  • set_index and reset_index
  • MultiIndex / Hierarchical Indexing
  • Advanced boolean logic with query() method

Mastering indexing and selection is crucial for effective data manipulation and preparation in Pandas. These methods form the backbone of most data cleaning and feature engineering tasks.