Tuesday, July 7, 2026
HomeData SciencePandas Cheat Sheet 2026: 50 Most Used Commands with Examples

Pandas Cheat Sheet 2026: 50 Most Used Commands with Examples

Table of Content

Pandas is the backbone of data science in Python. But with hundreds of methods and countless ways to combine them, even experienced practitioners frequently stop to look things up. This cheat sheet collects the 50 commands you will actually reach for in real projects — not the exhaustive reference, but the operations that appear again and again across every type of data work.

Every example uses concise, copy-paste ready code. Bookmark this page and return whenever you need a quick reminder of the right syntax.

Loading and Saving Data

import pandas as pd
import numpy as np

# Load from various sources
df = pd.read_csv('data.csv')                          # CSV
df = pd.read_csv('data.csv', sep='	')                # Tab-separated
df = pd.read_csv('data.csv', encoding='utf-8',        # Encoding + specific cols
                 usecols=['col1','col2','col3'])
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')  # Excel
df = pd.read_json('data.json')                        # JSON
df = pd.read_sql(query, connection)                   # SQL database

# Save
df.to_csv('output.csv', index=False)           # CSV without row numbers
df.to_excel('output.xlsx', index=False)        # Excel
df.to_parquet('output.parquet')                # Parquet (fast, compressed)

First Look at Your Data

df.shape              # (rows, columns)
df.dtypes             # column data types
df.info()             # summary: types, non-null counts, memory
df.head(10)           # first 10 rows
df.tail(5)            # last 5 rows
df.sample(5)          # 5 random rows
df.describe()         # stats for numeric columns
df.describe(include='all')    # stats for all columns including categorical
df.nunique()          # count unique values per column
df.value_counts()     # frequency of each value (for a Series)
df.columns.tolist()   # list all column names

Selecting and Filtering

# Select columns
df['col']                          # single column → Series
df[['col1', 'col2']]               # multiple columns → DataFrame

# Select rows by position
df.iloc[0]                         # first row
df.iloc[0:5]                       # rows 0-4
df.iloc[[0, 5, 10]]                # specific rows

# Select by label
df.loc[0]                          # row with index label 0
df.loc[0:5, 'col1':'col3']         # rows 0-5, columns col1 to col3

# Filter by condition
df[df['age'] > 30]                 # rows where age > 30
df[(df['age'] > 30) & (df['city'] == 'Mumbai')]  # AND condition
df[(df['score'] < 50) | (df['score'] > 90)]      # OR condition
df[df['name'].isin(['Alice', 'Bob'])]             # value in list
df[~df['name'].isin(['Alice', 'Bob'])]            # NOT in list
df[df['email'].str.contains('@gmail')]            # string contains
df.query('age > 30 and city == "Mumbai"')         # query string (cleaner)

Handling Missing Values

# Find missing values
df.isnull().sum()                        # count per column
df.isnull().mean() * 100                 # percentage per column

# Drop missing values
df.dropna()                              # drop rows with ANY missing
df.dropna(subset=['col1', 'col2'])       # drop only if specific cols are null
df.dropna(thresh=5)                      # keep rows with at least 5 non-null

# Fill missing values
df['col'].fillna(0)                      # fill with constant
df['col'].fillna(df['col'].mean())       # fill with mean
df['col'].fillna(df['col'].median())     # fill with median
df['col'].fillna(method='ffill')         # forward fill (propagate last valid)
df['col'].fillna(method='bfill')         # backward fill
df.fillna({'col1': 0, 'col2': 'Unknown'})  # different fill per column

Cleaning and Transforming

# Change data types
df['col'] = df['col'].astype(int)
df['col'] = df['col'].astype(float)
df['date_col'] = pd.to_datetime(df['date_col'])

# Rename columns
df.rename(columns={'old_name': 'new_name'}, inplace=True)
df.columns = [c.lower().replace(' ', '_') for c in df.columns]  # clean all names

# Drop columns / rows
df.drop(columns=['col1', 'col2'], inplace=True)
df.drop_duplicates(inplace=True)
df.drop_duplicates(subset=['email'], keep='first', inplace=True)

# Apply a function
df['col'] = df['col'].apply(lambda x: x.strip().lower())
df['new_col'] = df.apply(lambda row: row['a'] + row['b'], axis=1)

# String operations
df['name'].str.upper()
df['name'].str.lower()
df['name'].str.strip()
df['email'].str.split('@').str[1]      # extract domain
df['col'].str.replace('old', 'new')

GroupBy — Aggregation and Summaries

# Basic groupby
df.groupby('city')['salary'].mean()            # mean salary per city
df.groupby('city')['salary'].agg(['mean','median','std','count'])

# Multiple groupby keys
df.groupby(['city', 'department'])['salary'].mean()

# Multiple aggregations per column
df.groupby('city').agg({
    'salary':  ['mean', 'max'],
    'age':     'median',
    'name':    'count'
})

# Named aggregations (cleaner output)
df.groupby('city').agg(
    avg_salary = ('salary', 'mean'),
    max_salary = ('salary', 'max'),
    headcount  = ('name',   'count')
).reset_index()

# Transform — return same shape as input (useful for adding group stats)
df['avg_dept_salary'] = df.groupby('department')['salary'].transform('mean')

Merging and Joining

# Merge two DataFrames (like SQL JOIN)
merged = pd.merge(df1, df2, on='id', how='inner')   # inner join
merged = pd.merge(df1, df2, on='id', how='left')    # left join
merged = pd.merge(df1, df2, on='id', how='outer')   # full outer join
merged = pd.merge(df1, df2,
                  left_on='user_id', right_on='customer_id',
                  how='left')                         # different key names

# Concatenate — stack DataFrames
combined = pd.concat([df1, df2], ignore_index=True)        # vertically (rows)
combined = pd.concat([df1, df2], axis=1)                   # horizontally (cols)

Pivot Tables and Reshaping

# Pivot table
pivot = df.pivot_table(
    values='revenue',
    index='region',
    columns='quarter',
    aggfunc='sum',
    fill_value=0
)

# Melt — wide to long format
melted = pd.melt(df,
                 id_vars=['name', 'city'],
                 value_vars=['q1_sales', 'q2_sales', 'q3_sales'],
                 var_name='quarter',
                 value_name='sales')

Time Series Operations

df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')

# Extract date components
df['year']    = df.index.year
df['month']   = df.index.month
df['weekday'] = df.index.day_name()

# Resample — aggregate by time period
monthly = df['sales'].resample('M').sum()      # monthly totals
weekly  = df['sales'].resample('W').mean()     # weekly averages

# Rolling statistics
df['7day_avg']  = df['sales'].rolling(window=7).mean()
df['30day_std'] = df['sales'].rolling(window=30).std()

Frequently Asked Questions

What is the difference between loc and iloc in Pandas?

loc selects data using labels — the actual index values and column names. If your DataFrame has a string index like customer IDs, df.loc['CUST001'] returns the row with that label. iloc selects data using integer positions — always counting from zero like a Python list. df.iloc[0] always returns the first row regardless of what the index labels are. A common confusion arises when the index happens to be integers — if your DataFrame has index values [0, 1, 2, …], loc and iloc behave the same. But if the index is [10, 20, 30], df.loc[10] returns the row labelled 10 while df.iloc[0] returns the first row (also labelled 10 in this case). Use iloc when you know the position; use loc when you know the label.

Why does Pandas sometimes modify the original DataFrame and sometimes not?

This is the “SettingWithCopyWarning” problem that confuses almost every Pandas beginner. When you filter a DataFrame and then modify the result, Pandas may be working on a copy rather than the original. Operations that always modify in place with inplace=True: drop(), fillna(), rename(), sort_values(). The safest approach: avoid chaining operations (avoid df[df.a > 1]['b'] = 2) and instead use df.loc[df.a > 1, 'b'] = 2, which modifies the original directly. When in doubt, assign the result to a new variable rather than relying on in-place modification.

What is the fastest way to apply a function to every row?

In order from slowest to fastest: Python for loops (avoid for anything over a few thousand rows), df.apply(func, axis=1) (flexible but slow — pure Python under the hood), df.assign() with vectorised operations (fast — uses NumPy), and direct NumPy operations on the underlying arrays (fastest). The key insight is that Pandas and NumPy operations are “vectorised” — they apply the operation to the entire array in compiled C code rather than looping in Python. Replacing a row-level apply with a vectorised equivalent often speeds up code by 10-100x. For example, instead of df.apply(lambda row: row['a'] + row['b'], axis=1), just write df['a'] + df['b'] — same result, much faster.

How do I handle large datasets that do not fit in memory?

For datasets too large for Pandas to load into RAM, you have several options in 2026. First, try loading only the columns you need with usecols — this alone often reduces memory usage by 50-80%. Second, use dtype argument to specify smaller data types (int32 instead of int64, float32 instead of float64). Third, load the file in chunks: pd.read_csv(file, chunksize=100000) returns an iterator you can process piece by piece. For truly large datasets, switch to Polars (dramatically more memory-efficient than Pandas), DuckDB (run SQL queries on files without loading them), or PySpark for distributed processing. The choice depends on scale: up to a few gigabytes, Polars handles most tasks; beyond that, DuckDB or Spark is appropriate.

Leave feedback about this

  • Rating

Latest Posts

List of Categories