Imports
import pandas as pd
from pandas import DataFrame, Series, Index
from pandas import read_csv, read_excel, read_json, read_sql, read_parquet, read_pickle
from pandas import Timestamp, Timedelta, Period
from pandas import get_option, set_option, option_context
from pandas import NA, NaT
from pandas import concat, merge, pivot_table, melt
from pandas import cut, qcut, get_dummies
from pandas import to_datetime, to_timedelta, to_numeric
from pandas import isna, isnull, notna, notnull
from pandas import date_range, timedelta_range, period_range, interval_range
Core Patterns
Creating DataFrames ✅ Current
import pandas as pd
# From dictionary
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'city': ['NYC', 'SF', 'LA']
})
# From CSV file
df = pd.read_csv('data.csv', index_col=0)
# From Excel file
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# From JSON
df = pd.read_json('data.json', orient='records')
# From Parquet
df = pd.read_parquet('data.parquet')
# From pickle
df = pd.read_pickle('data.pkl')
- DataFrames are two-dimensional labeled data structures with columns of potentially different types
- Use
read_* functions for loading data from various file formats
- Specify
index_col to set which column becomes the row index
copy parameter default changed in v3.0 - see Migration section
Creating Series ✅ Current
import pandas as pd
# From list with index
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'], name='values')
# From dictionary
s = pd.Series({'a': 10, 'b': 20, 'c': 30})
# Extracting from DataFrame
df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
s = df['col1'] # Returns Series
- Series are one-dimensional labeled arrays capable of holding any data type
- Index provides labels for fast lookup
- Series maintain their name attribute for identification
copy parameter default changed in v3.0 - see Migration section
Data Selection and Filtering ✅ Current
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'score': [85, 90, 88]
})
# Select single column (returns Series)
ages = df['age']
# Select multiple columns (returns DataFrame)
subset = df[['name', 'age']]
# Boolean filtering
adults = df[df['age'] >= 30]
# Multiple conditions
high_scorers = df[(df['age'] >= 25) & (df['score'] >= 85)]
# Using .loc for label-based indexing
row = df.loc[0] # First row by index label
value = df.loc[0, 'name'] # Specific cell
# Using .iloc for position-based indexing
row = df.iloc[0] # First row by position
value = df.iloc[0, 1] # First row, second column
- Use bracket notation for column selection
- Boolean indexing filters rows based on conditions
.loc[] uses labels, .iloc[] uses integer positions
- Combine conditions with
& (and), | (or), ~ (not) - wrap each condition in parentheses
- Note: Copy-on-Write behavior changed in v3.0 - selections always return copies
Working with Time Series ✅ Current
import pandas as pd
# Create Timestamp
ts = pd.Timestamp('2024-01-15 14:30:00')
ts = pd.Timestamp(year=2024, month=1, day=15, hour=14, minute=30)
# Create DatetimeIndex
dates = pd.date_range('2024-01-01', periods=10, freq='D')
df = pd.DataFrame({'value': range(10)}, index=dates)
# Create Timedelta
td = pd.Timedelta('2 days')
td = pd.Timedelta(days=2, hours=3)
# Create TimedeltaIndex
deltas = pd.timedelta_range(start='1 day', periods=5, freq='D')
# Create Period
p = pd.Period('2024-01', freq='M')
# Create PeriodIndex
periods = pd.period_range('2024-01', periods=12, freq='M')
# Convert to datetime
df['date'] = pd.to_datetime(df['date_string'])
# Convert to timedelta
df['duration'] = pd.to_timedelta(df['duration_string'])
Timestamp replaces Python's datetime.datetime with nanosecond precision
DatetimeIndex enables time-based indexing and slicing
Timedelta represents duration between two dates or times
Period represents a span of time at a particular frequency
- Use
to_datetime() and to_timedelta() for conversions
Missing Values ✅ Current
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, np.nan, 3],
'B': [4, 5, pd.NA],
'C': [7, pd.NaT, 9]
})
# Detect missing values
has_nulls = df.isna() # or df.isnull()
has_values = df.notna() # or df.notnull()
# Check for any nulls
any_nulls = df['A'].isna().any()
# Drop rows with any null values
df_clean = df.dropna()
# Fill null values
df_filled = df.fillna(0)
df_filled = df.fillna(method='ffill') # Forward fill
# Use pandas NA for missing values
value = pd.NA # Scalable missing value indicator
nat = pd.NaT # Not-a-Time for datetime/timedelta
- Use
.isna() or .isnull() to detect missing values (they are aliases)
- Use
.notna() or .notnull() to detect non-missing values
pd.NA is the recommended missing value indicator for nullable dtypes
pd.NaT is used specifically for datetime/timedelta missing values
- Never compare to NaN directly with
== - always use .isna()
Combining DataFrames ✅ Current
import pandas as pd
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
# Concatenate along rows (vertical stack)
result = pd.concat([df1, df2], axis=0)
# Concatenate along columns (horizontal stack)
result = pd.concat([df1, df2], axis=1)
# Merge (join) DataFrames
left = pd.DataFrame({'key': ['A', 'B'], 'value': [1, 2]})
right = pd.DataFrame({'key': ['A', 'B'], 'value': [3, 4]})
# Inner join
merged = pd.merge(left, right, on='key', how='inner')
# Left join
merged = pd.merge(left, right, on='key', how='left')
# Outer join
merged = pd.merge(left, right, on='key', how='outer')
concat() stacks DataFrames along an axis
merge() performs database-style joins
- Use
how parameter to specify join type: 'inner', 'left', 'right', 'outer'
- Use
on parameter to specify join key(s)
Reshaping Data ✅ Current
import pandas as pd
# Pivot table
df = pd.DataFrame({
'date': ['2024-01', '2024-01', '2024-02', '2024-02'],
'product': ['A', 'B', 'A', 'B'],
'sales': [100, 150, 120, 180]
})
pivot = pd.pivot_table(df, values='sales', index='date', columns='product')
# Melt (unpivot) from wide to long format
melted = pd.melt(df, id_vars=['date'], value_vars=['product'],
var_name='category', value_name='value')
# Create dummy variables (one-hot encoding)
df = pd.DataFrame({'color': ['red', 'blue', 'red', 'green']})
dummies = pd.get_dummies(df['color'], prefix='color')
pivot_table() creates spreadsheet-style pivot tables
melt() transforms wide format to long format
get_dummies() creates dummy/indicator variables for categorical data
Binning and Discretization ✅ Current
import pandas as pd
data = pd.Series([1, 7, 5, 4, 6, 3, 9, 2, 8])
# Cut into equal-width bins
bins = pd.cut(data, bins=3, labels=['low', 'medium', 'high'])
# Cut with custom bin edges
bins = pd.cut(data, bins=[0, 3, 7, 10], labels=['low', 'medium', 'high'])
# Quantile-based discretization (equal-sized bins)
quantiles = pd.qcut(data, q=3, labels=['low', 'medium', 'high'])
cut() bins values into discrete intervals with equal width
qcut() bins values based on quantiles (equal frequency)
- Use
labels parameter to assign custom category names
Type Conversion ✅ Current
import pandas as pd
df = pd.DataFrame({
'numbers': ['1', '2', '3'],
'dates': ['2024-01-01', '2024-01-02', '2024-01-03']
})
# Convert to numeric
df['numbers'] = pd.to_numeric(df['numbers'])
# Convert to datetime
df['dates'] = pd.to_datetime(df['dates'])
# Convert column dtype
df['numbers'] = df['numbers'].astype('int64')
# Convert to categorical
df['category'] = df['category'].astype('category')
to_numeric() converts to numeric types with error handling
to_datetime() converts to datetime with flexible parsing
astype() explicitly converts dtypes
- Use
errors='coerce' parameter to handle conversion failures
Configuring Display Options ✅ Current
import pandas as pd
# Get current option value
max_rows = pd.get_option('display.max_rows')
# Set option value
pd.set_option('display.max_rows', 100)
pd.set_option('display.max_columns', 50)
pd.set_option('display.precision', 2)
# Temporarily set options with context manager
with pd.option_context('display.max_rows', 10, 'display.max_columns', 5):
print(df) # Uses temporary settings
# Outside context, original settings restored
# Reset option to default
pd.reset_option('display.max_rows')
# Describe available options
pd.describe_option('display') # All display options
pd.describe_option('display.max_rows') # Specific option
- Use
get_option() and set_option() for global configuration changes
option_context() provides temporary settings that restore automatically
- Common options:
display.max_rows, display.max_columns, display.precision, display.width
Configuration
Display Settings
# Default values
pd.get_option('display.max_rows') # 60
pd.get_option('display.max_columns') # 20
pd.get_option('display.width') # 80
pd.get_option('display.precision') # 6
# Common customizations
pd.set_option('display.max_rows', None) # Show all rows
pd.set_option('display.max_columns', None) # Show all columns
pd.set_option('display.float_format', '{:.2f}'.format) # Format floats
File Reading Options
# CSV reading with common parameters
df = pd.read_csv(
'data.csv',
sep=',', # Delimiter (default: ',')
header=0, # Row to use as column names (default: 'infer')
index_col=0, # Column to use as row index
usecols=['col1', 'col2'], # Columns to read
dtype={'col1': int, 'col2': str}, # Column data types
parse_dates=['date_col'], # Parse as datetime
na_values=['NA', 'null'], # Additional NA values
encoding='utf-8', # File encoding
nrows=1000, # Number of rows to read
skiprows=5 # Rows to skip at start
)
Index and Data Types
# Creating typed indexes
idx = pd.Index([1, 2, 3], dtype='int64', name='id')
cat_idx = pd.CategoricalIndex(['A', 'B', 'C'], name='category')
range_idx = pd.RangeIndex(start=0, stop=10, step=2)
multi_idx = pd.MultiIndex.from_tuples([('A', 1), ('A', 2), ('B', 1)])
# Creating categoricals
cat = pd.Categorical(['A', 'B', 'A', 'C'], categories=['A', 'B', 'C'], ordered=True)
# Creating intervals
interval = pd.Interval(left=0, right=5, closed='right')
interval_idx = pd.IntervalIndex.from_breaks([0, 1, 2, 3])
Pitfalls
Wrong: Using chained assignment
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# This may not work as expected and raises SettingWithCopyWarning
df[df['A'] > 1]['B'] = 99
Why: Chained indexing creates intermediate copies, so assignment may not affect the original DataFrame.
Right: Use .loc for assignment
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Correctly modifies the original DataFrame
df.loc[df['A'] > 1, 'B'] = 99
Wrong: Iterating over DataFrame rows with loops
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Very slow for large DataFrames
results = []
for i in range(len(df)):
results.append(df.iloc[i]['A'] + df.iloc[i]['B'])
Why: Row-by-row iteration is extremely slow and defeats pandas' vectorization.
Right: Use vectorized operations
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Much faster - operates on entire columns at once
df['result'] = df['A'] + df['B']
Wrong: Not specifying dtype when creating structures
import pandas as pd
# Mixed types cause object dtype (slow operations)
df = pd.DataFrame({'id': ['1', '2', '3'], 'value': [10, 20, 30]})
# df['id'].dtype is 'object', not efficient
Why: Object dtype prevents optimized operations and uses more memory.
Right: Specify dtypes explicitly or convert after creation
import pandas as pd
# Specify dtype at creation
df = pd.DataFrame({
'id': pd.Series([1, 2, 3], dtype='int64'),
'value': [10, 20, 30]
})
# Or convert after creation
df = pd.DataFrame({'id': ['1', '2', '3'], 'value': [10, 20, 30]})
df['id'] = df['id'].astype('int64')
Wrong: Using inplace=True for method chaining
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Cannot chain - inplace returns None
result = df.drop(columns=['B'], inplace=True).reset_index() # Error!
Why: Methods with inplace=True return None, breaking method chains.
Right: Avoid inplace, assign results
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Chain operations naturally
result = df.drop(columns=['B']).reset_index(drop=True)
# Or assign back if needed
df = df.drop(columns=['B'])
References
Migration from v2.x
Copy Semantics Changed
v2.x behavior:
df = pd.DataFrame({'A': [1, 2, 3]})
df2 = df[['A']] # Creates view in many cases
df2.iloc[0, 0] = 99 # May modify original df
v3.0 behavior:
df = pd.DataFrame({'A': [1, 2, 3]})
df2 = df[['A']] # Always creates copy (Copy-on-Write enforced)
df2.iloc[0, 0] = 99 # Never modifies original df
Migration: Copy-on-Write (CoW) is now the default and only mode in pandas 3.0. All indexing operations that return a subset of data will return a new copy. If you need to modify the original DataFrame, use direct assignment with .loc[] or .iloc[] rather than chaining operations.
Constructor Parameter Changes
The copy parameter behavior has changed in DataFrame and Series constructors:
v2.x:
df = pd.DataFrame(data, copy=True) # Explicitly copy data
v3.0:
df = pd.DataFrame(data, copy=None) # Default changed to None
# copy=None respects Copy-on-Write semantics
# copy=True still available but rarely needed with CoW
Migration: The default copy=None is sufficient for most cases under CoW. Only use copy=True if you need to ensure immediate physical copying of data.
Deprecated Parameters Removed
Several long-deprecated parameters have been removed in v3.0:
infer_datetime_format in read_csv() and similar functions (datetime format inference is now automatic)
- Various
convert_* parameters in IO functions
Migration: Remove these parameters from your code. Datetime format inference happens automatically in v3.0.
Index Constructor Changes
The tupleize_cols parameter default behavior may affect MultiIndex creation:
# May need explicit handling for tuple columns
idx = pd.Index(data, tupleize_cols=True) # Explicit if needed
API Breaking Changes
Refer to the full changelog for comprehensive breaking changes: https://pandas.pydata.org/pandas-docs/stable/whatsnew/v3.0.0.html
Key areas to review:
- Copy-on-Write is now mandatory (no opt-out)
- Index and MultiIndex behavior changes
- DataFrame/Series constructor parameter defaults changed
- IO function parameter updates
- Deprecated method removals
API Reference
Core Data Structures
- DataFrame(data=None, index=None, columns=None, dtype=None, copy=None) - Two-dimensional labeled data structure with columns of potentially different types
- Series(data=None, index=None, dtype=None, name=None, copy=None) - One-dimensional labeled array capable of holding any data type
Index Types
- Index(data=None, dtype=None, copy=False, name=None, tupleize_cols=True) - Immutable sequence used for indexing and alignment
- RangeIndex(start=None, stop=None, step=None, dtype=None, copy=False, name=None) - Memory-efficient index for monotonic integer ranges
- MultiIndex(levels=None, codes=None, sortorder=None, names=None, dtype=None, copy=False, name=None, verify_integrity=True) - Multi-level or hierarchical index object
- DatetimeIndex(data=None, freq=None, tz=None, normalize=False, closed=None, ambiguous='raise', dayfirst=False, yearfirst=False, dtype=None, copy=False, name=None) - Immutable ndarray of datetime64 data
- TimedeltaIndex(data=None, unit=None, freq=None, closed=None, dtype=None, copy=False, name=None) - Immutable ndarray of timedelta64 data
- PeriodIndex(data=None, ordinal=None, freq=None, dtype=None, copy=False, name=None) - Immutable ndarray holding ordinal values indicating regular periods in time
- CategoricalIndex(data=None, categories=None, ordered=None, dtype=None, copy=False, name=None) - Index based on categorical data
- IntervalIndex(data, closed=None, dtype=None, copy=False, name=None, verify_integrity=True) - Index of intervals closed on the same side
Scalars
- Timestamp(ts_input=None, freq=None, tz=None, unit=None, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, nanosecond=None, tzinfo=None, fold=None) - Pandas replacement for datetime.datetime with nanosecond precision
- **Timedelta(value=None, unit=None, kwargs) - Duration representing difference between two dates or times
- Period(value=None, freq=None, ordinal=None, year=None, month=None, quarter=None, day=None, hour=None, minute=None, second=None) - Represents a time period at a particular frequency
- Interval(left, right, closed='right') - Immutable object representing an interval
- NA - Scalar missing value indicator
- NaT - Pandas Not-A-Time, used to represent null dates/times
Data Types
- Categorical(values, categories=None, ordered=None, dtype=None, copy=True) - Represents categorical variable for memory efficiency and operations
IO Functions
- read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, dtype=None, ...) - Read CSV file into DataFrame
- read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, dtype=None, ...) - Read Excel file into DataFrame
- read_json(path_or_buf, orient=None, typ='frame', dtype=None, ...) - Convert JSON to DataFrame or Series
- read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None, dtype_backend=None, dtype=None) - Read SQL query or table into DataFrame
- **read_parquet(path, engine='auto', columns=None, storage_options=None, use_nullable_dtypes=False, dtype_backend=None, filesystem=None, filters=None, kwargs) - Load parquet object into DataFrame
- read_pickle(filepath_or_buffer, compression='infer', storage_options=None) - Load pickled pandas object from file
- to_pickle(obj, filepath_or_buffer, compression='infer', protocol=5, storage_options=None) - Pickle (serialize) object to file
Data Manipulation
- concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True) - Concatenate pandas objects along a particular axis
- merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None) - Merge DataFrame or named Series objects with database-style join
- pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True) - Create spreadsheet-style pivot table as DataFrame
- melt(frame, id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True) - Unpivot DataFrame from wide to long format
- cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise', ordered=True) - Bin values into discrete intervals
- qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise') - Quantile-based discretization function
- get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None) - Convert categorical variable into dummy/indicator variables
Type Conversion
- to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True) - Convert argument to datetime
- to_timedelta(arg, unit=None, errors='raise') - Convert argument to timedelta
- to_numeric(arg, errors='raise', downcast=None, dtype_backend=None) - Convert argument to numeric type
Missing Value Detection
- isna(obj) - Detect missing values for an array-like object
- isnull(obj) - Detect missing values (alias of isna)
- notna(obj) - Detect non-missing values for an array-like object
- notnull(obj) - Detect non-missing values (alias of notna)
Index Generation
- **date_range(start=None, end=None, periods=None, freq=None, tz=None, normalize=False, name=None, inclusive='both', kwargs) - Return fixed frequency DatetimeIndex
- timedelta_range(start=None, end=None, periods=None, freq=None, name=None, closed=None) - Return fixed frequency TimedeltaIndex
- period_range(start=None, end=None, periods=None, freq=None, name=None) - Return fixed frequency PeriodIndex
- interval_range(start=None, end=None, periods=None, freq=None, name=None, closed='right') - Return fixed frequency IntervalIndex
Other Functions
- array(data, dtype=None, copy=True) - Create an ExtensionArray
- factorize(values, sort=False, use_na_sentinel=True, size_hint=None) - Encode the object as an enumerated type or categorical variable
Configuration
- get_option(pat: str) - Get value of single configuration option
- set_option(pat: str, value: Any) - Set value of single configuration option
- reset_option(pat: str) - Reset option to default value
- *option_context(args) - Context manager for temporary option changes
- describe_option(pat: str = '', _print_desc: bool = True) - Get description of configuration option
- options - Configuration options accessor (property)
1---2name: pandas-23description: Data manipulation and analysis library providing DataFrame and Series structures for working with structured data4license: BSD-3-Clause5---6
7## Imports
8
9```python
10import pandas as pd
11from pandas import DataFrame, Series, Index
12from pandas import read_csv, read_excel, read_json, read_sql, read_parquet, read_pickle
13from pandas import Timestamp, Timedelta, Period
14from pandas import get_option, set_option, option_context
15from pandas import NA, NaT
16from pandas import concat, merge, pivot_table, melt
17from pandas import cut, qcut, get_dummies
18from pandas import to_datetime, to_timedelta, to_numeric
19from pandas import isna, isnull, notna, notnull
20from pandas import date_range, timedelta_range, period_range, interval_range
21```
22
23## Core Patterns
24
25### Creating DataFrames ✅ Current
26```python
27import pandas as pd
28
29# From dictionary
30df = pd.DataFrame({
31 'name': ['Alice', 'Bob', 'Charlie'],
32 'age': [25, 30, 35],
33 'city': ['NYC', 'SF', 'LA']
34})
35
36# From CSV file
37df = pd.read_csv('data.csv', index_col=0)
38
39# From Excel file
40df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
41
42# From JSON
43df = pd.read_json('data.json', orient='records')
44
45# From Parquet
46df = pd.read_parquet('data.parquet')
47
48# From pickle
49df = pd.read_pickle('data.pkl')
50```
51* DataFrames are two-dimensional labeled data structures with columns of potentially different types
52* Use `read_*` functions for loading data from various file formats
53* Specify `index_col` to set which column becomes the row index
54* `copy` parameter default changed in v3.0 - see Migration section
55
56### Creating Series ✅ Current
57```python
58import pandas as pd
59
60# From list with index
61s = pd.Series([10, 20, 30], index=['a', 'b', 'c'], name='values')
62
63# From dictionary
64s = pd.Series({'a': 10, 'b': 20, 'c': 30})
65
66# Extracting from DataFrame
67df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
68s = df['col1'] # Returns Series
69```
70* Series are one-dimensional labeled arrays capable of holding any data type
71* Index provides labels for fast lookup
72* Series maintain their name attribute for identification
73* `copy` parameter default changed in v3.0 - see Migration section
74
75### Data Selection and Filtering ✅ Current
76```python
77import pandas as pd
78
79df = pd.DataFrame({
80 'name': ['Alice', 'Bob', 'Charlie'],
81 'age': [25, 30, 35],
82 'score': [85, 90, 88]
83})
84
85# Select single column (returns Series)
86ages = df['age']
87
88# Select multiple columns (returns DataFrame)
89subset = df[['name', 'age']]
90
91# Boolean filtering
92adults = df[df['age'] >= 30]
93
94# Multiple conditions
95high_scorers = df[(df['age'] >= 25) & (df['score'] >= 85)]
96
97# Using .loc for label-based indexing
98row = df.loc[0] # First row by index label
99value = df.loc[0, 'name'] # Specific cell
100
101# Using .iloc for position-based indexing
102row = df.iloc[0] # First row by position
103value = df.iloc[0, 1] # First row, second column
104```
105* Use bracket notation for column selection
106* Boolean indexing filters rows based on conditions
107* `.loc[]` uses labels, `.iloc[]` uses integer positions
108* Combine conditions with `&` (and), `|` (or), `~` (not) - wrap each condition in parentheses
109* Note: Copy-on-Write behavior changed in v3.0 - selections always return copies
110
111### Working with Time Series ✅ Current
112```python
113import pandas as pd
114
115# Create Timestamp
116ts = pd.Timestamp('2024-01-15 14:30:00')
117ts = pd.Timestamp(year=2024, month=1, day=15, hour=14, minute=30)
118
119# Create DatetimeIndex
120dates = pd.date_range('2024-01-01', periods=10, freq='D')
121df = pd.DataFrame({'value': range(10)}, index=dates)
122
123# Create Timedelta
124td = pd.Timedelta('2 days')
125td = pd.Timedelta(days=2, hours=3)
126
127# Create TimedeltaIndex
128deltas = pd.timedelta_range(start='1 day', periods=5, freq='D')
129
130# Create Period
131p = pd.Period('2024-01', freq='M')
132
133# Create PeriodIndex
134periods = pd.period_range('2024-01', periods=12, freq='M')
135
136# Convert to datetime
137df['date'] = pd.to_datetime(df['date_string'])
138
139# Convert to timedelta
140df['duration'] = pd.to_timedelta(df['duration_string'])
141```
142* `Timestamp` replaces Python's datetime.datetime with nanosecond precision
143* `DatetimeIndex` enables time-based indexing and slicing
144* `Timedelta` represents duration between two dates or times
145* `Period` represents a span of time at a particular frequency
146* Use `to_datetime()` and `to_timedelta()` for conversions
147
148### Missing Values ✅ Current
149```python
150import pandas as pd
151import numpy as np
152
153df = pd.DataFrame({
154 'A': [1, np.nan, 3],
155 'B': [4, 5, pd.NA],
156 'C': [7, pd.NaT, 9]
157})
158
159# Detect missing values
160has_nulls = df.isna() # or df.isnull()
161has_values = df.notna() # or df.notnull()
162
163# Check for any nulls
164any_nulls = df['A'].isna().any()
165
166# Drop rows with any null values
167df_clean = df.dropna()
168
169# Fill null values
170df_filled = df.fillna(0)
171df_filled = df.fillna(method='ffill') # Forward fill
172
173# Use pandas NA for missing values
174value = pd.NA # Scalable missing value indicator
175nat = pd.NaT # Not-a-Time for datetime/timedelta
176```
177* Use `.isna()` or `.isnull()` to detect missing values (they are aliases)
178* Use `.notna()` or `.notnull()` to detect non-missing values
179* `pd.NA` is the recommended missing value indicator for nullable dtypes
180* `pd.NaT` is used specifically for datetime/timedelta missing values
181* Never compare to NaN directly with `==` - always use `.isna()`
182
183### Combining DataFrames ✅ Current
184```python
185import pandas as pd
186
187df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
188df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
189
190# Concatenate along rows (vertical stack)
191result = pd.concat([df1, df2], axis=0)
192
193# Concatenate along columns (horizontal stack)
194result = pd.concat([df1, df2], axis=1)
195
196# Merge (join) DataFrames
197left = pd.DataFrame({'key': ['A', 'B'], 'value': [1, 2]})
198right = pd.DataFrame({'key': ['A', 'B'], 'value': [3, 4]})
199
200# Inner join
201merged = pd.merge(left, right, on='key', how='inner')
202
203# Left join
204merged = pd.merge(left, right, on='key', how='left')
205
206# Outer join
207merged = pd.merge(left, right, on='key', how='outer')
208```
209* `concat()` stacks DataFrames along an axis
210* `merge()` performs database-style joins
211* Use `how` parameter to specify join type: 'inner', 'left', 'right', 'outer'
212* Use `on` parameter to specify join key(s)
213
214### Reshaping Data ✅ Current
215```python
216import pandas as pd
217
218# Pivot table
219df = pd.DataFrame({
220 'date': ['2024-01', '2024-01', '2024-02', '2024-02'],
221 'product': ['A', 'B', 'A', 'B'],
222 'sales': [100, 150, 120, 180]
223})
224
225pivot = pd.pivot_table(df, values='sales', index='date', columns='product')
226
227# Melt (unpivot) from wide to long format
228melted = pd.melt(df, id_vars=['date'], value_vars=['product'],
229 var_name='category', value_name='value')
230
231# Create dummy variables (one-hot encoding)
232df = pd.DataFrame({'color': ['red', 'blue', 'red', 'green']})
233dummies = pd.get_dummies(df['color'], prefix='color')
234```
235* `pivot_table()` creates spreadsheet-style pivot tables
236* `melt()` transforms wide format to long format
237* `get_dummies()` creates dummy/indicator variables for categorical data
238
239### Binning and Discretization ✅ Current
240```python
241import pandas as pd
242
243data = pd.Series([1, 7, 5, 4, 6, 3, 9, 2, 8])
244
245# Cut into equal-width bins
246bins = pd.cut(data, bins=3, labels=['low', 'medium', 'high'])
247
248# Cut with custom bin edges
249bins = pd.cut(data, bins=[0, 3, 7, 10], labels=['low', 'medium', 'high'])
250
251# Quantile-based discretization (equal-sized bins)
252quantiles = pd.qcut(data, q=3, labels=['low', 'medium', 'high'])
253```
254* `cut()` bins values into discrete intervals with equal width
255* `qcut()` bins values based on quantiles (equal frequency)
256* Use `labels` parameter to assign custom category names
257
258### Type Conversion ✅ Current
259```python
260import pandas as pd
261
262df = pd.DataFrame({
263 'numbers': ['1', '2', '3'],
264 'dates': ['2024-01-01', '2024-01-02', '2024-01-03']
265})
266
267# Convert to numeric
268df['numbers'] = pd.to_numeric(df['numbers'])
269
270# Convert to datetime
271df['dates'] = pd.to_datetime(df['dates'])
272
273# Convert column dtype
274df['numbers'] = df['numbers'].astype('int64')
275
276# Convert to categorical
277df['category'] = df['category'].astype('category')
278```
279* `to_numeric()` converts to numeric types with error handling
280* `to_datetime()` converts to datetime with flexible parsing
281* `astype()` explicitly converts dtypes
282* Use `errors='coerce'` parameter to handle conversion failures
283
284### Configuring Display Options ✅ Current
285```python
286import pandas as pd
287
288# Get current option value
289max_rows = pd.get_option('display.max_rows')
290
291# Set option value
292pd.set_option('display.max_rows', 100)
293pd.set_option('display.max_columns', 50)
294pd.set_option('display.precision', 2)
295
296# Temporarily set options with context manager
297with pd.option_context('display.max_rows', 10, 'display.max_columns', 5):
298 print(df) # Uses temporary settings
299
300# Outside context, original settings restored
301
302# Reset option to default
303pd.reset_option('display.max_rows')
304
305# Describe available options
306pd.describe_option('display') # All display options
307pd.describe_option('display.max_rows') # Specific option
308```
309* Use `get_option()` and `set_option()` for global configuration changes
310* `option_context()` provides temporary settings that restore automatically
311* Common options: `display.max_rows`, `display.max_columns`, `display.precision`, `display.width`
312
313## Configuration
314
315### Display Settings
316```python
317# Default values
318pd.get_option('display.max_rows') # 60
319pd.get_option('display.max_columns') # 20
320pd.get_option('display.width') # 80
321pd.get_option('display.precision') # 6
322
323# Common customizations
324pd.set_option('display.max_rows', None) # Show all rows
325pd.set_option('display.max_columns', None) # Show all columns
326pd.set_option('display.float_format', '{:.2f}'.format) # Format floats
327```
328
329### File Reading Options
330```python
331# CSV reading with common parameters
332df = pd.read_csv(
333 'data.csv',
334 sep=',', # Delimiter (default: ',')
335 header=0, # Row to use as column names (default: 'infer')
336 index_col=0, # Column to use as row index
337 usecols=['col1', 'col2'], # Columns to read
338 dtype={'col1': int, 'col2': str}, # Column data types
339 parse_dates=['date_col'], # Parse as datetime
340 na_values=['NA', 'null'], # Additional NA values
341 encoding='utf-8', # File encoding
342 nrows=1000, # Number of rows to read
343 skiprows=5 # Rows to skip at start
344)
345```
346
347### Index and Data Types
348```python
349# Creating typed indexes
350idx = pd.Index([1, 2, 3], dtype='int64', name='id')
351cat_idx = pd.CategoricalIndex(['A', 'B', 'C'], name='category')
352range_idx = pd.RangeIndex(start=0, stop=10, step=2)
353multi_idx = pd.MultiIndex.from_tuples([('A', 1), ('A', 2), ('B', 1)])
354
355# Creating categoricals
356cat = pd.Categorical(['A', 'B', 'A', 'C'], categories=['A', 'B', 'C'], ordered=True)
357
358# Creating intervals
359interval = pd.Interval(left=0, right=5, closed='right')
360interval_idx = pd.IntervalIndex.from_breaks([0, 1, 2, 3])
361```
362
363## Pitfalls
364
365### Wrong: Using chained assignment
366```python
367import pandas as pd
368df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
369
370# This may not work as expected and raises SettingWithCopyWarning
371df[df['A'] > 1]['B'] = 99
372```
373**Why:** Chained indexing creates intermediate copies, so assignment may not affect the original DataFrame.
374
375### Right: Use .loc for assignment
376```python
377import pandas as pd
378df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
379
380# Correctly modifies the original DataFrame
381df.loc[df['A'] > 1, 'B'] = 99
382```
383
384### Wrong: Iterating over DataFrame rows with loops
385```python
386import pandas as pd
387
388df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
389
390# Very slow for large DataFrames
391results = []
392for i in range(len(df)):
393 results.append(df.iloc[i]['A'] + df.iloc[i]['B'])
394```
395**Why:** Row-by-row iteration is extremely slow and defeats pandas' vectorization.
396
397### Right: Use vectorized operations
398```python
399import pandas as pd
400
401df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
402
403# Much faster - operates on entire columns at once
404df['result'] = df['A'] + df['B']
405```
406
407---
408
409### Wrong: Not specifying dtype when creating structures
410```python
411import pandas as pd
412
413# Mixed types cause object dtype (slow operations)
414df = pd.DataFrame({'id': ['1', '2', '3'], 'value': [10, 20, 30]})
415# df['id'].dtype is 'object', not efficient
416```
417**Why:** Object dtype prevents optimized operations and uses more memory.
418
419### Right: Specify dtypes explicitly or convert after creation
420```python
421import pandas as pd
422
423# Specify dtype at creation
424df = pd.DataFrame({
425 'id': pd.Series([1, 2, 3], dtype='int64'),
426 'value': [10, 20, 30]
427})
428
429# Or convert after creation
430df = pd.DataFrame({'id': ['1', '2', '3'], 'value': [10, 20, 30]})
431df['id'] = df['id'].astype('int64')
432```
433
434---
435
436### Wrong: Using inplace=True for method chaining
437```python
438import pandas as pd
439
440df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
441
442# Cannot chain - inplace returns None
443result = df.drop(columns=['B'], inplace=True).reset_index() # Error!
444```
445**Why:** Methods with `inplace=True` return None, breaking method chains.
446
447### Right: Avoid inplace, assign results
448```python
449import pandas as pd
450
451df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
452
453# Chain operations naturally
454result = df.drop(columns=['B']).reset_index(drop=True)
455
456# Or assign back if needed
457df = df.drop(columns=['B'])
458```
459
460## References
461
462- [homepage](https://pandas.pydata.org)
463- [documentation](https://pandas.pydata.org/docs/)
464- [repository](https://github.com/pandas-dev/pandas)
465- [changelog](https://pandas.pydata.org/pandas-docs/stable/whatsnew/index.html)
466- [PyPI](https://pypi.org/project/pandas/)
467
468## Migration from v2.x
469
470### Copy Semantics Changed
471**v2.x behavior:**
472```python
473df = pd.DataFrame({'A': [1, 2, 3]})
474df2 = df[['A']] # Creates view in many cases
475df2.iloc[0, 0] = 99 # May modify original df
476```
477
478**v3.0 behavior:**
479```python
480df = pd.DataFrame({'A': [1, 2, 3]})
481df2 = df[['A']] # Always creates copy (Copy-on-Write enforced)
482df2.iloc[0, 0] = 99 # Never modifies original df
483```
484**Migration:** Copy-on-Write (CoW) is now the default and only mode in pandas 3.0. All indexing operations that return a subset of data will return a new copy. If you need to modify the original DataFrame, use direct assignment with `.loc[]` or `.iloc[]` rather than chaining operations.
485
486### Constructor Parameter Changes
487The `copy` parameter behavior has changed in DataFrame and Series constructors:
488
489**v2.x:**
490```python
491df = pd.DataFrame(data, copy=True) # Explicitly copy data
492```
493
494**v3.0:**
495```python
496df = pd.DataFrame(data, copy=None) # Default changed to None
497# copy=None respects Copy-on-Write semantics
498# copy=True still available but rarely needed with CoW
499```
500**Migration:** The default `copy=None` is sufficient for most cases under CoW. Only use `copy=True` if you need to ensure immediate physical copying of data.
501
502### Deprecated Parameters Removed
503Several long-deprecated parameters have been removed in v3.0:
504- `infer_datetime_format` in `read_csv()` and similar functions (datetime format inference is now automatic)
505- Various `convert_*` parameters in IO functions
506
507**Migration:** Remove these parameters from your code. Datetime format inference happens automatically in v3.0.
508
509### Index Constructor Changes
510The `tupleize_cols` parameter default behavior may affect MultiIndex creation:
511
512```python
513# May need explicit handling for tuple columns
514idx = pd.Index(data, tupleize_cols=True) # Explicit if needed
515```
516
517### API Breaking Changes
518Refer to the full changelog for comprehensive breaking changes: https://pandas.pydata.org/pandas-docs/stable/whatsnew/v3.0.0.html
519
520Key areas to review:
521- Copy-on-Write is now mandatory (no opt-out)
522- Index and MultiIndex behavior changes
523- DataFrame/Series constructor parameter defaults changed
524- IO function parameter updates
525- Deprecated method removals
526
527## API Reference
528
529### Core Data Structures
530- **DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)** - Two-dimensional labeled data structure with columns of potentially different types
531- **Series(data=None, index=None, dtype=None, name=None, copy=None)** - One-dimensional labeled array capable of holding any data type
532
533### Index Types
534- **Index(data=None, dtype=None, copy=False, name=None, tupleize_cols=True)** - Immutable sequence used for indexing and alignment
535- **RangeIndex(start=None, stop=None, step=None, dtype=None, copy=False, name=None)** - Memory-efficient index for monotonic integer ranges
536- **MultiIndex(levels=None, codes=None, sortorder=None, names=None, dtype=None, copy=False, name=None, verify_integrity=True)** - Multi-level or hierarchical index object
537- **DatetimeIndex(data=None, freq=None, tz=None, normalize=False, closed=None, ambiguous='raise', dayfirst=False, yearfirst=False, dtype=None, copy=False, name=None)** - Immutable ndarray of datetime64 data
538- **TimedeltaIndex(data=None, unit=None, freq=None, closed=None, dtype=None, copy=False, name=None)** - Immutable ndarray of timedelta64 data
539- **PeriodIndex(data=None, ordinal=None, freq=None, dtype=None, copy=False, name=None)** - Immutable ndarray holding ordinal values indicating regular periods in time
540- **CategoricalIndex(data=None, categories=None, ordered=None, dtype=None, copy=False, name=None)** - Index based on categorical data
541- **IntervalIndex(data, closed=None, dtype=None, copy=False, name=None, verify_integrity=True)** - Index of intervals closed on the same side
542
543### Scalars
544- **Timestamp(ts_input=None, freq=None, tz=None, unit=None, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, nanosecond=None, tzinfo=None, fold=None)** - Pandas replacement for datetime.datetime with nanosecond precision
545- **Timedelta(value=None, unit=None, **kwargs)** - Duration representing difference between two dates or times
546- **Period(value=None, freq=None, ordinal=None, year=None, month=None, quarter=None, day=None, hour=None, minute=None, second=None)** - Represents a time period at a particular frequency
547- **Interval(left, right, closed='right')** - Immutable object representing an interval
548- **NA** - Scalar missing value indicator
549- **NaT** - Pandas Not-A-Time, used to represent null dates/times
550
551### Data Types
552- **Categorical(values, categories=None, ordered=None, dtype=None, copy=True)** - Represents categorical variable for memory efficiency and operations
553
554### IO Functions
555- **read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, dtype=None, ...)** - Read CSV file into DataFrame
556- **read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, dtype=None, ...)** - Read Excel file into DataFrame
557- **read_json(path_or_buf, orient=None, typ='frame', dtype=None, ...)** - Convert JSON to DataFrame or Series
558- **read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None, dtype_backend=None, dtype=None)** - Read SQL query or table into DataFrame
559- **read_parquet(path, engine='auto', columns=None, storage_options=None, use_nullable_dtypes=False, dtype_backend=None, filesystem=None, filters=None, **kwargs)** - Load parquet object into DataFrame
560- **read_pickle(filepath_or_buffer, compression='infer', storage_options=None)** - Load pickled pandas object from file
561- **to_pickle(obj, filepath_or_buffer, compression='infer', protocol=5, storage_options=None)** - Pickle (serialize) object to file
562
563### Data Manipulation
564- **concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)** - Concatenate pandas objects along a particular axis
565- **merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)** - Merge DataFrame or named Series objects with database-style join
566- **pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True)** - Create spreadsheet-style pivot table as DataFrame
567- **melt(frame, id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True)** - Unpivot DataFrame from wide to long format
568- **cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise', ordered=True)** - Bin values into discrete intervals
569- **qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise')** - Quantile-based discretization function
570- **get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)** - Convert categorical variable into dummy/indicator variables
571
572### Type Conversion
573- **to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True)** - Convert argument to datetime
574- **to_timedelta(arg, unit=None, errors='raise')** - Convert argument to timedelta
575- **to_numeric(arg, errors='raise', downcast=None, dtype_backend=None)** - Convert argument to numeric type
576
577### Missing Value Detection
578- **isna(obj)** - Detect missing values for an array-like object
579- **isnull(obj)** - Detect missing values (alias of isna)
580- **notna(obj)** - Detect non-missing values for an array-like object
581- **notnull(obj)** - Detect non-missing values (alias of notna)
582
583### Index Generation
584- **date_range(start=None, end=None, periods=None, freq=None, tz=None, normalize=False, name=None, inclusive='both', **kwargs)** - Return fixed frequency DatetimeIndex
585- **timedelta_range(start=None, end=None, periods=None, freq=None, name=None, closed=None)** - Return fixed frequency TimedeltaIndex
586- **period_range(start=None, end=None, periods=None, freq=None, name=None)** - Return fixed frequency PeriodIndex
587- **interval_range(start=None, end=None, periods=None, freq=None, name=None, closed='right')** - Return fixed frequency IntervalIndex
588
589### Other Functions
590- **array(data, dtype=None, copy=True)** - Create an ExtensionArray
591- **factorize(values, sort=False, use_na_sentinel=True, size_hint=None)** - Encode the object as an enumerated type or categorical variable
592
593### Configuration
594- **get_option(pat: str)** - Get value of single configuration option
595- **set_option(pat: str, value: Any)** - Set value of single configuration option
596- **reset_option(pat: str)** - Reset option to default value
597- **option_context(*args)** - Context manager for temporary option changes
598- **describe_option(pat: str = '', _print_desc: bool = True)** - Get description of configuration option
599- **options** - Configuration options accessor (property)