SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

Pandas & Python AnalyticsOverview

What it is, why it matters, architecture and key concepts

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore Pandas & Python Analytics Team
Expert Content

Pandas — Data Analytics with Python

Pandas is the foundational Python library for data analysis. It provides DataFrame and Series data structures that make working with tabular data fast, expressive, and flexible.

Why Pandas?

python
# Without pandas — painful
data = []
with open('sales.csv') as f:
    for line in f:
        data.append(line.strip().split(','))
headers = data[0]
total = sum(float(row[3]) for row in data[1:] if row[2] == 'Electronics')

# With pandas — 2 lines
import pandas as pd
df = pd.read_csv('sales.csv')
total = df[df['category'] == 'Electronics']['revenue'].sum()

Installation & Setup

bash
pip install pandas numpy matplotlib seaborn openpyxl xlrd
python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Check version
print(pd.__version__)

# Display settings
pd.set_option('display.max_columns', 50)
pd.set_option('display.max_rows', 100)
pd.set_option('display.float_format', '{:.2f}'.format)

Reading Data

python
# CSV
df = pd.read_csv('data.csv')
df = pd.read_csv('data.csv',
    sep=';',                         # Custom delimiter
    header=0,                        # Row to use as header
    index_col='id',                  # Set column as index
    parse_dates=['created_at'],      # Parse date columns
    usecols=['name', 'revenue'],     # Only load these columns
    dtype={'revenue': float},        # Force column types
    na_values=['N/A', 'NULL', ''],   # Treat as NaN
    encoding='utf-8',
    nrows=1000                       # Only read first 1000 rows
)

# Excel
df = pd.read_excel('report.xlsx', sheet_name='Q1 Sales')
dfs = pd.read_excel('report.xlsx', sheet_name=None)  # All sheets → dict

# JSON
df = pd.read_json('data.json')
df = pd.read_json('data.json', orient='records')

# SQL Database
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:pass@host:5432/mydb')
df = pd.read_sql("SELECT * FROM orders WHERE status = 'completed'", engine)
df = pd.read_sql_table('orders', engine)

# Parquet (fast columnar format)
df = pd.read_parquet('data.parquet')

# Sample large files
df = pd.read_csv('huge.csv', nrows=100)         # First 100 rows
df = pd.read_csv('huge.csv', skiprows=range(1, 1000))  # Skip rows 1-999

Exploring Data

python
df.shape                    # (rows, columns)
df.dtypes                   # Column data types
df.info()                   # Summary with dtypes and nulls
df.describe()               # Statistics for numeric columns
df.describe(include='all')  # Including categorical

df.head(10)                 # First 10 rows
df.tail(5)                  # Last 5 rows
df.sample(5)                # Random 5 rows

df.columns.tolist()         # List of column names
df.index                    # Index info
df['revenue'].unique()      # Unique values
df['status'].value_counts() # Frequency count
df['revenue'].nunique()     # Number of unique values

# Missing values
df.isnull().sum()           # Null count per column
df.isnull().sum() / len(df) # Null percentage
df[df['revenue'].isnull()]  # Rows with null revenue

Selecting and Filtering

python
# Select columns
df['revenue']                           # Series
df[['name', 'revenue', 'date']]        # DataFrame
df.iloc[:, 0:3]                         # First 3 columns by position
df.loc[:, 'name':'revenue']            # Columns by label range

# Select rows
df.iloc[0]                              # First row by position
df.iloc[5:10]                           # Rows 5-9
df.loc[100]                             # Row by index label

# Filter rows
df[df['revenue'] > 1000]
df[df['status'] == 'completed']
df[(df['revenue'] > 1000) & (df['region'] == 'West')]  # AND
df[(df['status'] == 'A') | (df['status'] == 'B')]       # OR
df[~(df['status'] == 'cancelled')]                       # NOT
df[df['category'].isin(['Electronics', 'Clothing'])]    # In list
df[df['name'].str.contains('Apple', na=False)]          # String contains
df.query("revenue > 1000 and region == 'West'")         # SQL-like syntax

# Select by condition and columns
df.loc[df['revenue'] > 1000, ['name', 'revenue', 'region']]

Data Cleaning

python
# Handle missing values
df.dropna()                              # Drop rows with ANY null
df.dropna(subset=['revenue', 'date'])   # Drop rows with null in these cols
df.dropna(thresh=5)                     # Keep rows with at least 5 non-null
df.fillna(0)                            # Fill all nulls with 0
df['revenue'].fillna(df['revenue'].mean())  # Fill with mean
df.fillna(method='ffill')               # Forward fill
df.fillna(method='bfill')               # Backward fill

# Data types
df['date'] = pd.to_datetime(df['date'])
df['revenue'] = pd.to_numeric(df['revenue'], errors='coerce')  # Bad → NaN
df['id'] = df['id'].astype(str)
df['category'] = df['category'].astype('category')  # Memory efficient

# String cleaning
df['name'] = df['name'].str.strip()        # Remove whitespace
df['name'] = df['name'].str.lower()        # Lowercase
df['name'] = df['name'].str.replace('Inc.', 'Inc', regex=False)
df['email'] = df['email'].str.extract(r'(\w+@\w+\.\w+)')  # Extract pattern

# Duplicates
df.duplicated().sum()                       # Count duplicates
df.drop_duplicates()                        # Remove all duplicates
df.drop_duplicates(subset=['email'])        # Unique by email
df.drop_duplicates(subset=['email'], keep='last')  # Keep last occurrence

# Rename columns
df.rename(columns={'old_name': 'new_name', 'qty': 'quantity'}, inplace=True)
df.columns = df.columns.str.lower().str.replace(' ', '_')  # Standardize all

Aggregation & GroupBy

python
# Basic aggregations
df['revenue'].sum()
df['revenue'].mean()
df['revenue'].median()
df.groupby('region')['revenue'].sum()
df.groupby('region')['revenue'].agg(['sum', 'mean', 'count'])

# Multiple groupby
df.groupby(['region', 'category']).agg(
    total_revenue=('revenue', 'sum'),
    avg_order=('revenue', 'mean'),
    order_count=('id', 'count'),
    max_order=('revenue', 'max')
).reset_index()

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

# Rolling window (moving average)
df['revenue_7d_avg'] = df['revenue'].rolling(window=7).mean()
df['revenue_cumsum'] = df['revenue'].cumsum()

# Resample time series
df = df.set_index('date')
df.resample('M')['revenue'].sum()          # Monthly totals
df.resample('Q')['revenue'].sum()          # Quarterly
df.resample('W').agg({'revenue': 'sum', 'orders': 'count'})

Merging and Joining

python
# Merge (like SQL JOIN)
result = pd.merge(orders, customers,
    left_on='customer_id',
    right_on='id',
    how='left'       # left, right, inner, outer
)

# Multiple key join
result = pd.merge(orders, products,
    on=['product_id', 'warehouse_id']
)

# Concatenate
combined = pd.concat([df_q1, df_q2, df_q3, df_q4], ignore_index=True)
combined = pd.concat([df1, df2], axis=1)  # Side by side

Apply and Lambda

python
# Apply function to each value
df['revenue_usd'] = df['revenue'].apply(lambda x: x * 1.2)

# Apply to each row
df['full_name'] = df.apply(
    lambda row: f"{row['first_name']} {row['last_name']}",
    axis=1
)

# Vectorized (faster than apply)
df['discounted'] = np.where(df['revenue'] > 1000, df['revenue'] * 0.9, df['revenue'])

# Cut into bins
df['revenue_tier'] = pd.cut(df['revenue'],
    bins=[0, 100, 500, 1000, float('inf')],
    labels=['Low', 'Medium', 'High', 'Premium']
)

Export Data

python
df.to_csv('output.csv', index=False)
df.to_excel('output.xlsx', index=False, sheet_name='Analysis')
df.to_parquet('output.parquet')
df.to_json('output.json', orient='records', indent=2)
df.to_sql('table_name', engine, if_exists='replace', index=False)

Interview Questions

What is the difference between loc and iloc?

loc selects by label — row index labels and column names. iloc selects by integer position — row and column numbers. If your index is integers (0, 1, 2...) they look similar, but differ when index is non-numeric. df.loc[5, 'revenue'] selects row with index label 5 and column named 'revenue'. df.iloc[5, 3] selects the 6th row and 4th column regardless of labels.

How do you handle memory issues with large DataFrames?

Several strategies: use dtype parameter when reading to downcast (int64→int32, float64→float32), use usecols to only load needed columns, use category dtype for low-cardinality string columns (saves 10-100×), process in chunks with chunksize parameter in read_csv, use Parquet format instead of CSV (columnar, compressed), or switch to Dask for out-of-core computation on data larger than RAM.

Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Up Next
Pandas & Python AnalyticsPrerequisites
What to know or set up before starting
Also Worth Exploring
← Back to all Pandas & Python Analytics modules
Prerequisites