Pandas – note plan
Table of Contents
1. Introduction to Pandas
2. The Fundamental/Core Data Structures
3. Data Input and Output (I/O) Operations
4. Initial Data Inspection and Summary (Statistics)
5. Data Selection, Indexing
6. Data Cleaning preprocessing
7. Data Transformation and Manipulation
8. Data Aggregation and Grouping
9. Combining, merging, and concatination
12. Working with Time Series
15. Visualization with Pandas
1. Introduction to Pandas
What is Pandas
- Definition:
- A fast, powerful, and flexible open-source data analysis and manipulation library for Python.
- Built on top of NumPy.
Key features and benefits/advantages
- History and development
Key uses: why it’s used/primary use cases
- Data cleaning, transformation, data manipulation,
- analysis, and visualization preparation.
- Comparison with NumPy
- Relation to NumPy (Pandas is built on top of NumPy).
- Comparison with other libraries (e.g., NumPy, Polars)
- Overview of Pandas ecosystem (relation to NumPy, Matplotlib, etc.)
- Installation and Import: (using pip, conda)
pip install pandas:import pandas as pd:
- Pandas data structures overview (
Seriesvs/&DataFrame)- Data structures in Pandas:
SeriesandDataFrame
- Data structures in Pandas:
2. The Fundamental/Core Data Structures
2.1. (Pandas) Series:
- One-dimensional labeled array.
- Creating Series:
- from lists, dictionaries, NumPy arrays, scalar values
- Anatomy: Index and Values.
- Key attributes:
.index:.values:.dtype:.name:- shape +++
- Indexing and index objects
- Vectorized operations
- Boolean indexing with Series
-
Handling missing values in Series
- Indexes and Labels
- Accessing elements (
.loc[],.iloc[], slicing) - Operations on Series
- Arithmetic, comparison, and broadcasting
- Useful Series methods
head():tail():describe():value_counts():unique():nunique():map():apply():
- Handling missing values in Series
isna():fillna():dropna():
2.2. (Pandas) DataFrame:
-
Two-dimensional labeled data structure (like a spreadsheet or SQL table).
- Creating DataFrames from:
- From dicts
- from dict of Series/lists,
- list of dicts, List of dictionaries
- NumPy arrays,
- from a file (e.g., CSV, Excel).CSV/Excel files
- Dictionaries of lists/Series
- External databases
- DataFrame Anatomy: DataFrame structure:
- Index
- Columns,
- and Data.
- Key/Essential attributes:
.index:.columns:.axes:.dtypes:.shape:.size:.ndim:.values:
- Essential methods:
.info():.describe():.head():.tail():.sample():
3. Data Input and Output: (I/O) Operations
3.1. Reading data: from various sources/formats
pd.read_csv(): # key parameters: sep, header, index_col, usecols, dtype; Parameters like sep, header, index_col, dtypepd.read_excel(): # sheet_name, engine; from Excel; Sheet selection, multi-sheet handlingpd.read_json(): # orient, lines; from JSON; Orientation optionspd.read_html(): # web scraping; HTML tables-
pd.read_sql(): # sql, con; Queries, connections; SQLAlchemy engine pd.read_clipboard(): from Clipboard; Clipboardpd.read_table(): from Flat Files??read_fwf:- From URLs.
-
Parquet, HDF5, Feather, and other efficient formats
- Important Parameters for reading:
index_col:header:usecols:parse_dates:sep:dtype:nrows:
3.2. Writing Data: to files
df.to_csv(): # index=False, header, encoding; (important:index=False); Parameters like index, header, modedf.to_excel(): #sheet_name,index;ExcelWriter: Multi-sheet writing with ExcelWriterdf.to_sql(): writing to a database; Handling if_exists, chunksize; SQLAlchemy enginedf.to_json(): #orient; Orientation (split, records, etc.)-
df.to_parquet(): # efficient storage; efficient binary format, highly recommended for large datasets. - Key parameters for writing:
index=False:header=False:sheet_name):mode
- Handling large datasets: Chunking, iterators
- Parameters for performance and memory optimization
4. Basic/Initial Data Inspection and Summary (Statistics)
- Initial Review: Checking basic info: Viewing data:
df.head():df.tail():-
df.sample(): sampling; see random parts of your data df.info(): comprehensive overview; Concise summary:- (data types, entries, columns, Dtype/Data types, non-null counts, memory usage).
df.describe():- Summary statistics for numerical columns; (include/exclude parameters)
- Descriptive statistics (count, mean, std, min, max, quartiles).
df.value_counts(): column value countsdf.shape: Dimensions of the DataFrame.df.columns: List of column names.df.index:df.axes:df.shape: Shapedf.size: sizedf.memory_usage(): memory consumption
- Data Types:
df.dtypes: Data types of each column; checking types.astype(): converting types- Understanding common Pandas dtypes
- (
int64,float64,object,category, etc.).
- (
5. Data Selection & Indexing, Subsetting/Slicing and Filtering
This is a critical section. Understand the difference between [], .loc[], and .iloc[].
- Basic Selection:
- Selecting columns (as Series and as a DataFrame subset).
- Selecting rows using list slicing (
df[10:20]).
- Label-based Indexing:
- Using
.loc[](selection by labels/names for rows and columns). - Conditional/Boolean filtering (e.g.,
df[df['Age'] > 25]).
- Using
- Position-based Indexing:
- Using
.iloc[](selection by integer position for rows and columns).
- Using
- Advanced Indexing:
- Setting, resetting, and modifying the index:
.set_index(),.reset_index(). -
Working with MultiIndex (Hierarchical Indexing).
- Setting, resetting, and modifying the index:
- Accessing data
- Selecting columns (
df['col']), rows (.loc[],.iloc[]), slices
- Selecting columns (
- Copying vs referencing (
copy(deep=True))
Column Selection: selecting columns
df.columns: Column attributesdf['column_name']: Single column as Seriesdf[['column_name']]: Single column as DataFramedf[['col1', 'col2']]: Multiple columns.rename(columns={}): Renaming columns
Row Selection: selecting rows
By label/index: .loc[] (label-based indexing)
df.loc['index_label']: Single rowdf.loc[['label1', 'label2']]: Multiple rowsdf.loc['label1/start':'label3/end'](inclusive!): Slicing with labels
By integer position: (position-based indexing).iloc[]
df.iloc[0]: Single row:df.iloc[[0, 2, 4]]: Multiple rows:df.iloc[0:5]: Slicing with index-position (exclusive of the stop index)
Boolean Indexing/Filtering Data/Conditional selection
- Single condition
df[df['col'] > value]:df[df['age'] > 30]:df.loc[df['age'] > 30]:
- Multi-condition filtering with
&,|,~: - Boolean indexing with multiple conditions (
&,|,~).(df['age'] > 30) & (df['city'] == 'NYC'): Multiple conditions
.isin()method- Using
.isin([list]). .query()method for complex filtering- Using
.query()method.
- Using
- Boolean indexing with multiple categories
- Using
.strmethods for text filtering.
Combined Selection/Selecting Subsets (of Rows and Columns)/Subsetting
df.loc[row_labels, col_labels]:df.loc[3,'weight']df.loc[3,'weight'] = 50# changing its value
df.iloc[row_positions, col_positions]:- `df.iloc[]
df.iloc[3,'weight'] = 50
- Using
.loc[]:df.loc[rows_selection, columns_selection]df.loc[df['age'] > 25, ['name', 'city']]
- Using
.iloc[]:df.iloc[row_indices, column_indices]df.iloc[3, 3]df.iloc[3, 3] = 50# change values of [3,3] to 50- Example:
df.iloc[0:5, [1, 3]]
df.at[]anddf.iat[]for scalar accessisin(),between(),where(),mask()
6. Data Cleaning & Preprocessing: Preparation
6.1. Handling Missing Data: [done]
- Detecting/identifying/checking missing values/data:
.isna():.isnull():.notna():.notnull():
- Counting:
.isnull().sum(): Count of missing values per column..isnull().mean():
- Dropping missing values:
.dropna():- (axis, how, thresh, subset)
- (how=’any’/’all’, axis, thresh, subset)
- (rows/columns, parameters like
how='all',subset).
- Filling missing values:
.fillna():- e.g.
df.fillna(0),df['balance'].fillna(df['balance'].mean()) - (value, method=’ffill’/’bfill’, limit) ;
- (ffill/bfill, interpolation)
- (with a scalar, mean/median/mode, or forward fill
ffilland backward fillbfill)
- e.g.
- Interpolation:
.interpolate(): (method, limit_direction)
- Dropping or filling NaNs conditionally
6.2. Handling Duplicates/duplicate data: [done]
df.duplicated(): Detecting/identifying duplicates:- (subset, keep)
df.duplicated().sum(): Counting duplicatesdf.drop_duplicates(): Removing/dropping duplicates- (subset, keep=’first’/’last’/False)
6.3. Column Operations: Adding, Renaming/modifying and Dropping
- Adding columns: [done]
df['new'] = values:df['new_col'] = ...: Add [done]df.assign(): Adding columns:df.assign(new_col=...): Add
- Renaming columns:
.rename()[done]df.rename(columns={'old':'new', 'old':'new'}):df.rename({'make':'make1', 'model':'model1'}, axis=1)
- Dropping columns/index:
df.drop()df.drop(columns=[]):df.drop(columns=['col1', 'col2']):df.drop(['col1'], axis=1):df.drop(columns={'full_name', 'balance'})#df.drop(['name'])??
- Modifying data/values:
.replace(): replacing valuesdf['l_name'] = df['l_name'].replace({'Tamang':'Lama', np.nan: 'Nepali'})—>df['priority'] = df['priority'].replace({'yes': True, 'no': False})
.map(): mapping valuesdf['l_name'] = df['l_name'].replace({'Tamang':'Lama', np.nan: 'Nepali'})df['priority'] = df['priority'].replace({'yes': True, 'no': False})
6.4 Index/Row Operations: [done]
- Adding an Index: #Adding new index/row in pandas
df.loc['k'] = ['rabbit', 4, 2, 'yes']- Adding multiple indexes: using
.concat()
- Rename index(s)/row(s)
df.rename({2:20, 3:30})# rename index 2 and 3 to 20 and 30df.rename({2:20, 3:30}, axis=0)# same thing, axis is optional/dualdf.rename({'a':'A', 'b':'B'})df.rename(index={2:20, 3:30})
- Drop index(s)/row(s):
df.drop(4):df.drop(5, axis=0)# axis=0, optional/defaultdf.drop([6, 7, 8], axis=0)df.drop('k', axis=0)df.drop(['c', 'd', 'e'], axis=0)
- Changing a Value:
df.loc['f', 'age'] = 1.5
- Handling outliers
Data Type Conversion/Changing Data Types: See basic/initial
.astype()- basic type conversion; for simple conversions (e.g.,df['col'].astype('int32'))pd.to_numeric()- with error handling; more robust, handles errors (errors='coerce')pd.to_datetime()- date parsing; convert to datetime.pd.to_timedelta():infer_objects()- smart type inference
String Operations
- String accessor:
.str - Common methods:
- Case:
str.lower(),str.upper(),stritle()
- Searching:
str.contains(),str.startswith(),str.endswith()
- Manipulation:
str.replace(),str.strip(),str.split(),str.extract()
- Information:
.len(),.find()
- Case:
7. Data Transformation and Manipulation
7.1. Sorting
- Sorting by index:
.sort_index()(ascending, inplace)ascending, na_position)
- Sorting by values: ascending, na_position)
.sort_values()(by, ascending, na_position)df3 = df.sort_values('visits')# default: ascending=Truedf2 = df.sort_values('age', ascending=False)df.sort_values(by=['col1', 'col2'], ascending=[False, True])(multiple columns)df4 = df.sort_values(by=['age', 'visits'], ascending=[False, True])# can be more than two
- Reindexing (
reindex()) .reindex(): Reordering: column selection or- Changing column order
7.2. Applying Functions
.map()- element-wise Series transformation; Element-wise transformation on a Series..apply()- row/column-wise DataFrame operations; Row-wise or column-wise transformation on a DataFrame. More flexible, but slower..applymap()- element-wise on entire DataFrame; Element-wise on a whole DataFrame (less common).- Applying Functions:
- Element-wise operations: Using NumPy functions or lambda functions with
.apply()on a Series. - Row-wise or Column-wise operations: Using
.apply()withaxis=0oraxis=1.
- Element-wise operations: Using NumPy functions or lambda functions with
- Vectorized operations are preferred for performance.
- Lambda functions with apply
Binning & Discretization
pd.cut()- equal-sized binspd.qcut()- quantile-based bins
8. Data Aggregation & Grouping
Basic/Simple Aggregation: Statistical Methods/Descriptive statistics
- Single function:
describe(): Summary statistics for numerical columns.??sum():- Counts:
.count():.value_counts(): For categorical columns..nunique():
- Extremes:
.min():.max():
- Central tendency:
.mean():.median():.mode():
- Dispersion:
.std():.var():.mad():
- Quantiles:
.quantile():.percentile():
- Multiple functions:
.agg(['mean', 'std', 'count'])
- Column-specific:
.agg({'col1': 'mean', 'col2': ['min', 'max']})
- Grouping by multiple columns
- Iterating over groups
- Transformations (
transform()) - Pivot tables (
pivot_table()) - Cross-tabulation (
pd.crosstab())
GroupBy Operations: Grouping Basics
- Split-Apply-Combine pattern
.groupby('col'): Single column grouping.groupby(['col1', 'col2']: Multiple columns.groupby(lambda x: x.year): Grouping with functions
- The
groupbyMechanism- Concept: Split-Apply-Combine.
- Syntax:
df.groupby('by_column') - Aggregating:
.agg(['mean', 'std'])or.agg({'col1':'sum', 'col2':'mean'}) - Iterating over groups.
- Grouping by multiple columns.
- GroupBy methods:
- Aggregation:
.sum(),.mean(),.size() - Transformation:
.transform() - Filtration:
.filter() - Iteration:
for name, group in df.groupby()
- Aggregation:
- Grouping and Aggregation:
- The Split-Apply-Combine strategy.
- Using
.groupby()and common aggregation functions (e.g.,.mean(),.sum(),.count(),.agg()).
Advanced Grouping: Pivot Tables & Cross-Tabulation
.agg()with custom functions- Named aggregation with tuples
.pivot_table()- multi-dimensional analysis.crosstab()- frequency tablespd.pivot_table()-index,columns,values,aggfunc.pd.crosstab()- For computing a simple frequency table.
9. Combining DataFrames/DataSets: Data Manipulation??
9.1. Concatinating DataFrames (stacking/side-by-side): pd.concat()
- Key parameters:
axis=0/1,join='inner'/'outer', ignore_index, keys - Row-wise vs column-wise concatenation
axis=0(row-wise, stacking),axis=1(column-wise, side-by-side).
- join
9.2. Merging DataFrames: pd.merge()
- SQL/Database-style joins
- Join types (
how): inner, outer, left, right, cross - Key parameters:
on,left_on,right_on,how,suffixes. - Indicator for merge diagnostics
9.3. Joining on indexes/index-based joining: .join()
- Difference between
merge(general) andjoin(on index)- SQL/Database-style joins vs ____
.combine_first()- filling missing values- Combining data from multiple sources
10. Reshaping and Pivoting
melt():pivot():- Stacking and unstacking
- Wide vs long format
- MultiIndex and hierarchical indexing
Pivot Tables & Melting
pd.pivot_table()- multi-dimensional aggregation.pivot()- reshaping without aggregation.melt()- wide to long format-
.stack()and.unstack()- hierarchical indexing - Reshaping Data:
- Pivoting data:
.pivot_table()(similar to pivot tables in spreadsheets). - Melting data:
pd.melt()(wide to long format). - Stacking/Unstacking.
- Pivoting data:
11. Working with Indexes
- Setting and resetting indexes (
set_index(),reset_index()) - Hierarchical (multi-level) indexes
- Index sorting and selection
- Reindexing and alignment
12. (Working with) Time Series and Categorical Data/Time Series Analysis
- Working with DateTimeIndex/DateTime Handling
pd.to_datetime(): Converting to datetimepd.to_datetime()- parsing dates- Setting a datetime column as the index.
pd.date_range():pd.date_range()- generating date sequences- Setting a DateTimeIndex.
- Accessing date/time components (e.g.,
.dt.year,.dt.day_name()).
- Date indexing and slicing
- Time-Based Indexing & Slicing
- Partial string indexing:
df.loc['2020'],df.loc['2020-01']
- Slicing:
df.loc['2020-01-01':'2020-01-15']
- Partial string indexing:
- Resampling, shifting, and time zone handling.
- Resampling (
resample()).resample('M').mean(): Downsampling (to a lower frequency)..resample('D').ffill(): Upsampling (to a higher frequency).
- Shifting and lagging (
shift(),tshift())
Resampling & Rolling
- Resampling:
.resample()(up/down sampling)- Downsampling: ‘D’→’M’, ‘H’→’D’
- Upsampling: ‘D’→’H’ with filling/interpolation
- Rolling operations:
.rolling()for moving averages
- Expanding operations:
.expanding()
-
- Rolling and expanding windows (
rolling(),expanding())
- DateTimeIndex properties and methods
- Timezone handling with
tz_convert():tz_localize():
Time-Based Operations
.set_index(): Setting datetime index- Time-based indexing:
df.loc['2023'],df.loc['2023-01':'2023-03']
- Date properties:
.dt.year,.dt.month,.dt.day_name()
- Categorical Data:
- Creating and converting to
categorydtype. - Benefits of using categorical data (memory and speed).
-
Getting dummy variables/one-hot encoding:
pd.get_dummies().
- Creating and converting to
14. Performance Optimization
- Memory usage and profiling
- (
memory_usage(): info(memory_usage='deep'))
- (
- Using
categoricaldata types - Vectorization over loops
- Chunked reading of large files
- Using
df.eval()anddf.query()for performance - Method chaining for readability
- Vectorized operations vs apply
- Efficient dtypes and memory usage
pd.eval()for expression evaluation- Using
.isin()instead of multiple OR conditions - Using optimized methods like
.at,.iat,.loc,.ilocover iterative loops. - The efficiency of vectorized operations over
.apply()(when possible). - Understanding
copy()and “SettingWithCopyWarning” to avoid chained assignment issues.
15. Visualization (with Pandas): Integration with Visualization
- Basic built-in plotting with (
df.plot(),plot(kind='bar'), etc.) - Line, bar, histogram, box/box plots, scatter, area plots
- Customizing plots: titles, labels, colors, legends
- Subplots and multiple figures
- Integration with Matplotlib and Seaborn (passing the DataFrame as data)
16. Advanced Topics
- MultiIndex operations
- Working with categorical data
- Handling large datasets (
chunksize,Dask) - Method chaining (using
pipe()) - Pandas options and settings (
pd.set_option()) - Style formatting (
df.style)
Categorical Data
astype('category')for memory efficiency- Ordered categories
- Performance benefits with groupby and sorting
- Benefits: Memory efficiency and performance for fixed, repeating values.
MultiIndex DataFrames
- Creating MultiIndex (from_tuples, from_product)
- Indexing with MultiIndex (.loc with tuples)
- Cross-sections with
.xs() - Stacking and unstacking levels
- Styling DataFrames
- Using
.styleto apply conditional formatting for display in Jupyter notebooks.
- Using
- Handling Large Data
- Specifying
dtypeon import. - Using
chunksizefor iterative processing. - Dask as a parallel-computing alternative.
- Specifying
- Method Chaining
- Writing clean, readable code by chaining methods.
- Example:
(df.load_data().query('age > 30').groupby('city')['income'].mean().round(2))
17. Integration with Other Libraries
- Pandas + NumPy
- Pandas + Matplotlib / Seaborn
- Pandas + Scikit-learn (
train_test_split,get_dummies()) - Pandas + SQL / Databases
18. Real-World Case Studies / Practice
- Exploratory Data Analysis (EDA) workflow
- Cleaning messy datasets (missing values, inconsistent text)
- Combining datasets (merging, reshaping)
- Feature engineering with Pandas
- Time series analysis
- Generating reports or dashboards
12. Practical Patterns & Best Practices
Common Operations
- Handling large datasets with chunksize
- Memory optimization with categoricals and dtypes
- Method chaining patterns
- Pipeline creation
Troubleshooting & Debugging
- Common errors and solutions
- Performance profiling with
%timeit - Memory usage analysis
- Data validation techniques
Integration with Other Libraries
- Visualization with Matplotlib/Seaborn
- Statistical analysis with SciPy/StatsModels
- Machine learning with Scikit-learn
- Web applications with Streamlit
13. Real-world Applications
- Data cleaning pipelines
- Exploratory Data Analysis (EDA) workflow
- Time series forecasting preparation
- Feature engineering examples
- Data validation and quality checks
Pro-Tips for Your Notes:
- Code Snippets: For every topic, include a small, clear code example.
- Common Pitfalls: Note down common errors, like using chained assignment (
df[df.age > 25]['salary'] = 1000), which should be avoided in favor of.loc. - “Cheat Sheet” Section: Create a quick-reference page with the most common operations and their syntax.
- Visuals: Use diagrams to explain concepts like
groupby(Split-Apply-Combine) andmergeoperations.